aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
commit13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch)
tree2732d02d7d51218d6eed98ac7fcfc5b8794896b5
parent657bc3d9848e3be92029b2416031340988cd0111 (diff)
downloadsrc-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.tar.gz
src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.zip
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):vendor/clang/clang-release_32-r168974
Notes
Notes: svn path=/vendor/clang/dist/; revision=243791 svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt30
-rw-r--r--Makefile4
-rw-r--r--NOTES.txt2
-rw-r--r--bindings/python/clang/cindex.py1330
-rw-r--r--bindings/python/tests/cindex/test_code_completion.py75
-rw-r--r--bindings/python/tests/cindex/test_cursor.py9
-rw-r--r--bindings/xml/comment-xml-schema.rng94
-rw-r--r--docs/AddressSanitizer.html49
-rw-r--r--docs/AutomaticReferenceCounting.html43
-rw-r--r--docs/BlockLanguageSpec.txt24
-rw-r--r--docs/ClangTools.html18
-rw-r--r--docs/HowToSetupToolingForLLVM.html34
-rw-r--r--docs/InternalsManual.html4
-rw-r--r--docs/LanguageExtensions.html8
-rw-r--r--docs/LibASTMatchers.html130
-rw-r--r--docs/LibASTMatchersReference.html1938
-rw-r--r--docs/LibTooling.html125
-rw-r--r--docs/ObjectiveCLiterals.html2
-rw-r--r--docs/PCHInternals.html320
-rw-r--r--docs/ReleaseNotes.html10
-rw-r--r--docs/ThreadSanitizer.html15
-rw-r--r--docs/UsersManual.html82
-rw-r--r--docs/analyzer/IPA.txt363
-rw-r--r--docs/analyzer/debug-checks.txt89
-rw-r--r--docs/tools/clang.pod2
-rw-r--r--docs/tools/dump_ast_matchers.py264
-rw-r--r--examples/analyzer-plugin/MainCallChecker.cpp2
-rw-r--r--examples/clang-interpreter/CMakeLists.txt3
-rw-r--r--examples/clang-interpreter/Makefile2
-rw-r--r--examples/clang-interpreter/main.cpp7
-rw-r--r--include/clang-c/Index.h170
-rw-r--r--include/clang/ARCMigrate/ARCMT.h5
-rw-r--r--include/clang/AST/ASTConsumer.h15
-rw-r--r--include/clang/AST/ASTContext.h616
-rw-r--r--include/clang/AST/ASTMutationListener.h2
-rw-r--r--include/clang/AST/Attr.h5
-rw-r--r--include/clang/AST/BuiltinTypes.def2
-rw-r--r--include/clang/AST/CMakeLists.txt12
-rw-r--r--include/clang/AST/CXXInheritance.h17
-rw-r--r--include/clang/AST/CanonicalType.h1
-rw-r--r--include/clang/AST/CharUnits.h4
-rw-r--r--include/clang/AST/Comment.h189
-rw-r--r--include/clang/AST/CommentBriefParser.h3
-rw-r--r--include/clang/AST/CommentCommandTraits.h186
-rw-r--r--include/clang/AST/CommentCommands.td156
-rw-r--r--include/clang/AST/CommentHTMLTags.td54
-rw-r--r--include/clang/AST/CommentLexer.h116
-rw-r--r--include/clang/AST/CommentParser.h4
-rw-r--r--include/clang/AST/CommentSema.h48
-rw-r--r--include/clang/AST/Decl.h52
-rw-r--r--include/clang/AST/DeclBase.h27
-rw-r--r--include/clang/AST/DeclCXX.h46
-rw-r--r--include/clang/AST/DeclFriend.h12
-rw-r--r--include/clang/AST/DeclObjC.h106
-rw-r--r--include/clang/AST/DeclTemplate.h130
-rw-r--r--include/clang/AST/DeclarationName.h4
-rw-r--r--include/clang/AST/Expr.h249
-rw-r--r--include/clang/AST/ExprCXX.h214
-rw-r--r--include/clang/AST/ExprObjC.h33
-rw-r--r--include/clang/AST/ExternalASTSource.h2
-rw-r--r--include/clang/AST/Makefile19
-rw-r--r--include/clang/AST/NSAPI.h6
-rw-r--r--include/clang/AST/NestedNameSpecifier.h3
-rw-r--r--include/clang/AST/OperationKinds.h6
-rw-r--r--include/clang/AST/PrettyPrinter.h12
-rw-r--r--include/clang/AST/RawCommentList.h6
-rw-r--r--include/clang/AST/RecordLayout.h4
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h13
-rw-r--r--include/clang/AST/SelectorLocationsKind.h4
-rw-r--r--include/clang/AST/Stmt.h377
-rw-r--r--include/clang/AST/StmtCXX.h5
-rw-r--r--include/clang/AST/StmtObjC.h7
-rw-r--r--include/clang/AST/TemplateBase.h92
-rw-r--r--include/clang/AST/Type.h163
-rw-r--r--include/clang/AST/TypeLoc.h42
-rw-r--r--include/clang/AST/UnresolvedSet.h2
-rw-r--r--include/clang/AST/VTableBuilder.h5
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h29
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h1445
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h621
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h65
-rw-r--r--include/clang/ASTMatchers/ASTTypeTraits.h209
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h24
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h3
-rw-r--r--include/clang/Analysis/AnalysisContext.h35
-rw-r--r--include/clang/Analysis/CFG.h6
-rw-r--r--include/clang/Analysis/DomainSpecific/ObjCNoReturn.h46
-rw-r--r--include/clang/Analysis/ProgramPoint.h7
-rw-r--r--include/clang/Basic/Attr.td16
-rw-r--r--include/clang/Basic/Builtins.def65
-rw-r--r--include/clang/Basic/BuiltinsMips.def63
-rw-r--r--include/clang/Basic/BuiltinsNVPTX.def246
-rw-r--r--include/clang/Basic/BuiltinsX86.def9
-rw-r--r--include/clang/Basic/ConvertUTF.h12
-rw-r--r--include/clang/Basic/Diagnostic.h27
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td16
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td24
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticGroups.td83
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td35
-rw-r--r--include/clang/Basic/DiagnosticOptions.def93
-rw-r--r--include/clang/Basic/DiagnosticOptions.h85
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td50
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td361
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td43
-rw-r--r--include/clang/Basic/FileManager.h4
-rw-r--r--include/clang/Basic/IdentifierTable.h33
-rw-r--r--include/clang/Basic/LangOptions.def22
-rw-r--r--include/clang/Basic/Module.h30
-rw-r--r--include/clang/Basic/ObjCRuntime.h45
-rw-r--r--include/clang/Basic/OnDiskHashTable.h5
-rw-r--r--include/clang/Basic/Sanitizers.def69
-rw-r--r--include/clang/Basic/SourceLocation.h2
-rw-r--r--include/clang/Basic/SourceManager.h21
-rw-r--r--include/clang/Basic/Specifiers.h15
-rw-r--r--include/clang/Basic/StmtNodes.td10
-rw-r--r--include/clang/Basic/TargetInfo.h59
-rw-r--r--include/clang/Basic/TargetOptions.h6
-rw-r--r--include/clang/Basic/TokenKinds.def41
-rw-r--r--include/clang/Basic/TokenKinds.h25
-rw-r--r--include/clang/Basic/TypeTraits.h1
-rw-r--r--include/clang/Basic/arm_neon.td8
-rw-r--r--include/clang/CodeGen/CodeGenAction.h2
-rw-r--r--include/clang/Driver/Action.h15
-rw-r--r--include/clang/Driver/Arg.h26
-rw-r--r--include/clang/Driver/ArgList.h72
-rw-r--r--include/clang/Driver/CC1AsOptions.h4
-rw-r--r--include/clang/Driver/CC1AsOptions.td43
-rw-r--r--include/clang/Driver/CC1Options.td419
-rw-r--r--include/clang/Driver/Compilation.h11
-rw-r--r--include/clang/Driver/Driver.h43
-rw-r--r--include/clang/Driver/Job.h4
-rw-r--r--include/clang/Driver/OptParser.td31
-rw-r--r--include/clang/Driver/OptTable.h61
-rw-r--r--include/clang/Driver/Option.h324
-rw-r--r--include/clang/Driver/Options.h4
-rw-r--r--include/clang/Driver/Options.td1645
-rw-r--r--include/clang/Driver/Tool.h4
-rw-r--r--include/clang/Driver/ToolChain.h40
-rw-r--r--include/clang/Driver/Types.h4
-rw-r--r--include/clang/Frontend/ASTUnit.h86
-rw-r--r--include/clang/Frontend/AnalyzerOptions.h135
-rw-r--r--include/clang/Frontend/CodeGenOptions.def132
-rw-r--r--include/clang/Frontend/CodeGenOptions.h182
-rw-r--r--include/clang/Frontend/CompilerInstance.h44
-rw-r--r--include/clang/Frontend/CompilerInvocation.h79
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h111
-rw-r--r--include/clang/Frontend/DiagnosticRenderer.h8
-rw-r--r--include/clang/Frontend/FrontendAction.h16
-rw-r--r--include/clang/Frontend/FrontendOptions.h34
-rw-r--r--include/clang/Frontend/LangStandard.h18
-rw-r--r--include/clang/Frontend/LangStandards.def58
-rw-r--r--include/clang/Frontend/LogDiagnosticPrinter.h4
-rw-r--r--include/clang/Frontend/MultiplexConsumer.h1
-rw-r--r--include/clang/Frontend/SerializedDiagnosticPrinter.h2
-rw-r--r--include/clang/Frontend/TextDiagnostic.h2
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h5
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h86
-rw-r--r--include/clang/Lex/ExternalPreprocessorSource.h3
-rw-r--r--include/clang/Lex/HeaderMap.h5
-rw-r--r--include/clang/Lex/HeaderSearch.h25
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h (renamed from include/clang/Frontend/HeaderSearchOptions.h)11
-rw-r--r--include/clang/Lex/Lexer.h91
-rw-r--r--include/clang/Lex/LiteralSupport.h10
-rw-r--r--include/clang/Lex/MacroInfo.h60
-rw-r--r--include/clang/Lex/ModuleMap.h74
-rw-r--r--include/clang/Lex/PPCallbacks.h53
-rw-r--r--include/clang/Lex/PPMutationListener.h43
-rw-r--r--include/clang/Lex/PTHLexer.h4
-rw-r--r--include/clang/Lex/PTHManager.h5
-rw-r--r--include/clang/Lex/PreprocessingRecord.h84
-rw-r--r--include/clang/Lex/Preprocessor.h128
-rw-r--r--include/clang/Lex/PreprocessorLexer.h4
-rw-r--r--include/clang/Lex/PreprocessorOptions.h (renamed from include/clang/Frontend/PreprocessorOptions.h)13
-rw-r--r--include/clang/Lex/Token.h18
-rw-r--r--include/clang/Lex/TokenLexer.h17
-rw-r--r--include/clang/Parse/Parser.h197
-rw-r--r--include/clang/Rewrite/Core/DeltaTree.h (renamed from include/clang/Rewrite/DeltaTree.h)4
-rw-r--r--include/clang/Rewrite/Core/HTMLRewrite.h (renamed from include/clang/Rewrite/HTMLRewrite.h)0
-rw-r--r--include/clang/Rewrite/Core/RewriteRope.h (renamed from include/clang/Rewrite/RewriteRope.h)26
-rw-r--r--include/clang/Rewrite/Core/Rewriter.h (renamed from include/clang/Rewrite/Rewriter.h)6
-rw-r--r--include/clang/Rewrite/Core/TokenRewriter.h (renamed from include/clang/Rewrite/TokenRewriter.h)4
-rw-r--r--include/clang/Rewrite/Frontend/ASTConsumers.h (renamed from include/clang/Rewrite/ASTConsumers.h)0
-rw-r--r--include/clang/Rewrite/Frontend/FixItRewriter.h (renamed from include/clang/Rewrite/FixItRewriter.h)2
-rw-r--r--include/clang/Rewrite/Frontend/FrontendActions.h (renamed from include/clang/Rewrite/FrontendActions.h)0
-rw-r--r--include/clang/Rewrite/Frontend/Rewriters.h (renamed from include/clang/Rewrite/Rewriters.h)0
-rw-r--r--include/clang/Sema/AttributeList.h8
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h20
-rw-r--r--include/clang/Sema/DeclSpec.h54
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h11
-rw-r--r--include/clang/Sema/ExternalSemaSource.h1
-rw-r--r--include/clang/Sema/Initialization.h4
-rw-r--r--include/clang/Sema/LocInfoType.h1
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h367
-rw-r--r--include/clang/Sema/Overload.h12
-rw-r--r--include/clang/Sema/Ownership.h216
-rw-r--r--include/clang/Sema/ParsedTemplate.h5
-rw-r--r--include/clang/Sema/Scope.h8
-rw-r--r--include/clang/Sema/ScopeInfo.h226
-rw-r--r--include/clang/Sema/Sema.h249
-rw-r--r--include/clang/Sema/SemaConsumer.h1
-rw-r--r--include/clang/Sema/Template.h5
-rw-r--r--include/clang/Sema/TemplateDeduction.h18
-rw-r--r--include/clang/Sema/TypoCorrection.h12
-rw-r--r--include/clang/Serialization/ASTBitCodes.h234
-rw-r--r--include/clang/Serialization/ASTDeserializationListener.h6
-rw-r--r--include/clang/Serialization/ASTReader.h476
-rw-r--r--include/clang/Serialization/ASTWriter.h72
-rw-r--r--include/clang/Serialization/ContinuousRangeMap.h4
-rw-r--r--include/clang/Serialization/Module.h66
-rw-r--r--include/clang/Serialization/ModuleManager.h9
-rw-r--r--include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h35
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def (renamed from include/clang/Frontend/Analyses.def)2
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h308
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h89
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h58
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h129
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h80
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h167
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h130
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h111
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h70
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h52
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h74
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h76
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h95
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h31
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h57
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h45
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h52
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h2
-rw-r--r--include/clang/Tooling/CommandLineClangTool.h80
-rw-r--r--include/clang/Tooling/CommonOptionsParser.h89
-rw-r--r--include/clang/Tooling/CompilationDatabase.h95
-rw-r--r--include/clang/Tooling/CompilationDatabasePluginRegistry.h27
-rw-r--r--include/clang/Tooling/FileMatchTrie.h90
-rw-r--r--include/clang/Tooling/JSONCompilationDatabase.h107
-rw-r--r--include/clang/Tooling/Refactoring.h1
-rw-r--r--include/clang/Tooling/Tooling.h48
-rw-r--r--lib/ARCMigrate/ARCMT.cpp75
-rw-r--r--lib/ARCMigrate/CMakeLists.txt3
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp2
-rw-r--r--lib/ARCMigrate/Internals.h2
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp2
-rw-r--r--lib/ARCMigrate/Transforms.cpp4
-rw-r--r--lib/AST/ASTConsumer.cpp5
-rw-r--r--lib/AST/ASTContext.cpp325
-rw-r--r--lib/AST/ASTDiagnostic.cpp277
-rw-r--r--lib/AST/ASTImporter.cpp478
-rw-r--r--lib/AST/CMakeLists.txt3
-rw-r--r--lib/AST/CXXInheritance.cpp32
-rw-r--r--lib/AST/Comment.cpp93
-rw-r--r--lib/AST/CommentBriefParser.cpp51
-rw-r--r--lib/AST/CommentCommandTraits.cpp141
-rw-r--r--lib/AST/CommentDumper.cpp48
-rw-r--r--lib/AST/CommentLexer.cpp62
-rw-r--r--lib/AST/CommentParser.cpp72
-rw-r--r--lib/AST/CommentSema.cpp314
-rw-r--r--lib/AST/Decl.cpp88
-rw-r--r--lib/AST/DeclBase.cpp2
-rw-r--r--lib/AST/DeclCXX.cpp30
-rw-r--r--lib/AST/DeclObjC.cpp269
-rw-r--r--lib/AST/DeclPrinter.cpp18
-rw-r--r--lib/AST/DeclTemplate.cpp86
-rw-r--r--lib/AST/DumpXML.cpp23
-rw-r--r--lib/AST/Expr.cpp299
-rw-r--r--lib/AST/ExprCXX.cpp121
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp61
-rw-r--r--lib/AST/ItaniumMangle.cpp133
-rw-r--r--lib/AST/MicrosoftMangle.cpp242
-rw-r--r--lib/AST/NSAPI.cpp1
-rw-r--r--lib/AST/ParentMap.cpp69
-rw-r--r--lib/AST/RawCommentList.cpp69
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp84
-rw-r--r--lib/AST/Stmt.cpp167
-rw-r--r--lib/AST/StmtDumper.cpp115
-rw-r--r--lib/AST/StmtPrinter.cpp68
-rw-r--r--lib/AST/StmtProfile.cpp16
-rw-r--r--lib/AST/TemplateBase.cpp63
-rw-r--r--lib/AST/Type.cpp55
-rw-r--r--lib/AST/TypeLoc.cpp55
-rw-r--r--lib/AST/TypePrinter.cpp14
-rw-r--r--lib/AST/VTableBuilder.cpp3
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp411
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp66
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp41
-rw-r--r--lib/Analysis/BodyFarm.cpp374
-rw-r--r--lib/Analysis/BodyFarm.h43
-rw-r--r--lib/Analysis/CFG.cpp83
-rw-r--r--lib/Analysis/CMakeLists.txt4
-rw-r--r--lib/Analysis/FormatString.cpp57
-rw-r--r--lib/Analysis/ObjCNoReturn.cpp67
-rw-r--r--lib/Analysis/PrintfFormatString.cpp43
-rw-r--r--lib/Analysis/ReachableCode.cpp4
-rw-r--r--lib/Analysis/ScanfFormatString.cpp36
-rw-r--r--lib/Analysis/ThreadSafety.cpp340
-rw-r--r--lib/Analysis/UninitializedValues.cpp64
-rw-r--r--lib/Basic/ConvertUTF.c24
-rw-r--r--lib/Basic/ConvertUTFWrapper.cpp18
-rw-r--r--lib/Basic/Diagnostic.cpp25
-rw-r--r--lib/Basic/DiagnosticIDs.cpp5
-rw-r--r--lib/Basic/FileManager.cpp7
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/Module.cpp11
-rw-r--r--lib/Basic/SourceLocation.cpp7
-rw-r--r--lib/Basic/SourceManager.cpp133
-rw-r--r--lib/Basic/TargetInfo.cpp8
-rw-r--r--lib/Basic/Targets.cpp406
-rw-r--r--lib/Basic/Version.cpp2
-rw-r--r--lib/CodeGen/ABIInfo.h38
-rw-r--r--lib/CodeGen/BackendUtil.cpp109
-rw-r--r--lib/CodeGen/CGBlocks.cpp138
-rw-r--r--lib/CodeGen/CGBlocks.h26
-rw-r--r--lib/CodeGen/CGBuiltin.cpp430
-rw-r--r--lib/CodeGen/CGCXXABI.cpp2
-rw-r--r--lib/CodeGen/CGCXXABI.h12
-rw-r--r--lib/CodeGen/CGCall.cpp223
-rw-r--r--lib/CodeGen/CGClass.cpp31
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp257
-rw-r--r--lib/CodeGen/CGDebugInfo.h3
-rw-r--r--lib/CodeGen/CGDecl.cpp53
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp77
-rw-r--r--lib/CodeGen/CGException.cpp17
-rw-r--r--lib/CodeGen/CGExpr.cpp568
-rw-r--r--lib/CodeGen/CGExprAgg.cpp32
-rw-r--r--lib/CodeGen/CGExprCXX.cpp71
-rw-r--r--lib/CodeGen/CGExprComplex.cpp5
-rw-r--r--lib/CodeGen/CGExprConstant.cpp41
-rw-r--r--lib/CodeGen/CGExprScalar.cpp482
-rw-r--r--lib/CodeGen/CGObjC.cpp86
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp156
-rw-r--r--lib/CodeGen/CGObjCMac.cpp798
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp7
-rw-r--r--lib/CodeGen/CGObjCRuntime.h8
-rw-r--r--lib/CodeGen/CGRTTI.cpp17
-rw-r--r--lib/CodeGen/CGRecordLayout.h4
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp26
-rw-r--r--lib/CodeGen/CGStmt.cpp128
-rw-r--r--lib/CodeGen/CGVTables.cpp60
-rw-r--r--lib/CodeGen/CodeGenAction.cpp6
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp66
-rw-r--r--lib/CodeGen/CodeGenFunction.h133
-rw-r--r--lib/CodeGen/CodeGenModule.cpp227
-rw-r--r--lib/CodeGen/CodeGenModule.h36
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp57
-rw-r--r--lib/CodeGen/CodeGenTBAA.h15
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp4
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp58
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp65
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp6
-rw-r--r--lib/CodeGen/TargetInfo.cpp752
-rw-r--r--lib/Driver/Arg.cpp34
-rw-r--r--lib/Driver/ArgList.cpp41
-rw-r--r--lib/Driver/CC1AsOptions.cpp14
-rw-r--r--lib/Driver/Compilation.cpp100
-rw-r--r--lib/Driver/Driver.cpp248
-rw-r--r--lib/Driver/DriverOptions.cpp14
-rw-r--r--lib/Driver/OptTable.cpp158
-rw-r--r--lib/Driver/Option.cpp333
-rw-r--r--lib/Driver/SanitizerArgs.h106
-rw-r--r--lib/Driver/ToolChain.cpp61
-rw-r--r--lib/Driver/ToolChains.cpp481
-rw-r--r--lib/Driver/ToolChains.h43
-rw-r--r--lib/Driver/Tools.cpp980
-rw-r--r--lib/Driver/Tools.h5
-rw-r--r--lib/Driver/Types.cpp14
-rw-r--r--lib/Driver/WindowsToolChain.cpp14
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp1
-rw-r--r--lib/Frontend/ASTConsumers.cpp5
-rw-r--r--lib/Frontend/ASTMerge.cpp5
-rw-r--r--lib/Frontend/ASTUnit.cpp306
-rw-r--r--lib/Frontend/ChainedDiagnosticConsumer.cpp2
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp22
-rw-r--r--lib/Frontend/CompilerInstance.cpp139
-rw-r--r--lib/Frontend/CompilerInvocation.cpp1261
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp11
-rw-r--r--lib/Frontend/DependencyFile.cpp10
-rw-r--r--lib/Frontend/DependencyGraph.cpp10
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp94
-rw-r--r--lib/Frontend/FrontendAction.cpp76
-rw-r--r--lib/Frontend/FrontendActions.cpp133
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp6
-rw-r--r--lib/Frontend/InitPreprocessor.cpp86
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp7
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp8
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp232
-rw-r--r--lib/Frontend/TextDiagnostic.cpp203
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp10
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp213
-rw-r--r--lib/Frontend/Warnings.cpp5
-rw-r--r--lib/FrontendTool/CMakeLists.txt3
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp9
-rw-r--r--lib/Headers/CMakeLists.txt4
-rw-r--r--lib/Headers/__wmmintrin_aes.h67
-rw-r--r--lib/Headers/__wmmintrin_pclmul.h34
-rw-r--r--lib/Headers/altivec.h26
-rw-r--r--lib/Headers/bmi2intrin.h19
-rw-r--r--lib/Headers/cpuid.h2
-rw-r--r--lib/Headers/f16cintrin.h58
-rw-r--r--lib/Headers/immintrin.h4
-rw-r--r--lib/Headers/module.map37
-rw-r--r--lib/Headers/rtmintrin.h49
-rw-r--r--lib/Headers/unwind.h2
-rw-r--r--lib/Headers/wmmintrin.h41
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h9
-rw-r--r--lib/Lex/HeaderMap.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp47
-rw-r--r--lib/Lex/Lexer.cpp75
-rw-r--r--lib/Lex/LiteralSupport.cpp263
-rw-r--r--lib/Lex/MacroArgs.cpp2
-rw-r--r--lib/Lex/MacroInfo.cpp90
-rw-r--r--lib/Lex/ModuleMap.cpp524
-rw-r--r--lib/Lex/PPDirectives.cpp56
-rw-r--r--lib/Lex/PPExpressions.cpp20
-rw-r--r--lib/Lex/PPLexerChange.cpp6
-rw-r--r--lib/Lex/PPMacroExpansion.cpp333
-rw-r--r--lib/Lex/PTHLexer.cpp11
-rw-r--r--lib/Lex/Pragma.cpp22
-rw-r--r--lib/Lex/PreprocessingRecord.cpp56
-rw-r--r--lib/Lex/Preprocessor.cpp66
-rw-r--r--lib/Lex/TokenLexer.cpp88
-rw-r--r--lib/Parse/ParseAST.cpp1
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp6
-rw-r--r--lib/Parse/ParseDecl.cpp224
-rw-r--r--lib/Parse/ParseDeclCXX.cpp190
-rw-r--r--lib/Parse/ParseExpr.cpp179
-rw-r--r--lib/Parse/ParseExprCXX.cpp203
-rw-r--r--lib/Parse/ParseInit.cpp11
-rw-r--r--lib/Parse/ParseObjc.cpp67
-rw-r--r--lib/Parse/ParsePragma.cpp248
-rw-r--r--lib/Parse/ParsePragma.h37
-rw-r--r--lib/Parse/ParseStmt.cpp297
-rw-r--r--lib/Parse/ParseTemplate.cpp10
-rw-r--r--lib/Parse/ParseTentative.cpp131
-rw-r--r--lib/Parse/Parser.cpp272
-rw-r--r--lib/Parse/RAIIObjectsForParser.h10
-rw-r--r--lib/Rewrite/CMakeLists.txt35
-rw-r--r--lib/Rewrite/Core/CMakeLists.txt24
-rw-r--r--lib/Rewrite/Core/DeltaTree.cpp (renamed from lib/Rewrite/DeltaTree.cpp)5
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp (renamed from lib/Rewrite/HTMLRewrite.cpp)5
-rw-r--r--lib/Rewrite/Core/Makefile18
-rw-r--r--lib/Rewrite/Core/RewriteRope.cpp (renamed from lib/Rewrite/RewriteRope.cpp)6
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp (renamed from lib/Rewrite/Rewriter.cpp)2
-rw-r--r--lib/Rewrite/Core/TokenRewriter.cpp (renamed from lib/Rewrite/TokenRewriter.cpp)2
-rw-r--r--lib/Rewrite/Frontend/CMakeLists.txt28
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp (renamed from lib/Rewrite/FixItRewriter.cpp)2
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp (renamed from lib/Rewrite/FrontendActions.cpp)8
-rw-r--r--lib/Rewrite/Frontend/HTMLPrint.cpp (renamed from lib/Rewrite/HTMLPrint.cpp)6
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp (renamed from lib/Rewrite/InclusionRewriter.cpp)12
-rw-r--r--lib/Rewrite/Frontend/Makefile18
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp (renamed from lib/Rewrite/RewriteMacros.cpp)4
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp (renamed from lib/Rewrite/RewriteModernObjC.cpp)156
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp (renamed from lib/Rewrite/RewriteObjC.cpp)38
-rw-r--r--lib/Rewrite/Frontend/RewriteTest.cpp (renamed from lib/Rewrite/RewriteTest.cpp)4
-rw-r--r--lib/Rewrite/Makefile10
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp290
-rw-r--r--lib/Sema/CMakeLists.txt3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp7
-rw-r--r--lib/Sema/DeclSpec.cpp38
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp2
-rw-r--r--lib/Sema/IdentifierResolver.cpp10
-rw-r--r--lib/Sema/JumpDiagnostics.cpp138
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp271
-rw-r--r--lib/Sema/ScopeInfo.cpp189
-rw-r--r--lib/Sema/Sema.cpp64
-rw-r--r--lib/Sema/SemaAccess.cpp17
-rw-r--r--lib/Sema/SemaAttr.cpp23
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp3
-rw-r--r--lib/Sema/SemaCast.cpp68
-rw-r--r--lib/Sema/SemaChecking.cpp706
-rw-r--r--lib/Sema/SemaCodeComplete.cpp86
-rw-r--r--lib/Sema/SemaDecl.cpp840
-rw-r--r--lib/Sema/SemaDeclAttr.cpp135
-rw-r--r--lib/Sema/SemaDeclCXX.cpp687
-rw-r--r--lib/Sema/SemaDeclObjC.cpp145
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp64
-rw-r--r--lib/Sema/SemaExpr.cpp475
-rw-r--r--lib/Sema/SemaExprCXX.cpp163
-rw-r--r--lib/Sema/SemaExprMember.cpp34
-rw-r--r--lib/Sema/SemaExprObjC.cpp124
-rw-r--r--lib/Sema/SemaInit.cpp120
-rw-r--r--lib/Sema/SemaLambda.cpp31
-rw-r--r--lib/Sema/SemaLookup.cpp43
-rw-r--r--lib/Sema/SemaObjCProperty.cpp227
-rw-r--r--lib/Sema/SemaOverload.cpp430
-rw-r--r--lib/Sema/SemaPseudoObject.cpp87
-rw-r--r--lib/Sema/SemaStmt.cpp930
-rw-r--r--lib/Sema/SemaStmtAsm.cpp661
-rw-r--r--lib/Sema/SemaStmtAttr.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp370
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp160
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp126
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp172
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--lib/Sema/SemaType.cpp176
-rw-r--r--lib/Sema/TreeTransform.h360
-rw-r--r--lib/Serialization/ASTCommon.cpp3
-rw-r--r--lib/Serialization/ASTReader.cpp2323
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp151
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp35
-rw-r--r--lib/Serialization/ASTWriter.cpp781
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp58
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp28
-rw-r--r--lib/Serialization/GeneratePCH.cpp13
-rw-r--r--lib/Serialization/Module.cpp18
-rw-r--r--lib/Serialization/ModuleManager.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp92
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp109
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt6
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp77
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp59
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td83
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp72
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp60
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp180
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp550
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp41
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp259
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp87
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp218
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp203
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp94
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp356
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp348
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp46
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp36
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp138
-rw-r--r--lib/StaticAnalyzer/Core/BasicConstraintManager.cpp446
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp517
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp602
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt7
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp166
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp54
-rw-r--r--lib/StaticAnalyzer/Core/ConstraintManager.cpp39
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp204
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp155
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp414
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp133
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp79
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp351
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp82
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp34
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp306
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp47
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp68
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp308
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h4
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp25
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp86
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp109
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp1
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp154
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.h4
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp2
-rw-r--r--lib/Tooling/CMakeLists.txt7
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp (renamed from lib/Tooling/CommandLineClangTool.cpp)61
-rw-r--r--lib/Tooling/CompilationDatabase.cpp297
-rw-r--r--lib/Tooling/CustomCompilationDatabase.h42
-rw-r--r--lib/Tooling/FileMatchTrie.cpp188
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp303
-rw-r--r--lib/Tooling/Refactoring.cpp11
-rw-r--r--lib/Tooling/Tooling.cpp30
-rw-r--r--runtime/compiler-rt/Makefile61
-rw-r--r--runtime/compiler-rt/clang_linux_test_input.c4
-rw-r--r--test/ARCMT/cxx-checking.mm27
-rw-r--r--test/ARCMT/verify.m5
-rw-r--r--test/ASTMerge/exprs.c1
-rw-r--r--test/Analysis/CFContainers-invalid.c20
-rw-r--r--test/Analysis/CFContainers.mm16
-rw-r--r--test/Analysis/CFDateGC.m1
-rw-r--r--test/Analysis/CFNumber.c1
-rw-r--r--test/Analysis/CFRetainRelease_NSAssertionHandler.m4
-rw-r--r--test/Analysis/CGColorSpace.c1
-rw-r--r--test/Analysis/CheckNSError.m1
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h57
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-simple-stream.h11
-rw-r--r--test/Analysis/Inputs/system-header-simulator-objc.h (renamed from test/Analysis/system-header-simulator-objc.h)0
-rw-r--r--test/Analysis/Inputs/system-header-simulator.h (renamed from test/Analysis/system-header-simulator.h)4
-rw-r--r--test/Analysis/MissingDealloc.m3
-rw-r--r--test/Analysis/NSPanel.m4
-rw-r--r--test/Analysis/NSString.m6
-rw-r--r--test/Analysis/NSWindow.m3
-rw-r--r--test/Analysis/NoReturn.m4
-rw-r--r--test/Analysis/OSAtomic_mac.cpp1
-rw-r--r--test/Analysis/ObjCProperties.m4
-rw-r--r--test/Analysis/ObjCRetSigs.m2
-rw-r--r--test/Analysis/PR2599.m2
-rw-r--r--test/Analysis/PR2978.m2
-rw-r--r--test/Analysis/PR3991.m3
-rw-r--r--test/Analysis/PR9741.cpp1
-rw-r--r--test/Analysis/additive-folding.cpp9
-rw-r--r--test/Analysis/analyzer-config.c13
-rw-r--r--test/Analysis/analyzer-config.cpp22
-rw-r--r--test/Analysis/array-struct-region.c110
-rw-r--r--test/Analysis/array-struct-region.cpp176
-rw-r--r--test/Analysis/array-struct.c11
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp2
-rw-r--r--test/Analysis/base-init.cpp3
-rw-r--r--test/Analysis/bitwise-ops.c14
-rw-r--r--test/Analysis/blocks.m14
-rw-r--r--test/Analysis/bool-assignment.cpp2
-rw-r--r--test/Analysis/bool-assignment2.c2
-rw-r--r--test/Analysis/bstring.c8
-rw-r--r--test/Analysis/casts.c5
-rw-r--r--test/Analysis/casts.m3
-rw-r--r--test/Analysis/cfref_PR2519.c4
-rw-r--r--test/Analysis/cfref_rdar6080742.c4
-rw-r--r--test/Analysis/chroot.c2
-rw-r--r--test/Analysis/comparison-implicit-casts.cpp2
-rw-r--r--test/Analysis/complex-init-list.cpp7
-rw-r--r--test/Analysis/complex.c1
-rw-r--r--test/Analysis/concrete-address.c3
-rw-r--r--test/Analysis/conditional-operator-path-notes.c1083
-rw-r--r--test/Analysis/coverage.c2
-rw-r--r--test/Analysis/cstring-syntax-cxx.cpp1
-rw-r--r--test/Analysis/ctor-inlining.mm32
-rw-r--r--test/Analysis/cxx-crashes.cpp1
-rw-r--r--test/Analysis/cxx-method-names.cpp3
-rw-r--r--test/Analysis/cxx11-crashes.cpp1
-rw-r--r--test/Analysis/dead-stores.c5
-rw-r--r--test/Analysis/dead-stores.cpp41
-rw-r--r--test/Analysis/dead-stores.m3
-rw-r--r--test/Analysis/delegates.m1
-rw-r--r--test/Analysis/derived-to-base.cpp2
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.c354
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.cpp16
-rw-r--r--test/Analysis/diagnostics/undef-value-caller.c379
-rw-r--r--test/Analysis/diagnostics/undef-value-param.c1183
-rw-r--r--test/Analysis/diagnostics/undef-value-param.m476
-rw-r--r--test/Analysis/domtest.c2
-rw-r--r--test/Analysis/dtor.cpp78
-rw-r--r--test/Analysis/dtors-in-dtor-cfg-output.cpp2
-rw-r--r--test/Analysis/elementtype.c2
-rw-r--r--test/Analysis/engine/replay-without-inlining.c1
-rw-r--r--test/Analysis/exceptions.mm38
-rw-r--r--test/Analysis/exercise-ps.c2
-rw-r--r--test/Analysis/fields.c12
-rw-r--r--test/Analysis/free.c2
-rw-r--r--test/Analysis/func.c2
-rw-r--r--test/Analysis/global-region-invalidation.c4
-rw-r--r--test/Analysis/idempotent-operations-limited-loops.c6
-rw-r--r--test/Analysis/idempotent-operations.c10
-rw-r--r--test/Analysis/idempotent-operations.cpp2
-rw-r--r--test/Analysis/idempotent-operations.m3
-rw-r--r--test/Analysis/initializer.cpp22
-rw-r--r--test/Analysis/inline-not-supported.c4
-rw-r--r--test/Analysis/inline-plist.c2988
-rw-r--r--test/Analysis/inline-unique-reports.c2
-rw-r--r--test/Analysis/inline.c2
-rw-r--r--test/Analysis/inline.cpp176
-rw-r--r--test/Analysis/inline2.c3
-rw-r--r--test/Analysis/inline3.c3
-rw-r--r--test/Analysis/inline4.c3
-rw-r--r--test/Analysis/inlining/DynDispatchBifurcate.m12
-rw-r--r--test/Analysis/inlining/InlineObjCInstanceMethod.m66
-rw-r--r--test/Analysis/inlining/RetainCountExamples.m96
-rw-r--r--test/Analysis/inlining/assume-super-init-does-not-return-nil.m41
-rw-r--r--test/Analysis/inlining/dyn-dispatch-bifurcate.cpp16
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.c788
-rw-r--r--test/Analysis/inlining/false-positive-suppression.c184
-rw-r--r--test/Analysis/inlining/path-notes.c4413
-rw-r--r--test/Analysis/inlining/path-notes.m469
-rw-r--r--test/Analysis/inlining/retain-count-self-init.m68
-rw-r--r--test/Analysis/inlining/stl.cpp29
-rw-r--r--test/Analysis/inlining/test-always-inline-size-option.c48
-rw-r--r--test/Analysis/inlining/test_objc_inlining_option.m34
-rw-r--r--test/Analysis/ivars.m8
-rw-r--r--test/Analysis/keychainAPI.m2
-rw-r--r--test/Analysis/logical-ops.c27
-rw-r--r--test/Analysis/lvalue.cpp1
-rw-r--r--test/Analysis/malloc-annotations.c2
-rw-r--r--test/Analysis/malloc-interprocedural.c41
-rw-r--r--test/Analysis/malloc-overflow.c2
-rw-r--r--test/Analysis/malloc-overflow.cpp3
-rw-r--r--test/Analysis/malloc-plist.c8604
-rw-r--r--test/Analysis/malloc-sizeof.c16
-rw-r--r--test/Analysis/malloc.c35
-rw-r--r--test/Analysis/malloc.cpp27
-rw-r--r--test/Analysis/malloc.m2
-rw-r--r--test/Analysis/malloc.mm60
-rw-r--r--test/Analysis/member-expr.cpp23
-rw-r--r--test/Analysis/method-call-intra-p.cpp1
-rw-r--r--test/Analysis/method-call-path-notes.cpp1470
-rw-r--r--test/Analysis/method-call.cpp30
-rw-r--r--test/Analysis/misc-ps-64.m4
-rw-r--r--test/Analysis/misc-ps-arm.m1
-rw-r--r--test/Analysis/misc-ps-eager-assume.m3
-rw-r--r--test/Analysis/misc-ps-ranges.m2
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m3
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m3
-rw-r--r--test/Analysis/misc-ps-region-store.cpp10
-rw-r--r--test/Analysis/misc-ps-region-store.m7
-rw-r--r--test/Analysis/misc-ps-region-store.mm5
-rw-r--r--test/Analysis/misc-ps.c18
-rw-r--r--test/Analysis/misc-ps.m10
-rw-r--r--test/Analysis/new-with-exceptions.cpp71
-rw-r--r--test/Analysis/new.cpp12
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m9
-rw-r--r--test/Analysis/no-exit-cfg.c3
-rw-r--r--test/Analysis/no-outofbounds.c2
-rw-r--r--test/Analysis/null-deref-path-notes.m488
-rw-r--r--test/Analysis/null-deref-ps-region.c3
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/objc-bool.m1
-rw-r--r--test/Analysis/objc-for.m2
-rw-r--r--test/Analysis/objc-method-coverage.m2
-rw-r--r--test/Analysis/objc-properties.m72
-rw-r--r--test/Analysis/objc_invalidation.m153
-rw-r--r--test/Analysis/operator-calls.cpp21
-rw-r--r--test/Analysis/out-of-bounds.c2
-rw-r--r--test/Analysis/outofbound-notwork.c2
-rw-r--r--test/Analysis/outofbound.c2
-rw-r--r--test/Analysis/override-werror.c2
-rw-r--r--test/Analysis/plist-html-macros.c31
-rw-r--r--test/Analysis/plist-output-alternate.m2137
-rw-r--r--test/Analysis/plist-output.m3659
-rw-r--r--test/Analysis/pointer-to-member.cpp44
-rw-r--r--test/Analysis/pr4209.m2
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m2
-rw-r--r--test/Analysis/pr_4164.c3
-rw-r--r--test/Analysis/pthreadlock.c2
-rw-r--r--test/Analysis/ptr-arith.c4
-rw-r--r--test/Analysis/rdar-6442306-1.m3
-rw-r--r--test/Analysis/rdar-6540084.m2
-rw-r--r--test/Analysis/rdar-6541136-region.c2
-rw-r--r--test/Analysis/rdar-6562655.m3
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m3
-rw-r--r--test/Analysis/rdar-7168531.m2
-rw-r--r--test/Analysis/redefined_system.c3
-rw-r--r--test/Analysis/refcnt_naming.m2
-rw-r--r--test/Analysis/reference.cpp28
-rw-r--r--test/Analysis/region-1.m3
-rw-r--r--test/Analysis/region-store.c1
-rw-r--r--test/Analysis/retain-release-gc-only.m53
-rw-r--r--test/Analysis/retain-release-inline.m18
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m2662
-rw-r--r--test/Analysis/retain-release-path-notes.m8833
-rw-r--r--test/Analysis/retain-release.m22839
-rw-r--r--test/Analysis/retain-release.mm19
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c1
-rw-r--r--test/Analysis/simple-stream-checks.c78
-rw-r--r--test/Analysis/sizeofpointer.c2
-rw-r--r--test/Analysis/stack-addr-ps.cpp2
-rw-r--r--test/Analysis/static_local.m19
-rw-r--r--test/Analysis/stream.c2
-rw-r--r--test/Analysis/string.c8
-rw-r--r--test/Analysis/svalbuilder-logic.c1
-rw-r--r--test/Analysis/taint-generic.c2
-rw-r--r--test/Analysis/taint-tester.c2
-rw-r--r--test/Analysis/taint-tester.cpp3
-rw-r--r--test/Analysis/taint-tester.m3
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp2
-rw-r--r--test/Analysis/templates.cpp8
-rw-r--r--test/Analysis/temporaries.cpp30
-rw-r--r--test/Analysis/test-objc-non-nil-return-value-checker.m50
-rw-r--r--test/Analysis/traversal-path-unification.c28
-rw-r--r--test/Analysis/undef-buffers.c2
-rw-r--r--test/Analysis/uninit-vals-ps-region.m2
-rw-r--r--test/Analysis/uninit-vals-ps.c12
-rw-r--r--test/Analysis/uninit-vals.m1
-rw-r--r--test/Analysis/unions-region.m1
-rw-r--r--test/Analysis/unions.cpp51
-rw-r--r--test/Analysis/unix-fns.c1857
-rw-r--r--test/Analysis/unreachable-code-path.c2
-rw-r--r--test/Analysis/viewcontroller.m135
-rw-r--r--test/Analysis/virtualcall.cpp8
-rw-r--r--test/Analysis/virtualcall.h28
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp24
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.classref/p4-cxx11.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.udir/p1.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p12.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp1
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.local/p2.cpp37
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp1
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2a.cpp1
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2b.cpp1
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2c.cpp1
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2g.cpp1
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp1
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp1
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp24
-rw-r--r--test/CXX/class.access/class.friend/p3-cxx0x.cpp26
-rw-r--r--test/CXX/class.access/class.protected/p1-cxx11.cpp1
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp2
-rw-r--r--test/CXX/class.derived/class.abstract/p16.cpp16
-rw-r--r--test/CXX/class.derived/p2.cpp1
-rw-r--r--test/CXX/class/class.friend/p1-ambiguous.cpp1
-rw-r--r--test/CXX/class/class.friend/p1-cxx11.cpp1
-rw-r--r--test/CXX/class/class.nest/p3.cpp1
-rw-r--r--test/CXX/class/p1-0x.cpp1
-rw-r--r--test/CXX/class/p2-0x.cpp8
-rw-r--r--test/CXX/class/p6-0x.cpp1
-rw-r--r--test/CXX/conv/conv.prom/p2.cpp5
-rw-r--r--test/CXX/conv/conv.prom/p4.cpp19
-rw-r--r--test/CXX/conv/conv.ptr/p2.cpp1
-rw-r--r--test/CXX/conv/conv.qual/pr6089.cpp1
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p2.cpp1
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp4
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp1
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp1
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udir/p6.cpp1
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp6
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp6
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.init/p7.cpp14
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp6
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/p1.cpp14
-rw-r--r--test/CXX/dcl.decl/dcl.name/p1.cpp1
-rw-r--r--test/CXX/dcl.decl/p4-0x.cpp1
-rw-r--r--test/CXX/except/except.spec/canonical.cpp1
-rw-r--r--test/CXX/except/except.spec/p11.cpp1
-rw-r--r--test/CXX/except/except.spec/p14.cpp38
-rw-r--r--test/CXX/except/except.spec/p15.cpp14
-rw-r--r--test/CXX/except/except.spec/p4.cpp36
-rw-r--r--test/CXX/expr/expr.cast/p4-0x.cpp1
-rw-r--r--test/CXX/expr/expr.const/p3-0x-nowarn.cpp1
-rw-r--r--test/CXX/expr/expr.const/p5-0x.cpp8
-rw-r--r--test/CXX/expr/expr.post/expr.const.cast/p1-0x.cpp1
-rw-r--r--test/CXX/expr/expr.post/expr.ref/p3.cpp1
-rw-r--r--test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp1
-rw-r--r--test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp1
-rw-r--r--test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp1
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp4
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp15
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp1
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp1
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp1
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp1
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp1
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p3.cpp1
-rw-r--r--test/CXX/expr/p8.cpp1
-rw-r--r--test/CXX/expr/p9.cpp1
-rw-r--r--test/CXX/lex/lex.literal/lex.ccon/p1.cpp1
-rw-r--r--test/CXX/lex/lex.trigraph/p3.cpp1
-rw-r--r--test/CXX/over/over.built/p1.cpp16
-rw-r--r--test/CXX/over/over.built/p23.cpp1
-rw-r--r--test/CXX/over/over.built/p25.cpp1
-rw-r--r--test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp1
-rw-r--r--test/CXX/over/over.match/over.match.best/p1.cpp1
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp29
-rw-r--r--test/CXX/over/over.match/over.match.funcs/p4-0x.cpp1
-rw-r--r--test/CXX/over/over.oper/over.literal/p7.cpp1
-rw-r--r--test/CXX/over/over.oper/over.literal/p8.cpp5
-rw-r--r--test/CXX/special/class.conv/class.conv.ctor/p1.cpp1
-rw-r--r--test/CXX/special/class.copy/p15-0x.cpp1
-rw-r--r--test/CXX/special/class.copy/p8-cxx11.cpp1
-rw-r--r--test/CXX/special/class.ctor/p1.cpp1
-rw-r--r--test/CXX/special/class.dtor/p2.cpp1
-rw-r--r--test/CXX/special/class.dtor/p3-0x.cpp2
-rw-r--r--test/CXX/special/class.dtor/p3.cpp17
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp104
-rw-r--r--test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp1
-rw-r--r--test/CXX/temp/p3.cpp2
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p1.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p9.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3-0x.cpp28
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp13
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p1.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/deduction.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-function.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp24
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp1
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp1
-rw-r--r--test/CXX/temp/temp.names/p2.cpp1
-rw-r--r--test/CXX/temp/temp.names/p4.cpp1
-rw-r--r--test/CXX/temp/temp.param/p10-0x.cpp1
-rw-r--r--test/CXX/temp/temp.param/p10.cpp1
-rw-r--r--test/CXX/temp/temp.param/p13.cpp1
-rw-r--r--test/CXX/temp/temp.param/p15-cxx0x.cpp154
-rw-r--r--test/CXX/temp/temp.param/p2.cpp1
-rw-r--r--test/CXX/temp/temp.param/p5.cpp1
-rw-r--r--test/CXX/temp/temp.param/p8.cpp1
-rw-r--r--test/CXX/temp/temp.res/temp.dep/p3.cpp1
-rw-r--r--test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp1
-rw-r--r--test/CXX/temp/temp.res/temp.local/p1.cpp1
-rw-r--r--test/CXX/temp/temp.res/temp.local/p7.cpp1
-rw-r--r--test/CXX/temp/temp.res/temp.local/p8.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p11.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp1
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p6.cpp1
-rw-r--r--test/CodeCompletion/Inputs/macros.h7
-rw-r--r--test/CodeCompletion/macros.c12
-rw-r--r--test/CodeCompletion/preamble.c2
-rw-r--r--test/CodeGen/2004-03-16-AsmRegisterCrash.c5
-rw-r--r--test/CodeGen/2008-01-25-ByValReadNone.c8
-rw-r--r--test/CodeGen/2008-01-25-ZeroSizedAggregate.c1
-rw-r--r--test/CodeGen/2008-12-23-AsmIntPointerTie.c1
-rw-r--r--test/CodeGen/2009-06-01-addrofknr.c1
-rw-r--r--test/CodeGen/2010-06-17-asmcrash.c5
-rw-r--r--test/CodeGen/PR3589-freestanding-libcalls.c6
-rw-r--r--test/CodeGen/a15.c5
-rw-r--r--test/CodeGen/address-safety-attr.cpp2
-rw-r--r--test/CodeGen/alias.c44
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c6
-rw-r--r--test/CodeGen/arm-aapcs-zerolength-bitfield.c1
-rw-r--r--test/CodeGen/arm-abi-vector.c263
-rw-r--r--test/CodeGen/arm-apcs-zerolength-bitfield.c1
-rw-r--r--test/CodeGen/arm-arguments.c45
-rw-r--r--test/CodeGen/arm-asm-warn.c18
-rw-r--r--test/CodeGen/arm-homogenous.c41
-rw-r--r--test/CodeGen/arm-pnaclcall.c33
-rw-r--r--test/CodeGen/asm.c9
-rw-r--r--test/CodeGen/atomic-ops.c9
-rw-r--r--test/CodeGen/attr-minsize.cpp75
-rw-r--r--test/CodeGen/attr-weakref.c6
-rw-r--r--test/CodeGen/attributes.c2
-rw-r--r--test/CodeGen/bitfield-promote.c10
-rw-r--r--test/CodeGen/bmi2-builtins.c17
-rw-r--r--test/CodeGen/builtin-memfns.c20
-rw-r--r--test/CodeGen/builtin-ms-noop.cpp14
-rw-r--r--test/CodeGen/builtins-mips-args.c23
-rw-r--r--test/CodeGen/builtins-mips.c210
-rw-r--r--test/CodeGen/builtins-nvptx.c74
-rw-r--r--test/CodeGen/builtins.c1
-rw-r--r--test/CodeGen/catch-undef-behavior.c241
-rw-r--r--test/CodeGen/const-init.c15
-rw-r--r--test/CodeGen/const-label-addr.c15
-rw-r--r--test/CodeGen/debug-info-iv.c2
-rw-r--r--test/CodeGen/debug-info-line3.c4
-rw-r--r--test/CodeGen/debug-info-line4.c11
-rw-r--r--test/CodeGen/debug-info.c5
-rw-r--r--test/CodeGen/debug-line-1.c2
-rw-r--r--test/CodeGen/decl-in-prototype.c2
-rw-r--r--test/CodeGen/dostmt.c10
-rw-r--r--test/CodeGen/exprs.c10
-rw-r--r--test/CodeGen/extern-inline.c4
-rw-r--r--test/CodeGen/f16c-builtins.c26
-rw-r--r--test/CodeGen/ffp-contract-option.c (renamed from test/CodeGen/fp-contract.c)0
-rw-r--r--test/CodeGen/fold-const-declref.c4
-rw-r--r--test/CodeGen/fp-contract-pragma.cpp64
-rw-r--r--test/CodeGen/func-ptr-cast-decl.c1
-rw-r--r--test/CodeGen/init.c2
-rw-r--r--test/CodeGen/inline.c6
-rw-r--r--test/CodeGen/integer-overflow.c9
-rw-r--r--test/CodeGen/le32-arguments.c61
-rw-r--r--test/CodeGen/le32-regparm.c41
-rw-r--r--test/CodeGen/libcall-declarations.c191
-rw-r--r--test/CodeGen/libcalls-fno-builtin.c97
-rw-r--r--test/CodeGen/long-double-x86-nacl.c7
-rw-r--r--test/CodeGen/microsoft-call-conv-x64.c39
-rw-r--r--test/CodeGen/microsoft-call-conv.c2
-rw-r--r--test/CodeGen/mips-byval-arg.c4
-rw-r--r--test/CodeGen/mips-clobber-reg.c2
-rw-r--r--test/CodeGen/mips-constraint-regs.c7
-rw-r--r--test/CodeGen/mips-vector-arg.c4
-rw-r--r--test/CodeGen/mips-vector-return.c4
-rw-r--r--test/CodeGen/mips64-class-return.cpp2
-rw-r--r--test/CodeGen/mips64-f128-literal.c2
-rw-r--r--test/CodeGen/mips64-nontrivial-return.cpp2
-rw-r--r--test/CodeGen/mips64-padding-arg.c2
-rw-r--r--test/CodeGen/ms-inline-asm-64.c16
-rw-r--r--test/CodeGen/ms-inline-asm.c170
-rw-r--r--test/CodeGen/ppc-atomics.c35
-rw-r--r--test/CodeGen/ppc64-align-long-double.c18
-rw-r--r--test/CodeGen/ppc64-extend.c15
-rw-r--r--test/CodeGen/ppc64-struct-onefloat.c49
-rw-r--r--test/CodeGen/ppc64-varargs-struct.c30
-rw-r--r--test/CodeGen/pragma-weak.c9
-rw-r--r--test/CodeGen/rtm-builtins.c23
-rw-r--r--test/CodeGen/sse-builtins.c31
-rw-r--r--test/CodeGen/statements.c1
-rw-r--r--test/CodeGen/stdcall-fastcall.c98
-rw-r--r--test/CodeGen/tbaa-for-vptr.cpp10
-rw-r--r--test/CodeGen/tbaa-struct.cpp17
-rw-r--r--test/CodeGen/trapv.c18
-rw-r--r--test/CodeGen/unwind-attr.c4
-rw-r--r--test/CodeGen/x86_64-arguments-nacl.c120
-rw-r--r--test/CodeGenCUDA/address-spaces.cu12
-rw-r--r--test/CodeGenCXX/2005-01-03-StaticInitializers.cpp1
-rw-r--r--test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp2
-rw-r--r--test/CodeGenCXX/assign-construct-memcpy.cpp89
-rw-r--r--test/CodeGenCXX/attr.cpp10
-rw-r--r--test/CodeGenCXX/builtins.cpp12
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp134
-rw-r--r--test/CodeGenCXX/compound-literals.cpp6
-rw-r--r--test/CodeGenCXX/const-global-linkage.cpp4
-rw-r--r--test/CodeGenCXX/const-init-cxx11.cpp6
-rw-r--r--test/CodeGenCXX/conversion-operator-base.cpp1
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-3.cpp1
-rw-r--r--test/CodeGenCXX/copy-constructor-elim-2.cpp4
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-array.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-constructors.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-references.cpp6
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp2
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp2
-rw-r--r--test/CodeGenCXX/cxx11-special-members.cpp32
-rw-r--r--test/CodeGenCXX/debug-info-artificial-arg.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-blocks.cpp14
-rw-r--r--test/CodeGenCXX/debug-info-class.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-enum-class.cpp16
-rw-r--r--test/CodeGenCXX/debug-info-fwd-ref.cpp11
-rw-r--r--test/CodeGenCXX/debug-info-global-ctor-dtor.cpp27
-rw-r--r--test/CodeGenCXX/debug-info-globalinit.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-pubtypes.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-template-quals.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-thunk.cpp17
-rw-r--r--test/CodeGenCXX/debug-info-user-def.cpp14
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp18
-rw-r--r--test/CodeGenCXX/debug-lambda-this.cpp15
-rw-r--r--test/CodeGenCXX/delete.cpp23
-rw-r--r--test/CodeGenCXX/dependent-type-member-pointer.cpp1
-rw-r--r--test/CodeGenCXX/destructor-debug-info.cpp2
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp5
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls.cpp4
-rw-r--r--test/CodeGenCXX/enum.cpp1
-rw-r--r--test/CodeGenCXX/exceptions.cpp1
-rw-r--r--test/CodeGenCXX/fastcall.cpp20
-rw-r--r--test/CodeGenCXX/for-range.cpp12
-rw-r--r--test/CodeGenCXX/implicit-copy-constructor.cpp28
-rw-r--r--test/CodeGenCXX/incomplete-types.cpp1
-rw-r--r--test/CodeGenCXX/init-priority-attr.cpp46
-rw-r--r--test/CodeGenCXX/instantiate-init-list.cpp1
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp9
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp7
-rw-r--r--test/CodeGenCXX/mangle-extern-local.cpp2
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp27
-rw-r--r--test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp78
-rw-r--r--test/CodeGenCXX/mangle-ms-return-qualifiers.cpp5
-rw-r--r--test/CodeGenCXX/mangle-ms-template-callback.cpp72
-rw-r--r--test/CodeGenCXX/mangle-ms-templates.cpp12
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp39
-rw-r--r--test/CodeGenCXX/mangle-nullptr-arg.cpp3
-rw-r--r--test/CodeGenCXX/mangle-template.cpp16
-rw-r--r--test/CodeGenCXX/mangle-valist.cpp44
-rw-r--r--test/CodeGenCXX/member-alignment.cpp1
-rw-r--r--test/CodeGenCXX/member-call-parens.cpp1
-rw-r--r--test/CodeGenCXX/member-functions.cpp3
-rw-r--r--test/CodeGenCXX/member-init-assignment.cpp2
-rw-r--r--test/CodeGenCXX/member-init-struct.cpp1
-rw-r--r--test/CodeGenCXX/member-init-union.cpp1
-rw-r--r--test/CodeGenCXX/microsoft-abi-constructors.cpp11
-rw-r--r--test/CodeGenCXX/microsoft-abi-default-cc.cpp47
-rw-r--r--test/CodeGenCXX/microsoft-abi-methods.cpp6
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp6
-rw-r--r--test/CodeGenCXX/microsoft-interface.cpp43
-rw-r--r--test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp13
-rw-r--r--test/CodeGenCXX/microsoft-uuidof.cpp72
-rw-r--r--test/CodeGenCXX/new-operator-phi.cpp1
-rw-r--r--test/CodeGenCXX/new.cpp10
-rw-r--r--test/CodeGenCXX/nrvo.cpp4
-rw-r--r--test/CodeGenCXX/override-layout.cpp15
-rw-r--r--test/CodeGenCXX/pr12251.cpp4
-rw-r--r--test/CodeGenCXX/pragma-visibility.cpp2
-rw-r--r--test/CodeGenCXX/reference-bind-default-argument.cpp1
-rw-r--r--test/CodeGenCXX/reference-init.cpp1
-rw-r--r--test/CodeGenCXX/regparm.cpp32
-rw-r--r--test/CodeGenCXX/reinterpret-cast.cpp2
-rw-r--r--test/CodeGenCXX/return.cpp12
-rw-r--r--test/CodeGenCXX/static-assert.cpp1
-rw-r--r--test/CodeGenCXX/static-init-2.cpp1
-rw-r--r--test/CodeGenCXX/switch-case-folding-2.cpp2
-rw-r--r--test/CodeGenCXX/throw-expression-cleanup.cpp2
-rw-r--r--test/CodeGenCXX/throw-expression-dtor.cpp1
-rw-r--r--test/CodeGenCXX/throw-expressions.cpp1
-rw-r--r--test/CodeGenCXX/thunk-linkonce-odr.cpp2
-rw-r--r--test/CodeGenCXX/thunks.cpp45
-rw-r--r--test/CodeGenCXX/typeid-cxx11.cpp8
-rw-r--r--test/CodeGenCXX/unary-type-trait.cpp1
-rw-r--r--test/CodeGenCXX/virtual-operator-call.cpp2
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp11
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp21
-rw-r--r--test/CodeGenCXX/vtt-layout.cpp24
-rw-r--r--test/CodeGenObjC/2008-10-3-EhValue.m2
-rw-r--r--test/CodeGenObjC/arc-arm.m20
-rw-r--r--test/CodeGenObjC/arc-block-ivar-layout.m60
-rw-r--r--test/CodeGenObjC/arc-blocks.m133
-rw-r--r--test/CodeGenObjC/arc-captured-32bit-block-var-layout.m425
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-inlined-layout.m112
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-layout.m425
-rw-r--r--test/CodeGenObjC/arc-exceptions.m5
-rw-r--r--test/CodeGenObjC/arc-foreach.m8
-rw-r--r--test/CodeGenObjC/arc-ivar-layout.m1
-rw-r--r--test/CodeGenObjC/arc-no-runtime.m4
-rw-r--r--test/CodeGenObjC/arc-property.m76
-rw-r--r--test/CodeGenObjC/arc-related-result-type.m10
-rw-r--r--test/CodeGenObjC/arc.m9
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m11
-rw-r--r--test/CodeGenObjC/attr-minsize.m12
-rw-r--r--test/CodeGenObjC/block-var-layout.m6
-rw-r--r--test/CodeGenObjC/builtin-memfns.m10
-rw-r--r--test/CodeGenObjC/category-super-class-meth.m32
-rw-r--r--test/CodeGenObjC/debug-info-crash-2.m2
-rw-r--r--test/CodeGenObjC/debug-info-fwddecl.m2
-rw-r--r--test/CodeGenObjC/debug-info-impl.m2
-rw-r--r--test/CodeGenObjC/debug-info-ivars.m24
-rw-r--r--test/CodeGenObjC/debug-info-pubtypes.m4
-rw-r--r--test/CodeGenObjC/debug-info-self.m8
-rw-r--r--test/CodeGenObjC/exceptions.m4
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m2
-rw-r--r--test/CodeGenObjC/ivar-layout-64.m52
-rw-r--r--test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m65
-rw-r--r--test/CodeGenObjC/newproperty-nested-synthesis-1.m1
-rw-r--r--test/CodeGenObjC/objc-arc-container-subscripting.m5
-rw-r--r--test/CodeGenObjC/objc2-ivar-assign.m3
-rw-r--r--test/CodeGenObjC/optimized-setter-ios-device.m33
-rw-r--r--test/CodeGenObjC/optimized-setter.m3
-rw-r--r--test/CodeGenObjC/prop-metadata-gnu.m15
-rw-r--r--test/CodeGenObjC/property.m5
-rw-r--r--test/CodeGenObjC/synchronized.m8
-rw-r--r--test/CodeGenObjC/synthesize_ivar-cont-class.m3
-rw-r--r--test/CodeGenObjC/synthesize_ivar.m3
-rw-r--r--test/CodeGenObjC/undefined-protocol.m3
-rw-r--r--test/CodeGenObjC/unoptimized-setter.m32
-rw-r--r--test/CodeGenObjCXX/address-safety-attr.mm2
-rw-r--r--test/CodeGenObjCXX/arc-exceptions.mm10
-rw-r--r--test/CodeGenObjCXX/arc-new-delete.mm5
-rw-r--r--test/CodeGenObjCXX/arc-references.mm2
-rw-r--r--test/CodeGenObjCXX/arc-special-member-functions.mm7
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm6
-rw-r--r--test/CodeGenObjCXX/implementation-in-extern-c.mm17
-rw-r--r--test/CodeGenObjCXX/implicit-copy-assign-operator.mm95
-rw-r--r--test/CodeGenObjCXX/property-objects.mm22
-rw-r--r--test/CodeGenOpenCL/single-precision-constant.cl3
-rw-r--r--test/Coverage/targets.c1
-rw-r--r--test/Driver/B-opt.c22
-rwxr-xr-x[-rw-r--r--]test/Driver/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld (renamed from test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o)0
-rwxr-xr-x[-rw-r--r--]test/Driver/Inputs/B_opt_tree/dir1/ld (renamed from test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o)0
-rwxr-xr-x[-rw-r--r--]test/Driver/Inputs/B_opt_tree/dir2/ld (renamed from test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o)0
-rwxr-xr-x[-rw-r--r--]test/Driver/Inputs/B_opt_tree/dir3/prefix-ld (renamed from test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o)0
-rw-r--r--test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep (renamed from test/PCH/badpch-dir.h.gch/.keep)0
-rw-r--r--test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep (renamed from test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o)0
-rw-r--r--test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep (renamed from test/PCH/badpch-empty.h.gch)0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtend.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtendS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtend.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtendS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/mipsel-linux-android/bin/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/mipsel-linux-android/include/c++/4.4.3/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/mipsel-linux-android/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_dynamic.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_so.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_static.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_android.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_so.o0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/lib32/.keep0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/lib64/.keep0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crt1.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crti.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crt1.o0
-rw-r--r--test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crti.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/lib64/.keep0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crt1.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crti.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crtn.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtend.o0
-rw-r--r--test/Driver/Wp-args.c8
-rw-r--r--test/Driver/altivec.cpp12
-rw-r--r--test/Driver/android-standalone.cpp65
-rw-r--r--test/Driver/apple-kext-i386.cpp55
-rw-r--r--test/Driver/arc.c6
-rw-r--r--test/Driver/arm-darwin-builtin.c2
-rw-r--r--test/Driver/asan-ld.c31
-rw-r--r--test/Driver/asan.c1
-rw-r--r--test/Driver/bindings.c58
-rw-r--r--test/Driver/bitrig.c29
-rw-r--r--test/Driver/clang-translation.c107
-rw-r--r--test/Driver/cpath.c4
-rw-r--r--test/Driver/crash-report.c3
-rw-r--r--test/Driver/darwin-arch-default.c7
-rw-r--r--test/Driver/darwin-asan-nofortify.c6
-rw-r--r--test/Driver/darwin-cc.c4
-rw-r--r--test/Driver/darwin-ld.c6
-rw-r--r--test/Driver/darwin-sdkroot.c22
-rw-r--r--test/Driver/fast-math.c49
-rw-r--r--test/Driver/freebsd-mips-as.c81
-rw-r--r--test/Driver/freebsd.c58
-rw-r--r--test/Driver/fsanitize.c23
-rw-r--r--test/Driver/gcc_forward.c2
-rw-r--r--test/Driver/hello.c18
-rw-r--r--test/Driver/immediate-options.c6
-rw-r--r--test/Driver/ios-simulator-arcruntime.c8
-rw-r--r--test/Driver/le32-unknown-nacl.cpp6
-rw-r--r--test/Driver/linker-opts.c2
-rw-r--r--test/Driver/linux-header-search.cpp4
-rw-r--r--test/Driver/linux-ld.c210
-rw-r--r--test/Driver/mips-as.c27
-rw-r--r--test/Driver/mips-features.c6
-rw-r--r--test/Driver/mips-float.c12
-rw-r--r--test/Driver/no-objc-arr.m1
-rw-r--r--test/Driver/objc++-cpp-output.mm3
-rw-r--r--test/Driver/objc-cpp-output.m3
-rw-r--r--test/Driver/openbsd.c12
-rw-r--r--test/Driver/pic.c162
-rw-r--r--test/Driver/retain-comments-from-system-headers.c9
-rw-r--r--test/Driver/rewrite-legacy-objc.m10
-rw-r--r--test/Driver/rewrite-objc.m11
-rw-r--r--test/Driver/stack-protector.c11
-rw-r--r--test/Driver/std.cpp8
-rw-r--r--test/Driver/tsan.c11
-rw-r--r--test/Driver/ubsan-ld.c10
-rw-r--r--test/Driver/warning-options.cpp5
-rw-r--r--test/Driver/working-directory-and-abs.c1
-rw-r--r--test/Driver/x86_64-nacl-defines.cpp45
-rw-r--r--test/Driver/x86_64-nacl-types.cpp37
-rw-r--r--test/FixIt/fixit-cxx0x.cpp2
-rw-r--r--test/FixIt/fixit-include.c2
-rw-r--r--test/FixIt/fixit-missing-self-in-block.m20
-rw-r--r--test/FixIt/fixit-objc.m2
-rw-r--r--test/FixIt/fixit.c7
-rw-r--r--test/FixIt/fixit.cpp9
-rw-r--r--test/FixIt/format-darwin.m198
-rw-r--r--test/FixIt/no-fixit.cpp6
-rw-r--r--test/FixIt/typo.cpp42
-rw-r--r--test/Frontend/ast-codegen.c4
-rw-r--r--test/Frontend/iframework.c3
-rw-r--r--test/Frontend/macros.c9
-rw-r--r--test/Frontend/unknown-pragmas.c1
-rw-r--r--test/Frontend/verify.c7
-rw-r--r--test/Frontend/verify2.c7
-rw-r--r--test/Frontend/verify3.c41
-rw-r--r--test/Frontend/warning-mapping-1.c1
-rw-r--r--test/Frontend/warning-mapping-4.c1
-rw-r--r--test/Headers/Inputs/include/stdint.h18
-rw-r--r--test/Headers/altivec-header.c12
-rw-r--r--test/Headers/c89.c1
-rw-r--r--test/Headers/int64-type.c1
-rw-r--r--test/Headers/typedef_guards.c1
-rw-r--r--test/Headers/unwind.c19
-rw-r--r--test/Headers/wchar_limits.cpp1
-rw-r--r--test/Headers/wmmintrin.c1
-rw-r--r--test/Index/Inputs/CommentXML/valid-availability-attr-01.xml11
-rw-r--r--test/Index/Inputs/CommentXML/valid-availability-attr-02.xml11
-rw-r--r--test/Index/Inputs/CommentXML/valid-deprecated-attr.xml6
-rw-r--r--test/Index/Inputs/CommentXML/valid-unavailable-attr.xml7
-rw-r--r--test/Index/Inputs/Frameworks/module.map1
-rw-r--r--test/Index/Inputs/retain-comments-from-system-headers.h8
-rw-r--r--test/Index/annotate-comments-availability-attrs.cpp44
-rw-r--r--test/Index/annotate-comments.cpp177
-rw-r--r--test/Index/annotate-deep-statements.cpp95
-rw-r--r--test/Index/annotate-macro-args.m4
-rw-r--r--test/Index/annotate-module.m42
-rw-r--r--test/Index/arc-annotate.m21
-rw-r--r--test/Index/c-index-getCursor-pp.c4
-rw-r--r--test/Index/code-completion-skip-bodies.cpp20
-rw-r--r--test/Index/comment-xml-schema.c5
-rw-r--r--test/Index/complete-cxx-inline-methods.cpp4
-rw-r--r--test/Index/complete-documentation-templates.cpp151
-rw-r--r--test/Index/complete-documentation.cpp4
-rw-r--r--test/Index/complete-exprs.cpp6
-rw-r--r--test/Index/complete-lambdas.mm14
-rw-r--r--test/Index/complete-macros.c5
-rw-r--r--test/Index/complete-method-decls.m16
-rw-r--r--test/Index/complete-objc-message.m12
-rw-r--r--test/Index/complete-preamble.cpp2
-rw-r--r--test/Index/complete-preprocessor.m4
-rw-r--r--test/Index/complete-property-flags.m20
-rw-r--r--test/Index/complete-qualified.cpp8
-rw-r--r--test/Index/cursor-dynamic-call.mm8
-rw-r--r--test/Index/get-cursor-macro-args.h4
-rw-r--r--test/Index/get-cursor-macro-args.m8
-rw-r--r--test/Index/get-cursor.m13
-rw-r--r--test/Index/index-decls.m13
-rw-r--r--test/Index/index-file.cpp6
-rw-r--r--test/Index/index-module.m54
-rw-r--r--test/Index/index-pch-with-module.m31
-rw-r--r--test/Index/index-pch.cpp6
-rw-r--r--test/Index/index-with-working-dir.c5
-rw-r--r--test/Index/overrides.cpp3
-rw-r--r--test/Index/overrides.m4
-rw-r--r--test/Index/overriding-ftemplate-comments.cpp79
-rw-r--r--test/Index/overriding-method-comments.mm124
-rw-r--r--test/Index/preamble-reparse-with-BOM.m6
-rw-r--r--test/Index/rdar12316296-codecompletion.m23
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp2
-rw-r--r--test/Index/retain-comments-from-system-headers.c19
-rw-r--r--test/Index/usrs.m2
-rw-r--r--test/Lexer/clang-keywords.cpp1
-rw-r--r--test/Lexer/digraph.c1
-rw-r--r--test/Lexer/dollar-idents.c8
-rw-r--r--test/Lexer/eof-char.c8
-rw-r--r--test/Lexer/eof-file.c8
-rw-r--r--test/Lexer/eof-string.c8
-rw-r--r--test/Lexer/gnu_keywords.c1
-rw-r--r--test/Lexer/has_feature_address_sanitizer.cpp2
-rw-r--r--test/Lexer/long-long.cpp24
-rw-r--r--test/Lexer/msdos-cpm-eof.c1
-rw-r--r--test/Lexer/newline-eof-c++11.cpp1
-rw-r--r--test/Lexer/numeric-literal-trash.c2
-rw-r--r--test/Lexer/pragma-mark.c1
-rw-r--r--test/Lexer/rdr-6096838.c1
-rw-r--r--test/Lexer/string-literal-errors.cpp25
-rw-r--r--test/Misc/ast-dump-stmt.c35
-rw-r--r--test/Misc/ast-dump-stmt.m36
-rw-r--r--test/Misc/caret-diags-macros.c79
-rw-r--r--test/Misc/diag-template-diffing-color.cpp53
-rw-r--r--test/Misc/diag-template-diffing.cpp366
-rw-r--r--test/Misc/predefines.c1
-rw-r--r--test/Misc/unnecessary-elipses.cpp15
-rw-r--r--test/Misc/unprintable.c41
-rw-r--r--test/Misc/warning-flags-enabled.c16
-rw-r--r--test/Misc/warning-flags.c15
-rw-r--r--test/Misc/wrong-encoding.c33
-rw-r--r--test/Misc/wrong-encoding2.c8
-rw-r--r--test/Modules/Inputs/Modified/A.h1
-rw-r--r--test/Modules/Inputs/Modified/B.h2
-rw-r--r--test/Modules/Inputs/Modified/module.map2
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Module.h2
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/module.map5
-rw-r--r--test/Modules/Inputs/NotAModule.framework/Headers/NotAModule.h2
-rw-r--r--test/Modules/Inputs/lookup_right.hpp1
-rw-r--r--test/Modules/Inputs/macros.h9
-rw-r--r--test/Modules/Inputs/macros_left.h14
-rw-r--r--test/Modules/Inputs/macros_other.h1
-rw-r--r--test/Modules/Inputs/macros_right.h17
-rw-r--r--test/Modules/Inputs/macros_right_undef.h1
-rw-r--r--test/Modules/Inputs/macros_top.h16
-rw-r--r--test/Modules/Inputs/module.map30
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/1.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/decltype.h2
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom.h8
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h8
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h9
-rw-r--r--test/Modules/Inputs/redecl-merge-top.h4
-rw-r--r--test/Modules/Inputs/templates-left.h29
-rw-r--r--test/Modules/Inputs/templates-right.h27
-rw-r--r--test/Modules/Inputs/templates-top.h17
-rw-r--r--test/Modules/compiler_builtins.m2
-rw-r--r--test/Modules/direct-module-import.m7
-rw-r--r--test/Modules/header-import.m1
-rw-r--r--test/Modules/import-decl.cpp2
-rw-r--r--test/Modules/inferred-frameworks.m8
-rw-r--r--test/Modules/inferred-submodules.m1
-rw-r--r--test/Modules/macros.c107
-rw-r--r--test/Modules/modify-module.m23
-rw-r--r--test/Modules/module-private.cpp7
-rw-r--r--test/Modules/normal-module-map.cpp10
-rw-r--r--test/Modules/on-demand-macros.m1
-rw-r--r--test/Modules/redecl-merge.m20
-rw-r--r--test/Modules/redeclarations.m1
-rw-r--r--test/Modules/submodules.m1
-rw-r--r--test/Modules/templates.mm36
-rw-r--r--test/PCH/Inputs/badpch-dir.h.gch/.keep0
-rw-r--r--test/PCH/Inputs/badpch-empty.h.gch0
-rw-r--r--test/PCH/Inputs/case-insensitive-include.h5
-rw-r--r--test/PCH/Inputs/chain-macro-override1.h4
-rw-r--r--test/PCH/Inputs/chain-macro-override2.h3
-rw-r--r--test/PCH/Inputs/cxx11-statement-attributes.h14
-rw-r--r--test/PCH/__va_list_tag.c2
-rw-r--r--test/PCH/asm.c1
-rw-r--r--test/PCH/badpch.c6
-rw-r--r--test/PCH/builtins.c2
-rw-r--r--test/PCH/case-insensitive-include.c29
-rw-r--r--test/PCH/chain-categories.m2
-rw-r--r--test/PCH/chain-class-extension.m2
-rw-r--r--test/PCH/chain-cxx.cpp2
-rw-r--r--test/PCH/chain-decls.c2
-rw-r--r--test/PCH/chain-macro-override.c2
-rw-r--r--test/PCH/chain-macro.c1
-rw-r--r--test/PCH/chain-remap-types.m1
-rw-r--r--test/PCH/cmdline-include.c1
-rw-r--r--test/PCH/cxx-exprs.cpp2
-rw-r--r--test/PCH/cxx-for-range.h5
-rw-r--r--test/PCH/cxx-friends.cpp2
-rw-r--r--test/PCH/cxx-functions.cpp2
-rw-r--r--test/PCH/cxx-implicit-moves.cpp1
-rw-r--r--test/PCH/cxx-method.cpp1
-rw-r--r--test/PCH/cxx-ms-function-specialization-class-scope.cpp1
-rw-r--r--test/PCH/cxx-namespaces.cpp2
-rw-r--r--test/PCH/cxx-templates.cpp21
-rw-r--r--test/PCH/cxx-templates.h5
-rw-r--r--test/PCH/cxx-traits.cpp2
-rw-r--r--test/PCH/cxx-typeid.cpp2
-rw-r--r--test/PCH/cxx-variadic-templates.cpp6
-rw-r--r--test/PCH/cxx-variadic-templates.h7
-rw-r--r--test/PCH/cxx11-constexpr.cpp9
-rw-r--r--test/PCH/cxx11-exception-spec.cpp1
-rw-r--r--test/PCH/cxx11-statement-attributes.cpp12
-rw-r--r--test/PCH/cxx_exprs.cpp8
-rw-r--r--test/PCH/cxx_exprs.h5
-rw-r--r--test/PCH/empty-with-headers.c2
-rw-r--r--test/PCH/enum.c2
-rw-r--r--test/PCH/exprs.c6
-rw-r--r--test/PCH/field-designator.c35
-rw-r--r--test/PCH/friend-template.cpp46
-rw-r--r--test/PCH/fuzzy-pch.c16
-rw-r--r--test/PCH/missing-file.cpp17
-rw-r--r--test/PCH/objc_container.m6
-rw-r--r--test/PCH/objc_import.m2
-rw-r--r--test/PCH/objc_literals.m10
-rw-r--r--test/PCH/objc_literals.mm10
-rw-r--r--test/PCH/objc_methods.m2
-rw-r--r--test/PCH/objc_property.m2
-rw-r--r--test/PCH/pch-dir.c28
-rw-r--r--test/PCH/pch-dir.h5
-rw-r--r--test/PCH/pending-ids.m2
-rw-r--r--test/PCH/pragma-diag-section.cpp19
-rw-r--r--test/PCH/pragma-diag.c2
-rw-r--r--test/PCH/rdar8852495.c2
-rw-r--r--test/PCH/reinclude.cpp2
-rw-r--r--test/PCH/single-token-macro.c2
-rw-r--r--test/PCH/target-options.c5
-rw-r--r--test/PCH/target-options.h2
-rw-r--r--test/Parser/MicrosoftExtensions.cpp56
-rw-r--r--test/Parser/block-block-storageclass.c1
-rw-r--r--test/Parser/block-pointer-decl.c1
-rw-r--r--test/Parser/builtin_classify_type.c2
-rw-r--r--test/Parser/check-objc2-syntax-1.m1
-rw-r--r--test/Parser/colon-colon-parentheses.cpp22
-rw-r--r--test/Parser/compound_literal.c1
-rw-r--r--test/Parser/cxx-ambig-decl-expr.cpp3
-rw-r--r--test/Parser/cxx-attributes.cpp1
-rw-r--r--test/Parser/cxx-casting.cpp12
-rw-r--r--test/Parser/cxx-class.cpp14
-rw-r--r--test/Parser/cxx-decl.cpp5
-rw-r--r--test/Parser/cxx-extern-c-array.cpp1
-rw-r--r--test/Parser/cxx-stmt.cpp8
-rw-r--r--test/Parser/cxx-template-argument.cpp17
-rw-r--r--test/Parser/cxx0x-attributes.cpp26
-rw-r--r--test/Parser/cxx0x-condition.cpp9
-rw-r--r--test/Parser/cxx0x-decl.cpp14
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp3
-rw-r--r--test/Parser/cxx0x-override-control-keywords.cpp1
-rw-r--r--test/Parser/cxx11-brace-initializers.cpp16
-rw-r--r--test/Parser/cxx11-stmt-attributes.cpp77
-rw-r--r--test/Parser/cxx11-user-defined-literals.cpp3
-rw-r--r--test/Parser/empty-translation-unit.c2
-rw-r--r--test/Parser/encode.m1
-rw-r--r--test/Parser/enhanced-proto-1.m1
-rw-r--r--test/Parser/if-scope-c90.c1
-rw-r--r--test/Parser/knr_parameter_attributes.c1
-rw-r--r--test/Parser/ms-inline-asm.c8
-rw-r--r--test/Parser/namelookup-bug-1.c1
-rw-r--r--test/Parser/namelookup-bug-2.c1
-rw-r--r--test/Parser/namespaces.cpp4
-rw-r--r--test/Parser/objcxx11-attributes.mm18
-rw-r--r--test/Parser/opencl-kernel.cl1
-rw-r--r--test/Parser/parmvardecl_conversion.c1
-rw-r--r--test/Parser/pragma-fp-contract.c12
-rw-r--r--test/Parser/pragma-options.cpp6
-rw-r--r--test/Parser/recovery.cpp7
-rw-r--r--test/Parser/recursion-limits.cpp1
-rw-r--r--test/Parser/selector-1.m1
-rw-r--r--test/Parser/statements.c15
-rw-r--r--test/Parser/top-level-semi-cxx0x.cpp1
-rw-r--r--test/Parser/types.c1
-rw-r--r--test/Preprocessor/comment_save_if.c1
-rw-r--r--test/Preprocessor/cxx_true.cpp2
-rw-r--r--test/Preprocessor/expr_define_expansion.c1
-rw-r--r--test/Preprocessor/expr_multichar.c1
-rw-r--r--test/Preprocessor/has_include.c32
-rw-r--r--test/Preprocessor/import_self.c2
-rw-r--r--test/Preprocessor/init.c293
-rw-r--r--test/Preprocessor/macro_arg_directive.c7
-rw-r--r--test/Preprocessor/macro_fn_comma_swallow2.c64
-rw-r--r--test/Preprocessor/macro_paste_identifier_error.c1
-rw-r--r--test/Preprocessor/microsoft-ext.c24
-rw-r--r--test/Preprocessor/objc-pp.m1
-rw-r--r--test/Preprocessor/optimize.c3
-rw-r--r--test/Preprocessor/pr13851.c11
-rw-r--r--test/Preprocessor/pragma-pushpop-macro.c19
-rw-r--r--test/Preprocessor/pragma_sysheader.c3
-rw-r--r--test/Preprocessor/predefined-arch-macros.c2
-rw-r--r--test/Preprocessor/user_defined_system_framework.c3
-rw-r--r--test/Rewriter/no-integrated-preprocessing-64bit.m26
-rw-r--r--test/Rewriter/no-integrated-preprocessing.m26
-rw-r--r--test/Rewriter/objc-modern-StretAPI-2.mm30
-rw-r--r--test/Rewriter/objc-modern-boxing.mm2
-rw-r--r--test/Rewriter/objc-modern-numeric-literal.mm2
-rw-r--r--test/Sema/MicrosoftCompatibility-x64.c8
-rw-r--r--test/Sema/MicrosoftCompatibility-x86.c6
-rw-r--r--test/Sema/MicrosoftCompatibility.c2
-rw-r--r--test/Sema/PR2727.c1
-rw-r--r--test/Sema/PR2728.c1
-rw-r--r--test/Sema/PR2923.c1
-rw-r--r--test/Sema/address-constant.c1
-rw-r--r--test/Sema/align-arm-apcs.c1
-rw-r--r--test/Sema/align-x86-64.c1
-rw-r--r--test/Sema/align-x86.c1
-rw-r--r--test/Sema/arg-scope-c99.c1
-rw-r--r--test/Sema/arg-scope.c1
-rw-r--r--test/Sema/arm-layout.c1
-rw-r--r--test/Sema/array-init.c2
-rw-r--r--test/Sema/asm.c2
-rw-r--r--test/Sema/assign-null.c1
-rw-r--r--test/Sema/atomic-ops.c7
-rw-r--r--test/Sema/attr-availability-macosx.c6
-rw-r--r--test/Sema/attr-availability.c6
-rw-r--r--test/Sema/attr-minsize.c5
-rw-r--r--test/Sema/attr-used.c2
-rw-r--r--test/Sema/bitfield-layout.c1
-rw-r--r--test/Sema/bitfield-promote.c1
-rw-r--r--test/Sema/block-return.c2
-rw-r--r--test/Sema/block-storageclass.c1
-rw-r--r--test/Sema/builtin_objc_msgSend.c1
-rw-r--r--test/Sema/builtins-arm.c20
-rw-r--r--test/Sema/builtins-decl.c1
-rw-r--r--test/Sema/builtins.c16
-rw-r--r--test/Sema/c89-2.c5
-rw-r--r--test/Sema/c89.c6
-rw-r--r--test/Sema/callingconv.c8
-rw-r--r--test/Sema/cast-to-union.c6
-rw-r--r--test/Sema/cast.c15
-rw-r--r--test/Sema/check-increment.c1
-rw-r--r--test/Sema/compare.c32
-rw-r--r--test/Sema/complex-promotion.c1
-rw-r--r--test/Sema/compound-literal.c19
-rw-r--r--test/Sema/const-eval-64.c1
-rw-r--r--test/Sema/const-ptr-int-ptr-cast.c1
-rw-r--r--test/Sema/constant-builtins-2.c3
-rw-r--r--test/Sema/constant-builtins.c4
-rw-r--r--test/Sema/darwin-align-cast.c1
-rw-r--r--test/Sema/enum-packed.c1
-rw-r--r--test/Sema/expr-comma-c99.c1
-rw-r--r--test/Sema/expr-comma.c1
-rw-r--r--test/Sema/exprs.c2
-rw-r--r--test/Sema/format-string-percentm.c1
-rw-r--r--test/Sema/format-strings-darwin.c64
-rw-r--r--test/Sema/format-strings-gnu.c55
-rw-r--r--test/Sema/format-strings-non-iso.c16
-rw-r--r--test/Sema/format-strings-scanf.c16
-rw-r--r--test/Sema/format-strings.c12
-rw-r--r--test/Sema/function-redecl.c4
-rw-r--r--test/Sema/heinous-extensions-on.c4
-rw-r--r--test/Sema/i-c-e.c2
-rw-r--r--test/Sema/implicit-builtin-freestanding.c1
-rw-r--r--test/Sema/init-struct-qualified.c1
-rw-r--r--test/Sema/init-vector.c1
-rw-r--r--test/Sema/int-arith-convert.c1
-rw-r--r--test/Sema/invalid-decl.c9
-rw-r--r--test/Sema/knr-variadic-def.c1
-rw-r--r--test/Sema/many-logical-ops.c1
-rw-r--r--test/Sema/member-reference.c1
-rw-r--r--test/Sema/mms-bitfields.c13
-rw-r--r--test/Sema/ms-inline-asm.c35
-rw-r--r--test/Sema/ms_wide_predefined_expr.cpp1
-rw-r--r--test/Sema/no-format-y2k-turnsoff-format.c2
-rw-r--r--test/Sema/outof-range-constant-compare.c149
-rw-r--r--test/Sema/overloaded-func-transparent-union.c1
-rw-r--r--test/Sema/parentheses.c6
-rw-r--r--test/Sema/parentheses.cpp12
-rw-r--r--test/Sema/pragma-align-mac68k.c13
-rw-r--r--test/Sema/pragma-align-packed.c1
-rw-r--r--test/Sema/pragma-ms_struct.c6
-rw-r--r--test/Sema/pragma-pack-2.c1
-rw-r--r--test/Sema/pragma-pack-3.c1
-rw-r--r--test/Sema/pragma-pack-4.c1
-rw-r--r--test/Sema/pragma-pack-5.c1
-rw-r--r--test/Sema/pragma-pack-6.c1
-rw-r--r--test/Sema/pragma-pack-and-options-align.c11
-rw-r--r--test/Sema/private-extern.c2
-rw-r--r--test/Sema/return-silent.c1
-rw-r--r--test/Sema/short-enums.c1
-rw-r--r--test/Sema/stdcall-fastcall-x64.c20
-rw-r--r--test/Sema/stdcall-fastcall.c1
-rw-r--r--test/Sema/struct-cast.c1
-rw-r--r--test/Sema/struct-packed-align.c1
-rw-r--r--test/Sema/surpress-deprecated.c1
-rw-r--r--test/Sema/template-specialization.cpp21
-rw-r--r--test/Sema/tentative-decls.c3
-rw-r--r--test/Sema/thread-specifier.c9
-rw-r--r--test/Sema/tls.c3
-rw-r--r--test/Sema/transparent-union-pointer.c1
-rw-r--r--test/Sema/typedef-prototype.c1
-rw-r--r--test/Sema/types.c2
-rw-r--r--test/Sema/uninit-variables.c23
-rw-r--r--test/Sema/unnamed-bitfield-init.c1
-rw-r--r--test/Sema/unused-expr.c11
-rw-r--r--test/Sema/va_arg_x86_64.c1
-rw-r--r--test/Sema/variadic-block.c1
-rw-r--r--test/Sema/vector-cast.c12
-rw-r--r--test/Sema/vfprintf-valid-redecl.c1
-rw-r--r--test/Sema/warn-bad-function-cast.c47
-rw-r--r--test/Sema/warn-documentation-fixits.cpp44
-rw-r--r--test/Sema/warn-documentation.cpp136
-rw-r--r--test/Sema/warn-documentation.m8
-rw-r--r--test/Sema/warn-gnu-designators.c1
-rw-r--r--test/Sema/warn-missing-variable-declarations.c18
-rw-r--r--test/Sema/warn-type-safety-mpi-hdf5.c4
-rw-r--r--test/Sema/warn-type-safety.c8
-rw-r--r--test/Sema/warn-type-safety.cpp4
-rw-r--r--test/Sema/warn-unreachable.c9
-rw-r--r--test/Sema/warn-unused-function.c14
-rw-r--r--test/Sema/wchar.c2
-rw-r--r--test/Sema/weak-import-on-enum.c1
-rw-r--r--test/SemaCXX/2008-01-11-BadWarning.cpp1
-rw-r--r--test/SemaCXX/MicrosoftCompatibilityNoExceptions.cpp1
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp7
-rw-r--r--test/SemaCXX/PR10447.cpp1
-rw-r--r--test/SemaCXX/PR5086-ambig-resolution-enum.cpp1
-rw-r--r--test/SemaCXX/PR6562.cpp1
-rw-r--r--test/SemaCXX/PR9884.cpp1
-rw-r--r--test/SemaCXX/PR9902.cpp1
-rw-r--r--test/SemaCXX/PR9908.cpp1
-rw-r--r--test/SemaCXX/__try.cpp1
-rw-r--r--test/SemaCXX/ambiguous-conversion-show-overload.cpp21
-rw-r--r--test/SemaCXX/anonymous-union-cxx11.cpp1
-rw-r--r--test/SemaCXX/ast-print.cpp83
-rw-r--r--test/SemaCXX/attr-format.cpp8
-rw-r--r--test/SemaCXX/attr-nodebug.cpp7
-rw-r--r--test/SemaCXX/attr-noreturn.cpp26
-rw-r--r--test/SemaCXX/attr-unused.cpp9
-rw-r--r--test/SemaCXX/blocks-1.cpp1
-rw-r--r--test/SemaCXX/blocks.cpp1
-rw-r--r--test/SemaCXX/borland-extensions.cpp1
-rw-r--r--test/SemaCXX/builtin-exception-spec.cpp1
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload.cpp1
-rw-r--r--test/SemaCXX/builtin_objc_msgSend.cpp1
-rw-r--r--test/SemaCXX/builtins-arm.cpp6
-rw-r--r--test/SemaCXX/builtins-va_arg.cpp52
-rw-r--r--test/SemaCXX/builtins.cpp13
-rw-r--r--test/SemaCXX/cast-conversion.cpp22
-rw-r--r--test/SemaCXX/cast-explicit-ctor.cpp1
-rw-r--r--test/SemaCXX/class-layout.cpp1
-rw-r--r--test/SemaCXX/class.cpp2
-rw-r--r--test/SemaCXX/comma.cpp1
-rw-r--r--test/SemaCXX/compare.cpp32
-rw-r--r--test/SemaCXX/complex-init-list.cpp1
-rw-r--r--test/SemaCXX/conditional-expr.cpp13
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp83
-rw-r--r--test/SemaCXX/constant-expression.cpp2
-rw-r--r--test/SemaCXX/constexpr-turing.cpp1
-rw-r--r--test/SemaCXX/constructor-initializer.cpp16
-rw-r--r--test/SemaCXX/crashes.cpp35
-rw-r--r--test/SemaCXX/cstyle-cast.cpp1
-rw-r--r--test/SemaCXX/cxx0x-delegating-ctors.cpp4
-rw-r--r--test/SemaCXX/cxx0x-initializer-constructor.cpp16
-rw-r--r--test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp4
-rw-r--r--test/SemaCXX/cxx11-crashes.cpp76
-rw-r--r--test/SemaCXX/cxx98-compat-pedantic.cpp6
-rw-r--r--test/SemaCXX/cxx98-compat.cpp13
-rw-r--r--test/SemaCXX/dcl_ambig_res.cpp3
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp2
-rw-r--r--test/SemaCXX/decltype-98.cpp1
-rw-r--r--test/SemaCXX/decltype-overloaded-functions.cpp25
-rw-r--r--test/SemaCXX/decltype-pr4444.cpp1
-rw-r--r--test/SemaCXX/decltype-pr4448.cpp1
-rw-r--r--test/SemaCXX/decltype-this.cpp1
-rw-r--r--test/SemaCXX/decltype.cpp15
-rw-r--r--test/SemaCXX/default-argument-temporaries.cpp1
-rw-r--r--test/SemaCXX/defaulted-ctor-loop.cpp2
-rw-r--r--test/SemaCXX/do-while-scope.cpp1
-rw-r--r--test/SemaCXX/empty-class-layout.cpp1
-rw-r--r--test/SemaCXX/exception-spec-no-exceptions.cpp1
-rw-r--r--test/SemaCXX/explicit.cpp22
-rw-r--r--test/SemaCXX/for-range-dereference.cpp89
-rw-r--r--test/SemaCXX/for-range-examples.cpp2
-rw-r--r--test/SemaCXX/for-range-no-std.cpp4
-rw-r--r--test/SemaCXX/format-strings.cpp60
-rw-r--r--test/SemaCXX/friend-out-of-line.cpp1
-rw-r--r--test/SemaCXX/function-type-qual.cpp3
-rw-r--r--test/SemaCXX/functional-cast.cpp1
-rw-r--r--test/SemaCXX/gnu-case-ranges.cpp1
-rw-r--r--test/SemaCXX/goto2.cpp1
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp11
-rw-r--r--test/SemaCXX/indirect-goto.cpp1
-rw-r--r--test/SemaCXX/issue547.cpp1
-rw-r--r--test/SemaCXX/lambda-expressions.cpp29
-rw-r--r--test/SemaCXX/libstdcxx_atomic_ns_hack.cpp35
-rw-r--r--test/SemaCXX/libstdcxx_common_type_hack.cpp33
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp12
-rw-r--r--test/SemaCXX/local-classes.cpp1
-rw-r--r--test/SemaCXX/lookup-member.cpp1
-rw-r--r--test/SemaCXX/member-expr-anonymous-union.cpp1
-rw-r--r--test/SemaCXX/member-expr-static.cpp1
-rw-r--r--test/SemaCXX/member-pointer-size.cpp1
-rw-r--r--test/SemaCXX/missing-header.cpp2
-rw-r--r--test/SemaCXX/ms-exception-spec.cpp1
-rw-r--r--test/SemaCXX/ms-interface.cpp77
-rw-r--r--test/SemaCXX/nested-name-spec.cpp11
-rw-r--r--test/SemaCXX/new-delete-0x.cpp9
-rw-r--r--test/SemaCXX/new-delete-predefined-decl-2.cpp1
-rw-r--r--test/SemaCXX/new-delete-predefined-decl.cpp1
-rw-r--r--test/SemaCXX/no-warn-composite-pointer-type.cpp9
-rw-r--r--test/SemaCXX/no-wchar.cpp9
-rw-r--r--test/SemaCXX/null_in_arithmetic_ops.cpp2
-rw-r--r--test/SemaCXX/nullptr-98.cpp1
-rw-r--r--test/SemaCXX/overload-value-dep-arg.cpp1
-rw-r--r--test/SemaCXX/overloaded-builtin-operators-0x.cpp1
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp2
-rw-r--r--test/SemaCXX/overloaded-operator-decl.cpp10
-rw-r--r--test/SemaCXX/pragma-pack.cpp1
-rw-r--r--test/SemaCXX/pragma-unused.cpp1
-rw-r--r--test/SemaCXX/pragma-visibility.cpp7
-rw-r--r--test/SemaCXX/prefetch-enum.cpp1
-rw-r--r--test/SemaCXX/primary-base.cpp1
-rw-r--r--test/SemaCXX/ptrtomember-overload-resolution.cpp1
-rw-r--r--test/SemaCXX/qualified-member-enum.cpp1
-rw-r--r--test/SemaCXX/references.cpp2
-rw-r--r--test/SemaCXX/scope-check.cpp103
-rw-r--r--test/SemaCXX/short-wchar-sign.cpp1
-rw-r--r--test/SemaCXX/static-initializers.cpp1
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp3
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough-macro.cpp139
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough-per-method.cpp2
-rw-r--r--test/SemaCXX/tag-ambig.cpp1
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp16
-rw-r--r--test/SemaCXX/trivial-constructor.cpp1
-rw-r--r--test/SemaCXX/trivial-destructor.cpp1
-rw-r--r--test/SemaCXX/typo-correction.cpp12
-rw-r--r--test/SemaCXX/uninitialized.cpp151
-rw-r--r--test/SemaCXX/unknown-type-name.cpp23
-rw-r--r--test/SemaCXX/unused-functions.cpp1
-rw-r--r--test/SemaCXX/unused.cpp27
-rw-r--r--test/SemaCXX/using-decl-pr4441.cpp1
-rw-r--r--test/SemaCXX/using-decl-pr4450.cpp1
-rw-r--r--test/SemaCXX/value-dependent-exprs.cpp1
-rw-r--r--test/SemaCXX/vararg-default-arg.cpp1
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp18
-rw-r--r--test/SemaCXX/vector.cpp11
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp6
-rw-r--r--test/SemaCXX/warn-c++11-extensions.cpp7
-rw-r--r--test/SemaCXX/warn-enum-compare.cpp4
-rw-r--r--test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp24
-rw-r--r--test/SemaCXX/warn-missing-variable-declarations.cpp43
-rw-r--r--test/SemaCXX/warn-new-overaligned-2.cpp1
-rw-r--r--test/SemaCXX/warn-overloaded-virtual.cpp56
-rw-r--r--test/SemaCXX/warn-self-comparisons.cpp1
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp669
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp49
-rw-r--r--test/SemaCXX/warn-unique-enum.cpp27
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp16
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp17
-rw-r--r--test/SemaCXX/warn-using-namespace-in-header.cpp96
-rw-r--r--test/SemaCXX/warn-using-namespace-in-header.h50
-rw-r--r--test/SemaCXX/zero-length-arrays.cpp1
-rw-r--r--test/SemaObjC/ClassPropertyNotObject.m1
-rw-r--r--test/SemaObjC/ContClassPropertyLookup.m1
-rw-r--r--test/SemaObjC/arc-decls.m2
-rw-r--r--test/SemaObjC/arc-objc-lifetime.m31
-rw-r--r--test/SemaObjC/arc-property-decl-attrs.m6
-rw-r--r--test/SemaObjC/arc-property-lifetime.m22
-rw-r--r--test/SemaObjC/arc-property.m12
-rw-r--r--test/SemaObjC/arc-readonly-property-ivar-1.m1
-rw-r--r--test/SemaObjC/arc-readonly-property-ivar.m1
-rw-r--r--test/SemaObjC/arc-repeated-weak.mm386
-rw-r--r--test/SemaObjC/arc-setter-property-match.m1
-rw-r--r--test/SemaObjC/arc-system-header.m2
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m2
-rw-r--r--test/SemaObjC/arc-unsafe_unretained.m1
-rw-r--r--test/SemaObjC/attr-availability.m8
-rw-r--r--test/SemaObjC/attr-cleanup.m1
-rw-r--r--test/SemaObjC/attr-deprecated.m3
-rw-r--r--test/SemaObjC/block-as-object.m1
-rw-r--r--test/SemaObjC/block-ivar.m1
-rw-r--r--test/SemaObjC/block-return.m1
-rw-r--r--test/SemaObjC/builtin_objc_assign_ivar.m1
-rw-r--r--test/SemaObjC/builtin_objc_msgSend.m1
-rw-r--r--test/SemaObjC/category-method-lookup-2.m1
-rw-r--r--test/SemaObjC/category-method-lookup.m1
-rw-r--r--test/SemaObjC/class-getter-using-dotsyntax.m1
-rw-r--r--test/SemaObjC/class-property-access.m1
-rw-r--r--test/SemaObjC/class-protocol.m1
-rw-r--r--test/SemaObjC/comptypes-2.m1
-rw-r--r--test/SemaObjC/comptypes-8.m1
-rw-r--r--test/SemaObjC/conditional-expr-5.m1
-rw-r--r--test/SemaObjC/conditional-expr-6.m1
-rw-r--r--test/SemaObjC/conditional-expr-7.m1
-rw-r--r--test/SemaObjC/conditional-expr-8.m1
-rw-r--r--test/SemaObjC/conflict-nonfragile-abi2.m1
-rw-r--r--test/SemaObjC/continuation-class-err.m4
-rw-r--r--test/SemaObjC/crash-on-objc-bool-literal.m12
-rw-r--r--test/SemaObjC/default-synthesize-2.m4
-rw-r--r--test/SemaObjC/delay-parsing-cfunctions.m1
-rw-r--r--test/SemaObjC/direct-synthesized-ivar-access.m1
-rw-r--r--test/SemaObjC/enhanced-proto-2.m1
-rw-r--r--test/SemaObjC/enum-fixed-type.m1
-rw-r--r--test/SemaObjC/error-property-gc-attr.m8
-rw-r--r--test/SemaObjC/getter-setter-defined-in-category-of-parent.m1
-rw-r--r--test/SemaObjC/iboutletcollection-attr.m4
-rw-r--r--test/SemaObjC/id_builtin.m1
-rw-r--r--test/SemaObjC/idiomatic-parentheses.m11
-rw-r--r--test/SemaObjC/ignore-qualifier-on-qualified-id.m1
-rw-r--r--test/SemaObjC/ignore-weakimport-method.m1
-rw-r--r--test/SemaObjC/interface-layout-2.m1
-rw-r--r--test/SemaObjC/interface-layout.m1
-rw-r--r--test/SemaObjC/interface-scope-2.m1
-rw-r--r--test/SemaObjC/interface-scope.m1
-rw-r--r--test/SemaObjC/ivar-access-package.m1
-rw-r--r--test/SemaObjC/ivar-in-class-extension-error.m4
-rw-r--r--test/SemaObjC/ivar-in-class-extension.m2
-rw-r--r--test/SemaObjC/ivar-sem-check-2.m4
-rw-r--r--test/SemaObjC/method-attributes.m29
-rw-r--r--test/SemaObjC/method-conflict-1.m1
-rw-r--r--test/SemaObjC/method-in-class-extension-impl.m1
-rw-r--r--test/SemaObjC/method-lookup-2.m1
-rw-r--r--test/SemaObjC/method-lookup-4.m1
-rw-r--r--test/SemaObjC/method-typecheck-1.m15
-rw-r--r--test/SemaObjC/nested-typedef-decl.m1
-rw-r--r--test/SemaObjC/no-gc-weak-test.m1
-rw-r--r--test/SemaObjC/no-ivar-access-control.m1
-rw-r--r--test/SemaObjC/no-ivar-in-interface-block.m6
-rw-r--r--test/SemaObjC/no-warn-qual-mismatch.m1
-rw-r--r--test/SemaObjC/no-warn-synth-protocol-meth.m1
-rw-r--r--test/SemaObjC/no-warn-unimpl-method.m1
-rw-r--r--test/SemaObjC/no-warning-unavail-unimp.m1
-rw-r--r--test/SemaObjC/nonarc-weak.m16
-rw-r--r--test/SemaObjC/nonnull.m1
-rw-r--r--test/SemaObjC/nowarn-superclass-method-mismatch.m1
-rw-r--r--test/SemaObjC/nsobject-attribute-1.m1
-rw-r--r--test/SemaObjC/nsobject-attribute.m11
-rw-r--r--test/SemaObjC/objc-buffered-methods.m1
-rw-r--r--test/SemaObjC/objc-literal-comparison.m4
-rw-r--r--test/SemaObjC/objc-qualified-property-lookup.m1
-rw-r--r--test/SemaObjC/overriding-property-in-class-extension.m27
-rw-r--r--test/SemaObjC/pedantic-dynamic-test.m1
-rw-r--r--test/SemaObjC/pragma-pack.m1
-rw-r--r--test/SemaObjC/property-11.m1
-rw-r--r--test/SemaObjC/property-13.m1
-rw-r--r--test/SemaObjC/property-2.m1
-rw-r--r--test/SemaObjC/property-6.m1
-rw-r--r--test/SemaObjC/property-7.m1
-rw-r--r--test/SemaObjC/property-8.m1
-rw-r--r--test/SemaObjC/property-9-impl-method.m1
-rw-r--r--test/SemaObjC/property-and-class-extension.m2
-rw-r--r--test/SemaObjC/property-and-ivar-use.m1
-rw-r--r--test/SemaObjC/property-deprecated-warning.m64
-rw-r--r--test/SemaObjC/property-dot-receiver.m1
-rw-r--r--test/SemaObjC/property-impl-misuse.m2
-rw-r--r--test/SemaObjC/property-in-class-extension-1.m59
-rw-r--r--test/SemaObjC/property-ivar-mismatch.m8
-rw-r--r--test/SemaObjC/property-method-lookup-impl.m1
-rw-r--r--test/SemaObjC/property-nonfragile-abi.m1
-rw-r--r--test/SemaObjC/property-noprotocol-warning.m1
-rw-r--r--test/SemaObjC/property-redundant-decl-accessor.m1
-rw-r--r--test/SemaObjC/property-weak.m1
-rw-r--r--test/SemaObjC/property.m4
-rw-r--r--test/SemaObjC/props-on-prots.m1
-rw-r--r--test/SemaObjC/protocol-expr-1.m1
-rw-r--r--test/SemaObjC/protocol-implementation-inherited.m1
-rw-r--r--test/SemaObjC/protocol-lookup-2.m1
-rw-r--r--test/SemaObjC/protocol-lookup.m1
-rw-r--r--test/SemaObjC/protocol-qualified-class-unsupported.m1
-rw-r--r--test/SemaObjC/rdar6248119.m1
-rw-r--r--test/SemaObjC/restrict-id-type.m1
-rw-r--r--test/SemaObjC/selector-1.m1
-rw-r--r--test/SemaObjC/selector-2.m1
-rw-r--r--test/SemaObjC/self-declared-in-block.m1
-rw-r--r--test/SemaObjC/self-in-function.m1
-rw-r--r--test/SemaObjC/setter-dotsyntax.m1
-rw-r--r--test/SemaObjC/super-cat-prot.m1
-rw-r--r--test/SemaObjC/super-dealloc-attribute.m87
-rw-r--r--test/SemaObjC/super-property-message-expr.m1
-rw-r--r--test/SemaObjC/super-property-notation.m1
-rw-r--r--test/SemaObjC/synth-provisional-ivars-1.m1
-rw-r--r--test/SemaObjC/synthesize-setter-contclass.m1
-rw-r--r--test/SemaObjC/transparent-union.m1
-rw-r--r--test/SemaObjC/ucn-objc-string.m1
-rw-r--r--test/SemaObjC/uninit-variables.m29
-rw-r--r--test/SemaObjC/unused.m27
-rw-r--r--test/SemaObjC/va-method-1.m1
-rw-r--r--test/SemaObjC/warn-direct-ivar-access.m2
-rw-r--r--test/SemaObjC/warn-implicit-self-in-block.m18
-rw-r--r--test/SemaObjC/warn-isa-ref.m2
-rw-r--r--test/SemaObjC/warn-retain-cycle.m63
-rw-r--r--test/SemaObjC/warning-missing-selector-name.m32
-rw-r--r--test/SemaObjC/weak-property.m2
-rw-r--r--test/SemaObjC/weak-receiver-warn.m48
-rw-r--r--test/SemaObjC/writable-property-in-superclass.m1
-rw-r--r--test/SemaObjCXX/abstract-class-type-ivar.mm2
-rw-r--r--test/SemaObjCXX/arc-0x.mm12
-rw-r--r--test/SemaObjCXX/arc-bool-conversion.mm1
-rw-r--r--test/SemaObjCXX/arc-libstdcxx.mm1
-rw-r--r--test/SemaObjCXX/arc-memfunc.mm1
-rw-r--r--test/SemaObjCXX/arc-non-pod.mm116
-rw-r--r--test/SemaObjCXX/arc-objc-lifetime.mm68
-rw-r--r--test/SemaObjCXX/arc-object-init-destroy.mm52
-rw-r--r--test/SemaObjCXX/arc-type-traits.mm1
-rw-r--r--test/SemaObjCXX/argument-dependent-lookup.mm1
-rw-r--r--test/SemaObjCXX/category-lookup.mm2
-rw-r--r--test/SemaObjCXX/composite-objc-pointertype.mm1
-rw-r--r--test/SemaObjCXX/conversion-ranking.mm1
-rw-r--r--test/SemaObjCXX/conversion-to-objc-pointer-2.mm1
-rw-r--r--test/SemaObjCXX/conversion-to-objc-pointer.mm1
-rw-r--r--test/SemaObjCXX/debugger-support.mm8
-rw-r--r--test/SemaObjCXX/decltype.mm25
-rw-r--r--test/SemaObjCXX/delay-parsing-cfunctions.mm1
-rw-r--r--test/SemaObjCXX/delay-parsing-cplusfuncs.mm1
-rw-r--r--test/SemaObjCXX/delay-parsing-func-tryblock.mm1
-rw-r--r--test/SemaObjCXX/expr-objcxx.mm1
-rw-r--r--test/SemaObjCXX/format-strings.mm81
-rw-r--r--test/SemaObjCXX/function-pointer-void-star.mm1
-rw-r--r--test/SemaObjCXX/instantiate-method-return.mm1
-rw-r--r--test/SemaObjCXX/ivar-lookup.mm1
-rw-r--r--test/SemaObjCXX/ivar-struct.mm1
-rw-r--r--test/SemaObjCXX/linkage-spec.mm1
-rw-r--r--test/SemaObjCXX/namespace-lookup.mm1
-rw-r--r--test/SemaObjCXX/null_objc_pointer.mm1
-rw-r--r--test/SemaObjCXX/nullptr.mm1
-rw-r--r--test/SemaObjCXX/overload-gc.mm1
-rw-r--r--test/SemaObjCXX/pointer-to-objc-pointer-conv.mm3
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm2
-rw-r--r--test/SemaObjCXX/properties.mm23
-rw-r--r--test/SemaObjCXX/property-synthesis-error.mm23
-rw-r--r--test/SemaObjCXX/property-type-mismatch.mm1
-rw-r--r--test/SemaObjCXX/references.mm1
-rw-r--r--test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm1
-rw-r--r--test/SemaObjCXX/reserved-keyword-methods.mm1
-rw-r--r--test/SemaObjCXX/standard-conversion-to-bool.mm1
-rw-r--r--test/SemaObjCXX/static-cast.mm1
-rw-r--r--test/SemaObjCXX/vla.mm1
-rw-r--r--test/SemaOpenCL/cond.cl1
-rw-r--r--test/SemaOpenCL/init.cl1
-rw-r--r--test/SemaOpenCL/vec_compare.cl1
-rw-r--r--test/SemaOpenCL/vector_literals_const.cl1
-rw-r--r--test/SemaTemplate/ackermann.cpp1
-rw-r--r--test/SemaTemplate/alias-church-numerals.cpp1
-rw-r--r--test/SemaTemplate/alias-template-template-param.cpp1
-rw-r--r--test/SemaTemplate/array-to-pointer-decay.cpp1
-rw-r--r--test/SemaTemplate/atomics.cpp1
-rw-r--r--test/SemaTemplate/class-template-ctor-initializer.cpp17
-rw-r--r--test/SemaTemplate/class-template-id.cpp2
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp133
-rw-r--r--test/SemaTemplate/current-instantiation.cpp14
-rw-r--r--test/SemaTemplate/deduction-crash.cpp25
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp1
-rw-r--r--test/SemaTemplate/dependent-base-member-init.cpp1
-rw-r--r--test/SemaTemplate/dependent-expr.cpp1
-rw-r--r--test/SemaTemplate/dependent-names.cpp26
-rw-r--r--test/SemaTemplate/dependent-sized_array.cpp11
-rw-r--r--test/SemaTemplate/derived.cpp12
-rw-r--r--test/SemaTemplate/enum-argument.cpp1
-rw-r--r--test/SemaTemplate/example-typelist.cpp1
-rw-r--r--test/SemaTemplate/inject-templated-friend-post.cpp8
-rw-r--r--test/SemaTemplate/instantiate-array.cpp1
-rw-r--r--test/SemaTemplate/instantiate-attr.cpp10
-rw-r--r--test/SemaTemplate/instantiate-decl-init.cpp1
-rw-r--r--test/SemaTemplate/instantiate-declref-ice.cpp1
-rw-r--r--test/SemaTemplate/instantiate-deeply.cpp1
-rw-r--r--test/SemaTemplate/instantiate-dependent-nested-name.cpp1
-rw-r--r--test/SemaTemplate/instantiate-elab-type-specifier.cpp1
-rw-r--r--test/SemaTemplate/instantiate-enum-2.cpp1
-rw-r--r--test/SemaTemplate/instantiate-exception-spec-cxx11.cpp12
-rw-r--r--test/SemaTemplate/instantiate-friend-class.cpp1
-rw-r--r--test/SemaTemplate/instantiate-local-class.cpp1
-rw-r--r--test/SemaTemplate/instantiate-member-expr.cpp17
-rw-r--r--test/SemaTemplate/instantiate-non-type-template-parameter.cpp1
-rw-r--r--test/SemaTemplate/instantiate-overload-candidates.cpp30
-rw-r--r--test/SemaTemplate/instantiate-overloaded-arrow.cpp1
-rw-r--r--test/SemaTemplate/instantiate-sizeof.cpp1
-rw-r--r--test/SemaTemplate/instantiation-default-3.cpp1
-rw-r--r--test/SemaTemplate/instantiation-depth-exception-spec.cpp11
-rw-r--r--test/SemaTemplate/instantiation-depth-subst-2.cpp7
-rw-r--r--test/SemaTemplate/instantiation-depth-subst.cpp6
-rw-r--r--test/SemaTemplate/issue150.cpp1
-rw-r--r--test/SemaTemplate/lookup-dependent-bases.cpp1
-rw-r--r--test/SemaTemplate/member-access-ambig.cpp21
-rw-r--r--test/SemaTemplate/member-initializers.cpp1
-rw-r--r--test/SemaTemplate/nested-linkage.cpp1
-rw-r--r--test/SemaTemplate/nested-template.cpp5
-rw-r--r--test/SemaTemplate/operator-function-id-template.cpp1
-rw-r--r--test/SemaTemplate/overload-uneval.cpp1
-rw-r--r--test/SemaTemplate/pragma-ms_struct.cpp1
-rw-r--r--test/SemaTemplate/temp_class_spec_blocks.cpp1
-rw-r--r--test/SemaTemplate/template-class-traits.cpp1
-rw-r--r--test/SemaTemplate/typo-dependent-name.cpp1
-rw-r--r--test/SemaTemplate/unresolved-construct.cpp1
-rw-r--r--test/Tooling/clang-check-ast-dump.cpp9
-rw-r--r--test/lit.cfg29
-rw-r--r--tools/CMakeLists.txt6
-rw-r--r--tools/Makefile5
-rw-r--r--tools/arcmt-test/CMakeLists.txt2
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp10
-rw-r--r--tools/c-arcmt-test/Makefile8
-rw-r--r--tools/c-index-test/CMakeLists.txt7
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c173
-rw-r--r--tools/clang-check/CMakeLists.txt1
-rw-r--r--tools/clang-check/ClangCheck.cpp130
-rw-r--r--tools/clang-check/Makefile4
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp4
-rw-r--r--tools/diagtool/TreeView.cpp51
-rw-r--r--tools/driver/CMakeLists.txt3
-rw-r--r--tools/driver/Makefile3
-rw-r--r--tools/driver/cc1_main.cpp78
-rw-r--r--tools/driver/cc1as_main.cpp17
-rw-r--r--tools/driver/driver.cpp12
-rw-r--r--tools/libclang/CIndex.cpp202
-rw-r--r--tools/libclang/CIndexCXX.cpp3
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp8
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp8
-rw-r--r--tools/libclang/CIndexUSRs.cpp44
-rw-r--r--tools/libclang/CMakeLists.txt3
-rw-r--r--tools/libclang/CXComment.cpp197
-rw-r--r--tools/libclang/CXComment.h23
-rw-r--r--tools/libclang/CXCursor.cpp204
-rw-r--r--tools/libclang/CXType.cpp3
-rw-r--r--tools/libclang/CursorVisitor.h20
-rw-r--r--tools/libclang/IndexBody.cpp14
-rw-r--r--tools/libclang/IndexDecl.cpp15
-rw-r--r--tools/libclang/Indexing.cpp104
-rw-r--r--tools/libclang/IndexingContext.cpp68
-rw-r--r--tools/libclang/IndexingContext.h26
-rw-r--r--tools/libclang/Makefile15
-rw-r--r--tools/libclang/RecursiveASTVisitor.h7
-rw-r--r--tools/libclang/libclang.exports7
-rwxr-xr-xtools/scan-build/ccc-analyzer2
-rwxr-xr-xtools/scan-build/scan-build338
-rw-r--r--tools/scan-build/scan-build.115
-rwxr-xr-xtools/scan-build/set-xcode-analyzer22
-rw-r--r--tools/scan-view/ScanView.py5
-rw-r--r--unittests/AST/CMakeLists.txt5
-rw-r--r--unittests/AST/CommentLexer.cpp327
-rw-r--r--unittests/AST/CommentParser.cpp125
-rw-r--r--unittests/AST/DeclPrinterTest.cpp1248
-rw-r--r--unittests/AST/Makefile8
-rw-r--r--unittests/AST/SourceLocationTest.cpp289
-rw-r--r--unittests/AST/StmtPrinterTest.cpp172
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp1859
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h20
-rw-r--r--unittests/ASTMatchers/Makefile3
-rw-r--r--unittests/Basic/SourceManagerTest.cpp32
-rw-r--r--unittests/Frontend/Makefile3
-rw-r--r--unittests/Lex/CMakeLists.txt1
-rw-r--r--unittests/Lex/LexerTest.cpp21
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp246
-rw-r--r--unittests/Lex/PreprocessingRecordTest.cpp21
-rw-r--r--unittests/Tooling/CMakeLists.txt2
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp123
-rw-r--r--unittests/Tooling/Makefile3
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp68
-rw-r--r--unittests/Tooling/RefactoringCallbacksTest.cpp16
-rw-r--r--unittests/Tooling/RefactoringTest.cpp4
-rw-r--r--unittests/Tooling/RewriterTestContext.h11
-rw-r--r--unittests/Tooling/TestVisitor.h161
-rw-r--r--unittests/Tooling/ToolingTest.cpp32
-rw-r--r--utils/ClangDataFormat.py113
-rw-r--r--utils/TableGen/CMakeLists.txt4
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp4
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp72
-rw-r--r--utils/TableGen/ClangCommentHTMLTagsEmitter.cpp69
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp20
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp23
-rw-r--r--utils/TableGen/Makefile2
-rw-r--r--utils/TableGen/NeonEmitter.cpp28
-rw-r--r--utils/TableGen/OptParserEmitter.cpp101
-rw-r--r--utils/TableGen/TableGen.cpp175
-rw-r--r--utils/TableGen/TableGenBackends.h5
-rwxr-xr-xutils/analyzer/CmpRuns.py92
-rw-r--r--utils/analyzer/SATestAdd.py18
-rw-r--r--utils/analyzer/SATestBuild.py163
-rw-r--r--utils/analyzer/SumTimerInfo.py17
-rwxr-xr-xutils/analyzer/update_plist_test.pl51
-rw-r--r--www/analyzer/available_checks.html3
-rw-r--r--www/analyzer/checker_dev_manual.html2
-rw-r--r--www/analyzer/content.css32
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/menu.html.incl1
-rw-r--r--www/analyzer/potential_checkers.html1651
-rw-r--r--www/analyzer/release_notes.html23
-rw-r--r--www/cxx_status.html8
-rw-r--r--www/libstdc++4.6-clang11.patch11
-rw-r--r--www/menu.css4
-rw-r--r--www/timing-data/2008-10-31/176.gcc-01.txt135
-rw-r--r--www/timing-data/2008-10-31/176.gcc-02.txt135
-rw-r--r--www/timing-data/2008-10-31/176.gcc.pngbin20395 -> 0 bytes
-rw-r--r--www/timing-data/2008-10-31/sketch-01.txt187
-rw-r--r--www/timing-data/2008-10-31/sketch-02.txt187
-rw-r--r--www/timing-data/2008-10-31/sketch.pngbin23482 -> 0 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.pdfbin34547 -> 0 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.pngbin77003 -> 0 bytes
-rw-r--r--www/timing-data/2009-03-02/176.gcc.txt1120
-rw-r--r--www/timing-data/2009-03-02/sketch.pdfbin36086 -> 0 bytes
-rw-r--r--www/timing-data/2009-03-02/sketch.pngbin78278 -> 0 bytes
-rw-r--r--www/timing-data/2009-03-02/sketch.txt2368
-rw-r--r--www/timing-data/2009-06-26/176.gcc.pdfbin33680 -> 0 bytes
-rw-r--r--www/timing-data/2009-06-26/176.gcc.pngbin61190 -> 0 bytes
-rw-r--r--www/timing-data/2009-06-26/176.gcc.txt699
-rw-r--r--www/timing-data/2009-06-26/sketch.pdfbin34528 -> 0 bytes
-rw-r--r--www/timing-data/2009-06-26/sketch.pngbin62222 -> 0 bytes
-rw-r--r--www/timing-data/2009-06-26/sketch.txt803
2195 files changed, 118236 insertions, 46303 deletions
diff --git a/.gitignore b/.gitignore
index b906ab919cbe..6be9976262a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@
*.pyc
# vim swap files
.*.swp
+.sw?
#==============================================================================#
# Explicit files to ignore (only matches one).
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f4fa1cb5d7a..53d4165caec3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -181,16 +181,26 @@ endfunction(clang_tablegen)
macro(add_clang_library name)
llvm_process_sources(srcs ${ARGN})
if(MSVC_IDE OR XCODE)
- string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
- list( GET split_path -1 dir)
- file( GLOB_RECURSE headers
- ../../../include/clang/StaticAnalyzer${dir}/*.h
- ../../../include/clang/StaticAnalyzer${dir}/*.td
- ../../../include/clang/StaticAnalyzer${dir}/*.def
- ../../include/clang${dir}/*.h
- ../../include/clang${dir}/*.td
- ../../include/clang${dir}/*.def)
- set(srcs ${srcs} ${headers})
+ # Add public headers
+ file(RELATIVE_PATH lib_path
+ ${CLANG_SOURCE_DIR}/lib/
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+ if(NOT lib_path MATCHES "^[.][.]")
+ file( GLOB_RECURSE headers
+ ${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.h
+ ${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.def
+ )
+ set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
+
+ file( GLOB_RECURSE tds
+ ${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.td
+ )
+ source_group("TableGen descriptions" FILES ${tds})
+ set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
+
+ set(srcs ${srcs} ${headers} ${tds})
+ endif()
endif(MSVC_IDE OR XCODE)
if (MODULE)
set(libkind MODULE)
diff --git a/Makefile b/Makefile
index bf1a77210b5e..cb2566a0a17d 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,10 @@ ifeq ($(MAKECMDGOALS),libs-only)
DIRS := $(filter-out tools docs, $(DIRS))
OPTIONAL_DIRS :=
endif
+ifeq ($(BUILD_CLANG_ONLY),YES)
+ DIRS := $(filter-out docs unittests, $(DIRS))
+ OPTIONAL_DIRS :=
+endif
###
# Common Makefile code, shared by all Clang Makefiles.
diff --git a/NOTES.txt b/NOTES.txt
index ca46d1cae478..1c89d685729b 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -44,7 +44,7 @@ TODO: File Manager Speedup:
2. Instead of stat'ing the file in FileManager::getFile, check to see if
the dir has been read. If so, fail immediately, if not, read the dir,
then retry.
- 3. Reading the dir uses the getdirentries syscall, creating an FileEntry
+ 3. Reading the dir uses the getdirentries syscall, creating a FileEntry
for all files found.
//===---------------------------------------------------------------------===//
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index fc0a2a18bb40..5e162c0e8349 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -67,26 +67,12 @@ import collections
import clang.enumerations
-def get_cindex_library():
- # FIXME: It's probably not the case that the library is actually found in
- # this location. We need a better system of identifying and loading the
- # CIndex library. It could be on path or elsewhere, or versioned, etc.
- import platform
- name = platform.system()
- if name == 'Darwin':
- return cdll.LoadLibrary('libclang.dylib')
- elif name == 'Windows':
- return cdll.LoadLibrary('libclang.dll')
- else:
- return cdll.LoadLibrary('libclang.so')
-
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
# object. This is a problem, because it means that from_parameter will see an
# integer and pass the wrong value on platforms where int != void*. Work around
# this by marshalling object arguments as void**.
c_object_p = POINTER(c_void_p)
-lib = get_cindex_library()
callbacks = {}
### Exception Classes ###
@@ -133,18 +119,43 @@ class TranslationUnitSaveError(Exception):
### Structures and Utility Classes ###
+class CachedProperty(object):
+ """Decorator that lazy-loads the value of a property.
+
+ The first time the property is accessed, the original property function is
+ executed. The value it returns is set as the new value of that instance's
+ property, replacing the original method.
+ """
+
+ def __init__(self, wrapped):
+ self.wrapped = wrapped
+ try:
+ self.__doc__ = wrapped.__doc__
+ except:
+ pass
+
+ def __get__(self, instance, instance_type=None):
+ if instance is None:
+ return self
+
+ value = self.wrapped(instance)
+ setattr(instance, self.wrapped.__name__, value)
+
+ return value
+
+
class _CXString(Structure):
"""Helper for transforming CXString results."""
_fields_ = [("spelling", c_char_p), ("free", c_int)]
def __del__(self):
- lib.clang_disposeString(self)
+ conf.lib.clang_disposeString(self)
@staticmethod
def from_result(res, fn, args):
assert isinstance(res, _CXString)
- return lib.clang_getCString(res)
+ return conf.lib.clang_getCString(res)
class SourceLocation(Structure):
"""
@@ -156,7 +167,7 @@ class SourceLocation(Structure):
def _get_instantiation(self):
if self._data is None:
f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
- lib.clang_getInstantiationLocation(self, byref(f), byref(l),
+ conf.lib.clang_getInstantiationLocation(self, byref(f), byref(l),
byref(c), byref(o))
if f:
f = File(f)
@@ -171,7 +182,7 @@ class SourceLocation(Structure):
Retrieve the source location associated with a given file/line/column in
a particular translation unit.
"""
- return lib.clang_getLocation(tu, file, line, column)
+ return conf.lib.clang_getLocation(tu, file, line, column)
@staticmethod
def from_offset(tu, file, offset):
@@ -181,7 +192,7 @@ class SourceLocation(Structure):
file -- File instance to obtain offset from
offset -- Integer character offset within file
"""
- return lib.clang_getLocationForOffset(tu, file, offset)
+ return conf.lib.clang_getLocationForOffset(tu, file, offset)
@property
def file(self):
@@ -204,7 +215,7 @@ class SourceLocation(Structure):
return self._get_instantiation()[3]
def __eq__(self, other):
- return lib.clang_equalLocations(self, other)
+ return conf.lib.clang_equalLocations(self, other)
def __ne__(self, other):
return not self.__eq__(other)
@@ -231,7 +242,7 @@ class SourceRange(Structure):
# object.
@staticmethod
def from_locations(start, end):
- return lib.clang_getRange(start, end)
+ return conf.lib.clang_getRange(start, end)
@property
def start(self):
@@ -239,7 +250,7 @@ class SourceRange(Structure):
Return a SourceLocation representing the first character within a
source range.
"""
- return lib.clang_getRangeStart(self)
+ return conf.lib.clang_getRangeStart(self)
@property
def end(self):
@@ -247,10 +258,10 @@ class SourceRange(Structure):
Return a SourceLocation representing the last character within a
source range.
"""
- return lib.clang_getRangeEnd(self)
+ return conf.lib.clang_getRangeEnd(self)
def __eq__(self, other):
- return lib.clang_equalRanges(self, other)
+ return conf.lib.clang_equalRanges(self, other)
def __ne__(self, other):
return not self.__eq__(other)
@@ -275,19 +286,19 @@ class Diagnostic(object):
self.ptr = ptr
def __del__(self):
- lib.clang_disposeDiagnostic(self)
+ conf.lib.clang_disposeDiagnostic(self)
@property
def severity(self):
- return lib.clang_getDiagnosticSeverity(self)
+ return conf.lib.clang_getDiagnosticSeverity(self)
@property
def location(self):
- return lib.clang_getDiagnosticLocation(self)
+ return conf.lib.clang_getDiagnosticLocation(self)
@property
def spelling(self):
- return lib.clang_getDiagnosticSpelling(self)
+ return conf.lib.clang_getDiagnosticSpelling(self)
@property
def ranges(self):
@@ -296,12 +307,12 @@ class Diagnostic(object):
self.diag = diag
def __len__(self):
- return int(lib.clang_getDiagnosticNumRanges(self.diag))
+ return int(conf.lib.clang_getDiagnosticNumRanges(self.diag))
def __getitem__(self, key):
if (key >= len(self)):
raise IndexError
- return lib.clang_getDiagnosticRange(self.diag, key)
+ return conf.lib.clang_getDiagnosticRange(self.diag, key)
return RangeIterator(self)
@@ -312,11 +323,11 @@ class Diagnostic(object):
self.diag = diag
def __len__(self):
- return int(lib.clang_getDiagnosticNumFixIts(self.diag))
+ return int(conf.lib.clang_getDiagnosticNumFixIts(self.diag))
def __getitem__(self, key):
range = SourceRange()
- value = lib.clang_getDiagnosticFixIt(self.diag, key,
+ value = conf.lib.clang_getDiagnosticFixIt(self.diag, key,
byref(range))
if len(value) == 0:
raise IndexError
@@ -328,25 +339,25 @@ class Diagnostic(object):
@property
def category_number(self):
"""The category number for this diagnostic."""
- return lib.clang_getDiagnosticCategory(self)
+ return conf.lib.clang_getDiagnosticCategory(self)
@property
def category_name(self):
"""The string name of the category for this diagnostic."""
- return lib.clang_getDiagnosticCategoryName(self.category_number)
+ return conf.lib.clang_getDiagnosticCategoryName(self.category_number)
@property
def option(self):
"""The command-line option that enables this diagnostic."""
- return lib.clang_getDiagnosticOption(self, None)
+ return conf.lib.clang_getDiagnosticOption(self, None)
@property
def disable_option(self):
"""The command-line option that disables this diagnostic."""
disable = _CXString()
- lib.clang_getDiagnosticOption(self, byref(disable))
+ conf.lib.clang_getDiagnosticOption(self, byref(disable))
- return lib.clang_getCString(disable)
+ return conf.lib.clang_getCString(disable)
def __repr__(self):
return "<Diagnostic severity %r, location %r, spelling %r>" % (
@@ -389,7 +400,7 @@ class TokenGroup(object):
self._count = count
def __del__(self):
- lib.clang_disposeTokens(self._tu, self._memory, self._count)
+ conf.lib.clang_disposeTokens(self._tu, self._memory, self._count)
@staticmethod
def get_tokens(tu, extent):
@@ -401,7 +412,7 @@ class TokenGroup(object):
tokens_memory = POINTER(Token)()
tokens_count = c_uint()
- lib.clang_tokenize(tu, extent, byref(tokens_memory),
+ conf.lib.clang_tokenize(tu, extent, byref(tokens_memory),
byref(tokens_count))
count = int(tokens_count.value)
@@ -507,39 +518,39 @@ class CursorKind(object):
def is_declaration(self):
"""Test if this is a declaration kind."""
- return lib.clang_isDeclaration(self)
+ return conf.lib.clang_isDeclaration(self)
def is_reference(self):
"""Test if this is a reference kind."""
- return lib.clang_isReference(self)
+ return conf.lib.clang_isReference(self)
def is_expression(self):
"""Test if this is an expression kind."""
- return lib.clang_isExpression(self)
+ return conf.lib.clang_isExpression(self)
def is_statement(self):
"""Test if this is a statement kind."""
- return lib.clang_isStatement(self)
+ return conf.lib.clang_isStatement(self)
def is_attribute(self):
"""Test if this is an attribute kind."""
- return lib.clang_isAttribute(self)
+ return conf.lib.clang_isAttribute(self)
def is_invalid(self):
"""Test if this is an invalid kind."""
- return lib.clang_isInvalid(self)
+ return conf.lib.clang_isInvalid(self)
def is_translation_unit(self):
"""Test if this is a translation unit kind."""
- return lib.clang_isTranslationUnit(self)
+ return conf.lib.clang_isTranslationUnit(self)
def is_preprocessing(self):
"""Test if this is a preprocessing kind."""
- return lib.clang_isPreprocessing(self)
+ return conf.lib.clang_isPreprocessing(self)
def is_unexposed(self):
"""Test if this is an unexposed kind."""
- return lib.clang_isUnexposed(self)
+ return conf.lib.clang_isUnexposed(self)
def __repr__(self):
return 'CursorKind.%s' % (self.name,)
@@ -643,7 +654,7 @@ CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27)
CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28)
# A C++ template template parameter.
-CursorKind.TEMPLATE_TEMPLATE_PARAMTER = CursorKind(29)
+CursorKind.TEMPLATE_TEMPLATE_PARAMETER = CursorKind(29)
# A C++ function template.
CursorKind.FUNCTION_TEMPLATE = CursorKind(30)
@@ -1038,13 +1049,13 @@ class Cursor(Structure):
def from_location(tu, location):
# We store a reference to the TU in the instance so the TU won't get
# collected before the cursor.
- cursor = lib.clang_getCursor(tu, location)
+ cursor = conf.lib.clang_getCursor(tu, location)
cursor._tu = tu
return cursor
def __eq__(self, other):
- return lib.clang_equalCursors(self, other)
+ return conf.lib.clang_equalCursors(self, other)
def __ne__(self, other):
return not self.__eq__(other)
@@ -1054,13 +1065,13 @@ class Cursor(Structure):
Returns true if the declaration pointed at by the cursor is also a
definition of that entity.
"""
- return lib.clang_isCursorDefinition(self)
+ return conf.lib.clang_isCursorDefinition(self)
def is_static_method(self):
"""Returns True if the cursor refers to a C++ member function or member
function template that is declared 'static'.
"""
- return lib.clang_CXXMethod_isStatic(self)
+ return conf.lib.clang_CXXMethod_isStatic(self)
def get_definition(self):
"""
@@ -1070,7 +1081,7 @@ class Cursor(Structure):
"""
# TODO: Should probably check that this is either a reference or
# declaration prior to issuing the lookup.
- return lib.clang_getCursorDefinition(self)
+ return conf.lib.clang_getCursorDefinition(self)
def get_usr(self):
"""Return the Unified Symbol Resultion (USR) for the entity referenced
@@ -1081,7 +1092,7 @@ class Cursor(Structure):
program. USRs can be compared across translation units to determine,
e.g., when references in one translation refer to an entity defined in
another translation unit."""
- return lib.clang_getCursorUSR(self)
+ return conf.lib.clang_getCursorUSR(self)
@property
def kind(self):
@@ -1096,7 +1107,7 @@ class Cursor(Structure):
# this, for consistency with clang_getCursorUSR.
return None
if not hasattr(self, '_spelling'):
- self._spelling = lib.clang_getCursorSpelling(self)
+ self._spelling = conf.lib.clang_getCursorSpelling(self)
return self._spelling
@@ -1110,7 +1121,7 @@ class Cursor(Structure):
class template specialization.
"""
if not hasattr(self, '_displayname'):
- self._displayname = lib.clang_getCursorDisplayName(self)
+ self._displayname = conf.lib.clang_getCursorDisplayName(self)
return self._displayname
@@ -1121,7 +1132,7 @@ class Cursor(Structure):
pointed at by the cursor.
"""
if not hasattr(self, '_loc'):
- self._loc = lib.clang_getCursorLocation(self)
+ self._loc = conf.lib.clang_getCursorLocation(self)
return self._loc
@@ -1132,7 +1143,7 @@ class Cursor(Structure):
pointed at by the cursor.
"""
if not hasattr(self, '_extent'):
- self._extent = lib.clang_getCursorExtent(self)
+ self._extent = conf.lib.clang_getCursorExtent(self)
return self._extent
@@ -1142,7 +1153,7 @@ class Cursor(Structure):
Retrieve the Type (if any) of the entity pointed at by the cursor.
"""
if not hasattr(self, '_type'):
- self._type = lib.clang_getCursorType(self)
+ self._type = conf.lib.clang_getCursorType(self)
return self._type
@@ -1156,7 +1167,7 @@ class Cursor(Structure):
declarations will be identical.
"""
if not hasattr(self, '_canonical'):
- self._canonical = lib.clang_getCanonicalCursor(self)
+ self._canonical = conf.lib.clang_getCanonicalCursor(self)
return self._canonical
@@ -1164,7 +1175,7 @@ class Cursor(Structure):
def result_type(self):
"""Retrieve the Type of the result for this Cursor."""
if not hasattr(self, '_result_type'):
- self._result_type = lib.clang_getResultType(self.type)
+ self._result_type = conf.lib.clang_getResultType(self.type)
return self._result_type
@@ -1177,7 +1188,8 @@ class Cursor(Structure):
"""
if not hasattr(self, '_underlying_type'):
assert self.kind.is_declaration()
- self._underlying_type = lib.clang_getTypedefDeclUnderlyingType(self)
+ self._underlying_type = \
+ conf.lib.clang_getTypedefDeclUnderlyingType(self)
return self._underlying_type
@@ -1190,7 +1202,7 @@ class Cursor(Structure):
"""
if not hasattr(self, '_enum_type'):
assert self.kind == CursorKind.ENUM_DECL
- self._enum_type = lib.clang_getEnumDeclIntegerType(self)
+ self._enum_type = conf.lib.clang_getEnumDeclIntegerType(self)
return self._enum_type
@@ -1213,16 +1225,18 @@ class Cursor(Structure):
TypeKind.ULONG,
TypeKind.ULONGLONG,
TypeKind.UINT128):
- self._enum_value = lib.clang_getEnumConstantDeclUnsignedValue(self)
+ self._enum_value = \
+ conf.lib.clang_getEnumConstantDeclUnsignedValue(self)
else:
- self._enum_value = lib.clang_getEnumConstantDeclValue(self)
+ self._enum_value = conf.lib.clang_getEnumConstantDeclValue(self)
return self._enum_value
@property
def objc_type_encoding(self):
"""Return the Objective-C type encoding as a str."""
if not hasattr(self, '_objc_type_encoding'):
- self._objc_type_encoding = lib.clang_getDeclObjCTypeEncoding(self)
+ self._objc_type_encoding = \
+ conf.lib.clang_getDeclObjCTypeEncoding(self)
return self._objc_type_encoding
@@ -1230,7 +1244,7 @@ class Cursor(Structure):
def hash(self):
"""Returns a hash of the cursor as an int."""
if not hasattr(self, '_hash'):
- self._hash = lib.clang_hashCursor(self)
+ self._hash = conf.lib.clang_hashCursor(self)
return self._hash
@@ -1238,7 +1252,7 @@ class Cursor(Structure):
def semantic_parent(self):
"""Return the semantic parent for this cursor."""
if not hasattr(self, '_semantic_parent'):
- self._semantic_parent = lib.clang_getCursorSemanticParent(self)
+ self._semantic_parent = conf.lib.clang_getCursorSemanticParent(self)
return self._semantic_parent
@@ -1246,7 +1260,7 @@ class Cursor(Structure):
def lexical_parent(self):
"""Return the lexical parent for this cursor."""
if not hasattr(self, '_lexical_parent'):
- self._lexical_parent = lib.clang_getCursorLexicalParent(self)
+ self._lexical_parent = conf.lib.clang_getCursorLexicalParent(self)
return self._lexical_parent
@@ -1257,6 +1271,12 @@ class Cursor(Structure):
# created.
return self._tu
+ def get_arguments(self):
+ """Return an iterator for accessing the arguments of this cursor."""
+ num_args = conf.lib.clang_Cursor_getNumArguments(self)
+ for i in range(0, num_args):
+ yield conf.lib.clang_Cursor_getArgument(self, i)
+
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -1264,14 +1284,14 @@ class Cursor(Structure):
def visitor(child, parent, children):
# FIXME: Document this assertion in API.
# FIXME: There should just be an isNull method.
- assert child != lib.clang_getNullCursor()
+ assert child != conf.lib.clang_getNullCursor()
# Create reference to TU so it isn't GC'd before Cursor.
child._tu = self._tu
children.append(child)
return 1 # continue
children = []
- lib.clang_visitChildren(self, callbacks['cursor_visit'](visitor),
+ conf.lib.clang_visitChildren(self, callbacks['cursor_visit'](visitor),
children)
return iter(children)
@@ -1287,7 +1307,7 @@ class Cursor(Structure):
def from_result(res, fn, args):
assert isinstance(res, Cursor)
# FIXME: There should just be an isNull method.
- if res == lib.clang_getNullCursor():
+ if res == conf.lib.clang_getNullCursor():
return None
# Store a reference to the TU in the Python object so it won't get GC'd
@@ -1310,7 +1330,7 @@ class Cursor(Structure):
@staticmethod
def from_cursor_result(res, fn, args):
assert isinstance(res, Cursor)
- if res == lib.clang_getNullCursor():
+ if res == conf.lib.clang_getNullCursor():
return None
res._tu = args[0]._tu
@@ -1352,7 +1372,7 @@ class TypeKind(object):
@property
def spelling(self):
"""Retrieve the spelling of this TypeKind."""
- return lib.clang_getTypeKindSpelling(self.value)
+ return conf.lib.clang_getTypeKindSpelling(self.value)
@staticmethod
def from_id(id):
@@ -1432,7 +1452,7 @@ class Type(Structure):
def __len__(self):
if self.length is None:
- self.length = lib.clang_getNumArgTypes(self.parent)
+ self.length = conf.lib.clang_getNumArgTypes(self.parent)
return self.length
@@ -1448,7 +1468,7 @@ class Type(Structure):
raise IndexError("Index greater than container length: "
"%d > %d" % ( key, len(self) ))
- result = lib.clang_getArgType(self.parent, key)
+ result = conf.lib.clang_getArgType(self.parent, key)
if result.kind == TypeKind.INVALID:
raise IndexError("Argument could not be retrieved.")
@@ -1464,7 +1484,7 @@ class Type(Structure):
If accessed on a type that is not an array, complex, or vector type, an
exception will be raised.
"""
- result = lib.clang_getElementType(self)
+ result = conf.lib.clang_getElementType(self)
if result.kind == TypeKind.INVALID:
raise Exception('Element type not available on this type.')
@@ -1478,7 +1498,7 @@ class Type(Structure):
If the Type is not an array or vector, this raises.
"""
- result = lib.clang_getNumElements(self)
+ result = conf.lib.clang_getNumElements(self)
if result < 0:
raise Exception('Type does not have elements.')
@@ -1516,7 +1536,7 @@ class Type(Structure):
example, if 'T' is a typedef for 'int', the canonical type for
'T' would be 'int'.
"""
- return lib.clang_getCanonicalType(self)
+ return conf.lib.clang_getCanonicalType(self)
def is_const_qualified(self):
"""Determine whether a Type has the "const" qualifier set.
@@ -1524,7 +1544,7 @@ class Type(Structure):
This does not look through typedefs that may have added "const"
at a different level.
"""
- return lib.clang_isConstQualifiedType(self)
+ return conf.lib.clang_isConstQualifiedType(self)
def is_volatile_qualified(self):
"""Determine whether a Type has the "volatile" qualifier set.
@@ -1532,7 +1552,7 @@ class Type(Structure):
This does not look through typedefs that may have added "volatile"
at a different level.
"""
- return lib.clang_isVolatileQualifiedType(self)
+ return conf.lib.clang_isVolatileQualifiedType(self)
def is_restrict_qualified(self):
"""Determine whether a Type has the "restrict" qualifier set.
@@ -1540,53 +1560,53 @@ class Type(Structure):
This does not look through typedefs that may have added "restrict" at
a different level.
"""
- return lib.clang_isRestrictQualifiedType(self)
+ return conf.lib.clang_isRestrictQualifiedType(self)
def is_function_variadic(self):
"""Determine whether this function Type is a variadic function type."""
assert self.kind == TypeKind.FUNCTIONPROTO
- return lib.clang_isFunctionTypeVariadic(self)
+ return conf.lib.clang_isFunctionTypeVariadic(self)
def is_pod(self):
"""Determine whether this Type represents plain old data (POD)."""
- return lib.clang_isPODType(self)
+ return conf.lib.clang_isPODType(self)
def get_pointee(self):
"""
For pointer types, returns the type of the pointee.
"""
- return lib.clang_getPointeeType(self)
+ return conf.lib.clang_getPointeeType(self)
def get_declaration(self):
"""
Return the cursor for the declaration of the given type.
"""
- return lib.clang_getTypeDeclaration(self)
+ return conf.lib.clang_getTypeDeclaration(self)
def get_result(self):
"""
Retrieve the result type associated with a function type.
"""
- return lib.clang_getResultType(self)
+ return conf.lib.clang_getResultType(self)
def get_array_element_type(self):
"""
Retrieve the type of the elements of the array type.
"""
- return lib.clang_getArrayElementType(self)
+ return conf.lib.clang_getArrayElementType(self)
def get_array_size(self):
"""
Retrieve the size of the constant array.
"""
- return lib.clang_getArraySize(self)
+ return conf.lib.clang_getArraySize(self)
def __eq__(self, other):
if type(other) != type(self):
return False
- return lib.clang_equalTypes(self, other)
+ return conf.lib.clang_equalTypes(self, other)
def __ne__(self, other):
return not self.__eq__(other)
@@ -1632,18 +1652,19 @@ class CompletionChunk:
def __repr__(self):
return "{'" + self.spelling + "', " + str(self.kind) + "}"
- @property
+ @CachedProperty
def spelling(self):
- return lib.clang_getCompletionChunkText(self.cs, self.key).spelling
+ return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling
- @property
+ @CachedProperty
def kind(self):
- res = lib.clang_getCompletionChunkKind(self.cs, self.key)
+ res = conf.lib.clang_getCompletionChunkKind(self.cs, self.key)
return completionChunkKindMap[res]
- @property
+ @CachedProperty
def string(self):
- res = lib.clang_getCompletionChunkCompletionString(self.cs, self.key)
+ res = conf.lib.clang_getCompletionChunkCompletionString(self.cs,
+ self.key)
if (res):
return CompletionString(res)
@@ -1700,31 +1721,43 @@ class CompletionString(ClangObject):
return "<Availability: %s>" % self
def __len__(self):
- return lib.clang_getNumCompletionChunks(self.obj)
+ self.num_chunks
+
+ @CachedProperty
+ def num_chunks(self):
+ return conf.lib.clang_getNumCompletionChunks(self.obj)
def __getitem__(self, key):
- if len(self) <= key:
+ if self.num_chunks <= key:
raise IndexError
return CompletionChunk(self.obj, key)
@property
def priority(self):
- return lib.clang_getCompletionPriority(self.obj)
+ return conf.lib.clang_getCompletionPriority(self.obj)
@property
def availability(self):
- res = lib.clang_getCompletionAvailability(self.obj)
+ res = conf.lib.clang_getCompletionAvailability(self.obj)
return availabilityKinds[res]
+ @property
+ def briefComment(self):
+ if conf.function_exists("clang_getCompletionBriefComment"):
+ return conf.lib.clang_getCompletionBriefComment(self.obj)
+ return _CXString()
+
def __repr__(self):
return " | ".join([str(a) for a in self]) \
+ " || Priority: " + str(self.priority) \
- + " || Availability: " + str(self.availability)
+ + " || Availability: " + str(self.availability) \
+ + " || Brief comment: " + str(self.briefComment.spelling)
availabilityKinds = {
0: CompletionChunk.Kind("Available"),
1: CompletionChunk.Kind("Deprecated"),
- 2: CompletionChunk.Kind("NotAvailable")}
+ 2: CompletionChunk.Kind("NotAvailable"),
+ 3: CompletionChunk.Kind("NotAccessible")}
class CodeCompletionResult(Structure):
_fields_ = [('cursorKind', c_int), ('completionString', c_object_p)]
@@ -1762,7 +1795,7 @@ class CodeCompletionResults(ClangObject):
return self._as_parameter_
def __del__(self):
- CodeCompletionResults_dispose(self)
+ conf.lib.clang_disposeCodeCompleteResults(self)
@property
def results(self):
@@ -1775,10 +1808,11 @@ class CodeCompletionResults(ClangObject):
self.ccr= ccr
def __len__(self):
- return int(lib.clang_codeCompleteGetNumDiagnostics(self.ccr))
+ return int(\
+ conf.lib.clang_codeCompleteGetNumDiagnostics(self.ccr))
def __getitem__(self, key):
- return lib.clang_codeCompleteGetDiagnostic(self.ccr, key)
+ return conf.lib.clang_codeCompleteGetDiagnostic(self.ccr, key)
return DiagnosticsItr(self)
@@ -1797,10 +1831,10 @@ class Index(ClangObject):
Parameters:
excludeDecls -- Exclude local declarations from translation units.
"""
- return Index(lib.clang_createIndex(excludeDecls, 0))
+ return Index(conf.lib.clang_createIndex(excludeDecls, 0))
def __del__(self):
- lib.clang_disposeIndex(self)
+ conf.lib.clang_disposeIndex(self)
def read(self, path):
"""Load a TranslationUnit from the given AST file."""
@@ -1857,6 +1891,10 @@ class TranslationUnit(ClangObject):
# searching for declarations/definitions.
PARSE_SKIP_FUNCTION_BODIES = 64
+ # Used to indicate that brief documentation comments should be included
+ # into the set of code completions returned from this translation unit.
+ PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 128
+
@classmethod
def from_source(cls, filename, args=None, unsaved_files=None, options=0,
index=None):
@@ -1923,7 +1961,7 @@ class TranslationUnit(ClangObject):
unsaved_array[i].contents = contents
unsaved_array[i].length = len(contents)
- ptr = lib.clang_parseTranslationUnit(index, filename, args_array,
+ ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array,
len(args), unsaved_array,
len(unsaved_files), options)
@@ -1948,7 +1986,7 @@ class TranslationUnit(ClangObject):
if index is None:
index = Index.create()
- ptr = lib.clang_createTranslationUnit(index, filename)
+ ptr = conf.lib.clang_createTranslationUnit(index, filename)
if ptr is None:
raise TranslationUnitLoadError(filename)
@@ -1965,17 +2003,17 @@ class TranslationUnit(ClangObject):
ClangObject.__init__(self, ptr)
def __del__(self):
- lib.clang_disposeTranslationUnit(self)
+ conf.lib.clang_disposeTranslationUnit(self)
@property
def cursor(self):
"""Retrieve the cursor that represents the given translation unit."""
- return lib.clang_getTranslationUnitCursor(self)
+ return conf.lib.clang_getTranslationUnitCursor(self)
@property
def spelling(self):
"""Get the original translation unit source file name."""
- return lib.clang_getTranslationUnitSpelling(self)
+ return conf.lib.clang_getTranslationUnitSpelling(self)
def get_includes(self):
"""
@@ -1992,7 +2030,7 @@ class TranslationUnit(ClangObject):
# Automatically adapt CIndex/ctype pointers to python objects
includes = []
- lib.clang_getInclusions(self,
+ conf.lib.clang_getInclusions(self,
callbacks['translation_unit_includes'](visitor), includes)
return iter(includes)
@@ -2068,10 +2106,10 @@ class TranslationUnit(ClangObject):
self.tu = tu
def __len__(self):
- return int(lib.clang_getNumDiagnostics(self.tu))
+ return int(conf.lib.clang_getNumDiagnostics(self.tu))
def __getitem__(self, key):
- diag = lib.clang_getDiagnostic(self.tu, key)
+ diag = conf.lib.clang_getDiagnostic(self.tu, key)
if not diag:
raise IndexError
return Diagnostic(diag)
@@ -2104,7 +2142,7 @@ class TranslationUnit(ClangObject):
unsaved_files_array[i].name = name
unsaved_files_array[i].contents = value
unsaved_files_array[i].length = len(value)
- ptr = lib.clang_reparseTranslationUnit(self, len(unsaved_files),
+ ptr = conf.lib.clang_reparseTranslationUnit(self, len(unsaved_files),
unsaved_files_array, options)
def save(self, filename):
@@ -2122,13 +2160,16 @@ class TranslationUnit(ClangObject):
filename -- The path to save the translation unit to.
"""
- options = lib.clang_defaultSaveOptions(self)
- result = int(lib.clang_saveTranslationUnit(self, filename, options))
+ options = conf.lib.clang_defaultSaveOptions(self)
+ result = int(conf.lib.clang_saveTranslationUnit(self, filename,
+ options))
if result != 0:
raise TranslationUnitSaveError(result,
'Error saving TranslationUnit.')
- def codeComplete(self, path, line, column, unsaved_files=None, options=0):
+ def codeComplete(self, path, line, column, unsaved_files=None,
+ include_macros=False, include_code_patterns=False,
+ include_brief_comments=False):
"""
Code complete in this translation unit.
@@ -2137,6 +2178,17 @@ class TranslationUnit(ClangObject):
and the second should be the contents to be substituted for the
file. The contents may be passed as strings or file objects.
"""
+ options = 0
+
+ if include_macros:
+ options += 1
+
+ if include_code_patterns:
+ options += 2
+
+ if include_brief_comments:
+ options += 4
+
if unsaved_files is None:
unsaved_files = []
@@ -2154,7 +2206,7 @@ class TranslationUnit(ClangObject):
unsaved_files_array[i].name = name
unsaved_files_array[i].contents = value
unsaved_files_array[i].length = len(value)
- ptr = lib.clang_codeCompleteAt(self, path, line, column,
+ ptr = conf.lib.clang_codeCompleteAt(self, path, line, column,
unsaved_files_array, len(unsaved_files), options)
if ptr:
return CodeCompletionResults(ptr)
@@ -2182,17 +2234,17 @@ class File(ClangObject):
@staticmethod
def from_name(translation_unit, file_name):
"""Retrieve a file handle within the given translation unit."""
- return File(lib.clang_getFile(translation_unit, file_name))
+ return File(conf.lib.clang_getFile(translation_unit, file_name))
@property
def name(self):
"""Return the complete file and path name of the file."""
- return lib.clang_getCString(lib.clang_getFileName(self))
+ return conf.lib.clang_getCString(conf.lib.clang_getFileName(self))
@property
def time(self):
"""Return the last modification time of the file."""
- return lib.clang_getFileTime(self)
+ return conf.lib.clang_getFileTime(self)
def __str__(self):
return self.name
@@ -2264,7 +2316,7 @@ class CompileCommand(object):
@property
def directory(self):
"""Get the working directory for this CompileCommand"""
- return lib.clang_CompileCommand_getDirectory(self.cmd)
+ return conf.lib.clang_CompileCommand_getDirectory(self.cmd)
@property
def arguments(self):
@@ -2274,9 +2326,9 @@ class CompileCommand(object):
Invariant : the first argument is the compiler executable
"""
- length = lib.clang_CompileCommand_getNumArgs(self.cmd)
+ length = conf.lib.clang_CompileCommand_getNumArgs(self.cmd)
for i in xrange(length):
- yield lib.clang_CompileCommand_getArg(self.cmd, i)
+ yield conf.lib.clang_CompileCommand_getArg(self.cmd, i)
class CompileCommands(object):
"""
@@ -2287,13 +2339,13 @@ class CompileCommands(object):
self.ccmds = ccmds
def __del__(self):
- lib.clang_CompileCommands_dispose(self.ccmds)
+ conf.lib.clang_CompileCommands_dispose(self.ccmds)
def __len__(self):
- return int(lib.clang_CompileCommands_getSize(self.ccmds))
+ return int(conf.lib.clang_CompileCommands_getSize(self.ccmds))
def __getitem__(self, i):
- cc = lib.clang_CompileCommands_getCommand(self.ccmds, i)
+ cc = conf.lib.clang_CompileCommands_getCommand(self.ccmds, i)
if not cc:
raise IndexError
return CompileCommand(cc, self)
@@ -2313,7 +2365,7 @@ class CompilationDatabase(ClangObject):
"""
def __del__(self):
- lib.clang_CompilationDatabase_dispose(self)
+ conf.lib.clang_CompilationDatabase_dispose(self)
@staticmethod
def from_result(res, fn, args):
@@ -2327,7 +2379,7 @@ class CompilationDatabase(ClangObject):
"""Builds a CompilationDatabase from the database found in buildDir"""
errorCode = c_uint()
try:
- cdb = lib.clang_CompilationDatabase_fromDirectory(buildDir,
+ cdb = conf.lib.clang_CompilationDatabase_fromDirectory(buildDir,
byref(errorCode))
except CompilationDatabaseError as e:
raise CompilationDatabaseError(int(errorCode.value),
@@ -2339,7 +2391,8 @@ class CompilationDatabase(ClangObject):
Get an iterable object providing all the CompileCommands available to
build filename. Returns None if filename is not found in the database.
"""
- return lib.clang_CompilationDatabase_getCompileCommands(self, filename)
+ return conf.lib.clang_CompilationDatabase_getCompileCommands(self,
+ filename)
class Token(Structure):
"""Represents a single token from the preprocessor.
@@ -2361,29 +2414,29 @@ class Token(Structure):
This is the textual representation of the token in source.
"""
- return lib.clang_getTokenSpelling(self._tu, self)
+ return conf.lib.clang_getTokenSpelling(self._tu, self)
@property
def kind(self):
"""Obtain the TokenKind of the current token."""
- return TokenKind.from_value(lib.clang_getTokenKind(self))
+ return TokenKind.from_value(conf.lib.clang_getTokenKind(self))
@property
def location(self):
"""The SourceLocation this Token occurs at."""
- return lib.clang_getTokenLocation(self._tu, self)
+ return conf.lib.clang_getTokenLocation(self._tu, self)
@property
def extent(self):
"""The SourceRange this Token occupies."""
- return lib.clang_getTokenExtent(self._tu, self)
+ return conf.lib.clang_getTokenExtent(self._tu, self)
@property
def cursor(self):
"""The Cursor this Token corresponds to."""
cursor = Cursor()
- lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor))
+ conf.lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor))
return cursor
@@ -2394,434 +2447,691 @@ callbacks['translation_unit_includes'] = CFUNCTYPE(None, c_object_p,
POINTER(SourceLocation), c_uint, py_object)
callbacks['cursor_visit'] = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
-def register_functions(lib):
- """Register function prototypes with a libclang library instance.
-
- This must be called as part of library instantiation so Python knows how
- to call out to the shared library.
- """
- # Functions are registered in strictly alphabetical order.
- lib.clang_annotateTokens.argtype = [TranslationUnit, POINTER(Token),
- c_uint, POINTER(Cursor)]
-
- lib.clang_CompilationDatabase_dispose.argtypes = [c_object_p]
-
- lib.clang_CompilationDatabase_fromDirectory.argtypes = [c_char_p,
- POINTER(c_uint)]
- lib.clang_CompilationDatabase_fromDirectory.restype = c_object_p
- lib.clang_CompilationDatabase_fromDirectory.errcheck = CompilationDatabase.from_result
-
- lib.clang_CompilationDatabase_getCompileCommands.argtypes = [c_object_p, c_char_p]
- lib.clang_CompilationDatabase_getCompileCommands.restype = c_object_p
- lib.clang_CompilationDatabase_getCompileCommands.errcheck = CompileCommands.from_result
-
- lib.clang_CompileCommands_dispose.argtypes = [c_object_p]
-
- lib.clang_CompileCommands_getCommand.argtypes = [c_object_p, c_uint]
- lib.clang_CompileCommands_getCommand.restype = c_object_p
-
- lib.clang_CompileCommands_getSize.argtypes = [c_object_p]
- lib.clang_CompileCommands_getSize.restype = c_uint
-
- lib.clang_CompileCommand_getArg.argtypes = [c_object_p, c_uint]
- lib.clang_CompileCommand_getArg.restype = _CXString
- lib.clang_CompileCommand_getArg.errcheck = _CXString.from_result
-
- lib.clang_CompileCommand_getDirectory.argtypes = [c_object_p]
- lib.clang_CompileCommand_getDirectory.restype = _CXString
- lib.clang_CompileCommand_getDirectory.errcheck = _CXString.from_result
-
- lib.clang_CompileCommand_getNumArgs.argtypes = [c_object_p]
- lib.clang_CompileCommand_getNumArgs.restype = c_uint
-
- lib.clang_codeCompleteAt.argtypes = [TranslationUnit, c_char_p, c_int,
- c_int, c_void_p, c_int, c_int]
- lib.clang_codeCompleteAt.restype = POINTER(CCRStructure)
-
- lib.clang_codeCompleteGetDiagnostic.argtypes = [CodeCompletionResults,
- c_int]
- lib.clang_codeCompleteGetDiagnostic.restype = Diagnostic
-
- lib.clang_codeCompleteGetNumDiagnostics.argtypes = [CodeCompletionResults]
- lib.clang_codeCompleteGetNumDiagnostics.restype = c_int
-
- lib.clang_createIndex.argtypes = [c_int, c_int]
- lib.clang_createIndex.restype = c_object_p
-
- lib.clang_createTranslationUnit.argtypes = [Index, c_char_p]
- lib.clang_createTranslationUnit.restype = c_object_p
-
- lib.clang_CXXMethod_isStatic.argtypes = [Cursor]
- lib.clang_CXXMethod_isStatic.restype = bool
-
- lib.clang_CXXMethod_isVirtual.argtypes = [Cursor]
- lib.clang_CXXMethod_isVirtual.restype = bool
-
- lib.clang_defaultSaveOptions.argtypes = [TranslationUnit]
- lib.clang_defaultSaveOptions.restype = c_uint
-
- lib.clang_disposeCodeCompleteResults.argtypes = [CodeCompletionResults]
-
- #lib.clang_disposeCXTUResourceUsage.argtypes = [CXTUResourceUsage]
-
- lib.clang_disposeDiagnostic.argtypes = [Diagnostic]
-
- lib.clang_disposeIndex.argtypes = [Index]
-
- lib.clang_disposeString.argtypes = [_CXString]
-
- lib.clang_disposeTokens.argtype = [TranslationUnit, POINTER(Token), c_uint]
-
- lib.clang_disposeTranslationUnit.argtypes = [TranslationUnit]
-
- lib.clang_equalCursors.argtypes = [Cursor, Cursor]
- lib.clang_equalCursors.restype = bool
-
- lib.clang_equalLocations.argtypes = [SourceLocation, SourceLocation]
- lib.clang_equalLocations.restype = bool
-
- lib.clang_equalRanges.argtypes = [SourceRange, SourceRange]
- lib.clang_equalRanges.restype = bool
-
- lib.clang_equalTypes.argtypes = [Type, Type]
- lib.clang_equalTypes.restype = bool
-
- lib.clang_getArgType.argtypes = [Type, c_uint]
- lib.clang_getArgType.restype = Type
- lib.clang_getArgType.errcheck = Type.from_result
-
- lib.clang_getArrayElementType.argtypes = [Type]
- lib.clang_getArrayElementType.restype = Type
- lib.clang_getArrayElementType.errcheck = Type.from_result
-
- lib.clang_getArraySize.argtypes = [Type]
- lib.clang_getArraySize.restype = c_longlong
-
- lib.clang_getCanonicalCursor.argtypes = [Cursor]
- lib.clang_getCanonicalCursor.restype = Cursor
- lib.clang_getCanonicalCursor.errcheck = Cursor.from_cursor_result
+# Functions strictly alphabetical order.
+functionList = [
+ ("clang_annotateTokens",
+ [TranslationUnit, POINTER(Token), c_uint, POINTER(Cursor)]),
- lib.clang_getCanonicalType.argtypes = [Type]
- lib.clang_getCanonicalType.restype = Type
- lib.clang_getCanonicalType.errcheck = Type.from_result
+ ("clang_CompilationDatabase_dispose",
+ [c_object_p]),
- lib.clang_getCompletionAvailability.argtypes = [c_void_p]
- lib.clang_getCompletionAvailability.restype = c_int
+ ("clang_CompilationDatabase_fromDirectory",
+ [c_char_p, POINTER(c_uint)],
+ c_object_p,
+ CompilationDatabase.from_result),
- lib.clang_getCompletionChunkCompletionString.argtypes = [c_void_p, c_int]
- lib.clang_getCompletionChunkCompletionString.restype = c_object_p
+ ("clang_CompilationDatabase_getCompileCommands",
+ [c_object_p, c_char_p],
+ c_object_p,
+ CompileCommands.from_result),
- lib.clang_getCompletionChunkKind.argtypes = [c_void_p, c_int]
- lib.clang_getCompletionChunkKind.restype = c_int
+ ("clang_CompileCommands_dispose",
+ [c_object_p]),
- lib.clang_getCompletionChunkText.argtypes = [c_void_p, c_int]
- lib.clang_getCompletionChunkText.restype = _CXString
+ ("clang_CompileCommands_getCommand",
+ [c_object_p, c_uint],
+ c_object_p),
- lib.clang_getCompletionPriority.argtypes = [c_void_p]
- lib.clang_getCompletionPriority.restype = c_int
+ ("clang_CompileCommands_getSize",
+ [c_object_p],
+ c_uint),
- lib.clang_getCString.argtypes = [_CXString]
- lib.clang_getCString.restype = c_char_p
+ ("clang_CompileCommand_getArg",
+ [c_object_p, c_uint],
+ _CXString,
+ _CXString.from_result),
- lib.clang_getCursor.argtypes = [TranslationUnit, SourceLocation]
- lib.clang_getCursor.restype = Cursor
+ ("clang_CompileCommand_getDirectory",
+ [c_object_p],
+ _CXString,
+ _CXString.from_result),
- lib.clang_getCursorDefinition.argtypes = [Cursor]
- lib.clang_getCursorDefinition.restype = Cursor
- lib.clang_getCursorDefinition.errcheck = Cursor.from_result
+ ("clang_CompileCommand_getNumArgs",
+ [c_object_p],
+ c_uint),
- lib.clang_getCursorDisplayName.argtypes = [Cursor]
- lib.clang_getCursorDisplayName.restype = _CXString
- lib.clang_getCursorDisplayName.errcheck = _CXString.from_result
+ ("clang_codeCompleteAt",
+ [TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int],
+ POINTER(CCRStructure)),
- lib.clang_getCursorExtent.argtypes = [Cursor]
- lib.clang_getCursorExtent.restype = SourceRange
+ ("clang_codeCompleteGetDiagnostic",
+ [CodeCompletionResults, c_int],
+ Diagnostic),
- lib.clang_getCursorLexicalParent.argtypes = [Cursor]
- lib.clang_getCursorLexicalParent.restype = Cursor
- lib.clang_getCursorLexicalParent.errcheck = Cursor.from_cursor_result
+ ("clang_codeCompleteGetNumDiagnostics",
+ [CodeCompletionResults],
+ c_int),
- lib.clang_getCursorLocation.argtypes = [Cursor]
- lib.clang_getCursorLocation.restype = SourceLocation
+ ("clang_createIndex",
+ [c_int, c_int],
+ c_object_p),
- lib.clang_getCursorReferenced.argtypes = [Cursor]
- lib.clang_getCursorReferenced.restype = Cursor
- lib.clang_getCursorReferenced.errcheck = Cursor.from_result
+ ("clang_createTranslationUnit",
+ [Index, c_char_p],
+ c_object_p),
- lib.clang_getCursorReferenceNameRange.argtypes = [Cursor, c_uint, c_uint]
- lib.clang_getCursorReferenceNameRange.restype = SourceRange
+ ("clang_CXXMethod_isStatic",
+ [Cursor],
+ bool),
- lib.clang_getCursorSemanticParent.argtypes = [Cursor]
- lib.clang_getCursorSemanticParent.restype = Cursor
- lib.clang_getCursorSemanticParent.errcheck = Cursor.from_cursor_result
+ ("clang_CXXMethod_isVirtual",
+ [Cursor],
+ bool),
- lib.clang_getCursorSpelling.argtypes = [Cursor]
- lib.clang_getCursorSpelling.restype = _CXString
- lib.clang_getCursorSpelling.errcheck = _CXString.from_result
+ ("clang_defaultSaveOptions",
+ [TranslationUnit],
+ c_uint),
- lib.clang_getCursorType.argtypes = [Cursor]
- lib.clang_getCursorType.restype = Type
- lib.clang_getCursorType.errcheck = Type.from_result
+ ("clang_disposeCodeCompleteResults",
+ [CodeCompletionResults]),
- lib.clang_getCursorUSR.argtypes = [Cursor]
- lib.clang_getCursorUSR.restype = _CXString
- lib.clang_getCursorUSR.errcheck = _CXString.from_result
+# ("clang_disposeCXTUResourceUsage",
+# [CXTUResourceUsage]),
- #lib.clang_getCXTUResourceUsage.argtypes = [TranslationUnit]
- #lib.clang_getCXTUResourceUsage.restype = CXTUResourceUsage
+ ("clang_disposeDiagnostic",
+ [Diagnostic]),
- lib.clang_getCXXAccessSpecifier.argtypes = [Cursor]
- lib.clang_getCXXAccessSpecifier.restype = c_uint
+ ("clang_disposeIndex",
+ [Index]),
- lib.clang_getDeclObjCTypeEncoding.argtypes = [Cursor]
- lib.clang_getDeclObjCTypeEncoding.restype = _CXString
- lib.clang_getDeclObjCTypeEncoding.errcheck = _CXString.from_result
+ ("clang_disposeString",
+ [_CXString]),
- lib.clang_getDiagnostic.argtypes = [c_object_p, c_uint]
- lib.clang_getDiagnostic.restype = c_object_p
+ ("clang_disposeTokens",
+ [TranslationUnit, POINTER(Token), c_uint]),
- lib.clang_getDiagnosticCategory.argtypes = [Diagnostic]
- lib.clang_getDiagnosticCategory.restype = c_uint
+ ("clang_disposeTranslationUnit",
+ [TranslationUnit]),
- lib.clang_getDiagnosticCategoryName.argtypes = [c_uint]
- lib.clang_getDiagnosticCategoryName.restype = _CXString
- lib.clang_getDiagnosticCategoryName.errcheck = _CXString.from_result
+ ("clang_equalCursors",
+ [Cursor, Cursor],
+ bool),
- lib.clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint,
- POINTER(SourceRange)]
- lib.clang_getDiagnosticFixIt.restype = _CXString
- lib.clang_getDiagnosticFixIt.errcheck = _CXString.from_result
+ ("clang_equalLocations",
+ [SourceLocation, SourceLocation],
+ bool),
+
+ ("clang_equalRanges",
+ [SourceRange, SourceRange],
+ bool),
+
+ ("clang_equalTypes",
+ [Type, Type],
+ bool),
+
+ ("clang_getArgType",
+ [Type, c_uint],
+ Type,
+ Type.from_result),
+
+ ("clang_getArrayElementType",
+ [Type],
+ Type,
+ Type.from_result),
+
+ ("clang_getArraySize",
+ [Type],
+ c_longlong),
+
+ ("clang_getCanonicalCursor",
+ [Cursor],
+ Cursor,
+ Cursor.from_cursor_result),
+
+ ("clang_getCanonicalType",
+ [Type],
+ Type,
+ Type.from_result),
+
+ ("clang_getCompletionAvailability",
+ [c_void_p],
+ c_int),
+
+ ("clang_getCompletionBriefComment",
+ [c_void_p],
+ _CXString),
+
+ ("clang_getCompletionChunkCompletionString",
+ [c_void_p, c_int],
+ c_object_p),
+
+ ("clang_getCompletionChunkKind",
+ [c_void_p, c_int],
+ c_int),
+
+ ("clang_getCompletionChunkText",
+ [c_void_p, c_int],
+ _CXString),
+
+ ("clang_getCompletionPriority",
+ [c_void_p],
+ c_int),
+
+ ("clang_getCString",
+ [_CXString],
+ c_char_p),
+
+ ("clang_getCursor",
+ [TranslationUnit, SourceLocation],
+ Cursor),
+
+ ("clang_getCursorDefinition",
+ [Cursor],
+ Cursor,
+ Cursor.from_result),
+
+ ("clang_getCursorDisplayName",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getCursorExtent",
+ [Cursor],
+ SourceRange),
+
+ ("clang_getCursorLexicalParent",
+ [Cursor],
+ Cursor,
+ Cursor.from_cursor_result),
+
+ ("clang_getCursorLocation",
+ [Cursor],
+ SourceLocation),
+
+ ("clang_getCursorReferenced",
+ [Cursor],
+ Cursor,
+ Cursor.from_result),
+
+ ("clang_getCursorReferenceNameRange",
+ [Cursor, c_uint, c_uint],
+ SourceRange),
+
+ ("clang_getCursorSemanticParent",
+ [Cursor],
+ Cursor,
+ Cursor.from_cursor_result),
+
+ ("clang_getCursorSpelling",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getCursorType",
+ [Cursor],
+ Type,
+ Type.from_result),
+
+ ("clang_getCursorUSR",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
+# ("clang_getCXTUResourceUsage",
+# [TranslationUnit],
+# CXTUResourceUsage),
+
+ ("clang_getCXXAccessSpecifier",
+ [Cursor],
+ c_uint),
+
+ ("clang_getDeclObjCTypeEncoding",
+ [Cursor],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getDiagnostic",
+ [c_object_p, c_uint],
+ c_object_p),
+
+ ("clang_getDiagnosticCategory",
+ [Diagnostic],
+ c_uint),
+
+ ("clang_getDiagnosticCategoryName",
+ [c_uint],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getDiagnosticFixIt",
+ [Diagnostic, c_uint, POINTER(SourceRange)],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getDiagnosticLocation",
+ [Diagnostic],
+ SourceLocation),
+
+ ("clang_getDiagnosticNumFixIts",
+ [Diagnostic],
+ c_uint),
+
+ ("clang_getDiagnosticNumRanges",
+ [Diagnostic],
+ c_uint),
+
+ ("clang_getDiagnosticOption",
+ [Diagnostic, POINTER(_CXString)],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getDiagnosticRange",
+ [Diagnostic, c_uint],
+ SourceRange),
+
+ ("clang_getDiagnosticSeverity",
+ [Diagnostic],
+ c_int),
+
+ ("clang_getDiagnosticSpelling",
+ [Diagnostic],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getElementType",
+ [Type],
+ Type,
+ Type.from_result),
+
+ ("clang_getEnumConstantDeclUnsignedValue",
+ [Cursor],
+ c_ulonglong),
+
+ ("clang_getEnumConstantDeclValue",
+ [Cursor],
+ c_longlong),
+
+ ("clang_getEnumDeclIntegerType",
+ [Cursor],
+ Type,
+ Type.from_result),
+
+ ("clang_getFile",
+ [TranslationUnit, c_char_p],
+ c_object_p),
+
+ ("clang_getFileName",
+ [File],
+ _CXString), # TODO go through _CXString.from_result?
+
+ ("clang_getFileTime",
+ [File],
+ c_uint),
+
+ ("clang_getIBOutletCollectionType",
+ [Cursor],
+ Type,
+ Type.from_result),
+
+ ("clang_getIncludedFile",
+ [Cursor],
+ File,
+ File.from_cursor_result),
+
+ ("clang_getInclusions",
+ [TranslationUnit, callbacks['translation_unit_includes'], py_object]),
+
+ ("clang_getInstantiationLocation",
+ [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint),
+ POINTER(c_uint)]),
+
+ ("clang_getLocation",
+ [TranslationUnit, File, c_uint, c_uint],
+ SourceLocation),
+
+ ("clang_getLocationForOffset",
+ [TranslationUnit, File, c_uint],
+ SourceLocation),
+
+ ("clang_getNullCursor",
+ None,
+ Cursor),
+
+ ("clang_getNumArgTypes",
+ [Type],
+ c_uint),
+
+ ("clang_getNumCompletionChunks",
+ [c_void_p],
+ c_int),
+
+ ("clang_getNumDiagnostics",
+ [c_object_p],
+ c_uint),
+
+ ("clang_getNumElements",
+ [Type],
+ c_longlong),
+
+ ("clang_getNumOverloadedDecls",
+ [Cursor],
+ c_uint),
+
+ ("clang_getOverloadedDecl",
+ [Cursor, c_uint],
+ Cursor,
+ Cursor.from_cursor_result),
+
+ ("clang_getPointeeType",
+ [Type],
+ Type,
+ Type.from_result),
+
+ ("clang_getRange",
+ [SourceLocation, SourceLocation],
+ SourceRange),
+
+ ("clang_getRangeEnd",
+ [SourceRange],
+ SourceLocation),
+
+ ("clang_getRangeStart",
+ [SourceRange],
+ SourceLocation),
+
+ ("clang_getResultType",
+ [Type],
+ Type,
+ Type.from_result),
+
+ ("clang_getSpecializedCursorTemplate",
+ [Cursor],
+ Cursor,
+ Cursor.from_cursor_result),
+
+ ("clang_getTemplateCursorKind",
+ [Cursor],
+ c_uint),
+
+ ("clang_getTokenExtent",
+ [TranslationUnit, Token],
+ SourceRange),
+
+ ("clang_getTokenKind",
+ [Token],
+ c_uint),
+
+ ("clang_getTokenLocation",
+ [TranslationUnit, Token],
+ SourceLocation),
+
+ ("clang_getTokenSpelling",
+ [TranslationUnit, Token],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getTranslationUnitCursor",
+ [TranslationUnit],
+ Cursor,
+ Cursor.from_result),
+
+ ("clang_getTranslationUnitSpelling",
+ [TranslationUnit],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_getTUResourceUsageName",
+ [c_uint],
+ c_char_p),
+
+ ("clang_getTypeDeclaration",
+ [Type],
+ Cursor,
+ Cursor.from_result),
+
+ ("clang_getTypedefDeclUnderlyingType",
+ [Cursor],
+ Type,
+ Type.from_result),
+
+ ("clang_getTypeKindSpelling",
+ [c_uint],
+ _CXString,
+ _CXString.from_result),
+
+ ("clang_hashCursor",
+ [Cursor],
+ c_uint),
+
+ ("clang_isAttribute",
+ [CursorKind],
+ bool),
+
+ ("clang_isConstQualifiedType",
+ [Type],
+ bool),
+
+ ("clang_isCursorDefinition",
+ [Cursor],
+ bool),
+
+ ("clang_isDeclaration",
+ [CursorKind],
+ bool),
+
+ ("clang_isExpression",
+ [CursorKind],
+ bool),
+
+ ("clang_isFileMultipleIncludeGuarded",
+ [TranslationUnit, File],
+ bool),
+
+ ("clang_isFunctionTypeVariadic",
+ [Type],
+ bool),
+
+ ("clang_isInvalid",
+ [CursorKind],
+ bool),
+
+ ("clang_isPODType",
+ [Type],
+ bool),
+
+ ("clang_isPreprocessing",
+ [CursorKind],
+ bool),
+
+ ("clang_isReference",
+ [CursorKind],
+ bool),
+
+ ("clang_isRestrictQualifiedType",
+ [Type],
+ bool),
+
+ ("clang_isStatement",
+ [CursorKind],
+ bool),
+
+ ("clang_isTranslationUnit",
+ [CursorKind],
+ bool),
+
+ ("clang_isUnexposed",
+ [CursorKind],
+ bool),
+
+ ("clang_isVirtualBase",
+ [Cursor],
+ bool),
+
+ ("clang_isVolatileQualifiedType",
+ [Type],
+ bool),
+
+ ("clang_parseTranslationUnit",
+ [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int],
+ c_object_p),
+
+ ("clang_reparseTranslationUnit",
+ [TranslationUnit, c_int, c_void_p, c_int],
+ c_int),
+
+ ("clang_saveTranslationUnit",
+ [TranslationUnit, c_char_p, c_uint],
+ c_int),
+
+ ("clang_tokenize",
+ [TranslationUnit, SourceRange, POINTER(POINTER(Token)), POINTER(c_uint)]),
+
+ ("clang_visitChildren",
+ [Cursor, callbacks['cursor_visit'], py_object],
+ c_uint),
+
+ ("clang_Cursor_getNumArguments",
+ [Cursor],
+ c_int),
- lib.clang_getDiagnosticLocation.argtypes = [Diagnostic]
- lib.clang_getDiagnosticLocation.restype = SourceLocation
-
- lib.clang_getDiagnosticNumFixIts.argtypes = [Diagnostic]
- lib.clang_getDiagnosticNumFixIts.restype = c_uint
-
- lib.clang_getDiagnosticNumRanges.argtypes = [Diagnostic]
- lib.clang_getDiagnosticNumRanges.restype = c_uint
-
- lib.clang_getDiagnosticOption.argtypes = [Diagnostic, POINTER(_CXString)]
- lib.clang_getDiagnosticOption.restype = _CXString
- lib.clang_getDiagnosticOption.errcheck = _CXString.from_result
-
- lib.clang_getDiagnosticRange.argtypes = [Diagnostic, c_uint]
- lib.clang_getDiagnosticRange.restype = SourceRange
-
- lib.clang_getDiagnosticSeverity.argtypes = [Diagnostic]
- lib.clang_getDiagnosticSeverity.restype = c_int
-
- lib.clang_getDiagnosticSpelling.argtypes = [Diagnostic]
- lib.clang_getDiagnosticSpelling.restype = _CXString
- lib.clang_getDiagnosticSpelling.errcheck = _CXString.from_result
-
- lib.clang_getElementType.argtypes = [Type]
- lib.clang_getElementType.restype = Type
- lib.clang_getElementType.errcheck = Type.from_result
-
- lib.clang_getEnumConstantDeclUnsignedValue.argtypes = [Cursor]
- lib.clang_getEnumConstantDeclUnsignedValue.restype = c_ulonglong
-
- lib.clang_getEnumConstantDeclValue.argtypes = [Cursor]
- lib.clang_getEnumConstantDeclValue.restype = c_longlong
-
- lib.clang_getEnumDeclIntegerType.argtypes = [Cursor]
- lib.clang_getEnumDeclIntegerType.restype = Type
- lib.clang_getEnumDeclIntegerType.errcheck = Type.from_result
-
- lib.clang_getFile.argtypes = [TranslationUnit, c_char_p]
- lib.clang_getFile.restype = c_object_p
-
- lib.clang_getFileName.argtypes = [File]
- lib.clang_getFileName.restype = _CXString
- # TODO go through _CXString.from_result?
-
- lib.clang_getFileTime.argtypes = [File]
- lib.clang_getFileTime.restype = c_uint
-
- lib.clang_getIBOutletCollectionType.argtypes = [Cursor]
- lib.clang_getIBOutletCollectionType.restype = Type
- lib.clang_getIBOutletCollectionType.errcheck = Type.from_result
-
- lib.clang_getIncludedFile.argtypes = [Cursor]
- lib.clang_getIncludedFile.restype = File
- lib.clang_getIncludedFile.errcheck = File.from_cursor_result
-
- lib.clang_getInclusions.argtypes = [TranslationUnit,
- callbacks['translation_unit_includes'], py_object]
-
- lib.clang_getInstantiationLocation.argtypes = [SourceLocation,
- POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]
-
- lib.clang_getLocation.argtypes = [TranslationUnit, File, c_uint, c_uint]
- lib.clang_getLocation.restype = SourceLocation
-
- lib.clang_getLocationForOffset.argtypes = [TranslationUnit, File, c_uint]
- lib.clang_getLocationForOffset.restype = SourceLocation
-
- lib.clang_getNullCursor.restype = Cursor
-
- lib.clang_getNumArgTypes.argtypes = [Type]
- lib.clang_getNumArgTypes.restype = c_uint
-
- lib.clang_getNumCompletionChunks.argtypes = [c_void_p]
- lib.clang_getNumCompletionChunks.restype = c_int
-
- lib.clang_getNumDiagnostics.argtypes = [c_object_p]
- lib.clang_getNumDiagnostics.restype = c_uint
-
- lib.clang_getNumElements.argtypes = [Type]
- lib.clang_getNumElements.restype = c_longlong
-
- lib.clang_getNumOverloadedDecls.argtypes = [Cursor]
- lib.clang_getNumOverloadedDecls.restyp = c_uint
-
- lib.clang_getOverloadedDecl.argtypes = [Cursor, c_uint]
- lib.clang_getOverloadedDecl.restype = Cursor
- lib.clang_getOverloadedDecl.errcheck = Cursor.from_cursor_result
-
- lib.clang_getPointeeType.argtypes = [Type]
- lib.clang_getPointeeType.restype = Type
- lib.clang_getPointeeType.errcheck = Type.from_result
-
- lib.clang_getRange.argtypes = [SourceLocation, SourceLocation]
- lib.clang_getRange.restype = SourceRange
-
- lib.clang_getRangeEnd.argtypes = [SourceRange]
- lib.clang_getRangeEnd.restype = SourceLocation
-
- lib.clang_getRangeStart.argtypes = [SourceRange]
- lib.clang_getRangeStart.restype = SourceLocation
-
- lib.clang_getResultType.argtypes = [Type]
- lib.clang_getResultType.restype = Type
- lib.clang_getResultType.errcheck = Type.from_result
-
- lib.clang_getSpecializedCursorTemplate.argtypes = [Cursor]
- lib.clang_getSpecializedCursorTemplate.restype = Cursor
- lib.clang_getSpecializedCursorTemplate.errcheck = Cursor.from_cursor_result
-
- lib.clang_getTemplateCursorKind.argtypes = [Cursor]
- lib.clang_getTemplateCursorKind.restype = c_uint
-
- lib.clang_getTokenExtent.argtypes = [TranslationUnit, Token]
- lib.clang_getTokenExtent.restype = SourceRange
-
- lib.clang_getTokenKind.argtypes = [Token]
- lib.clang_getTokenKind.restype = c_uint
-
- lib.clang_getTokenLocation.argtype = [TranslationUnit, Token]
- lib.clang_getTokenLocation.restype = SourceLocation
-
- lib.clang_getTokenSpelling.argtype = [TranslationUnit, Token]
- lib.clang_getTokenSpelling.restype = _CXString
- lib.clang_getTokenSpelling.errcheck = _CXString.from_result
-
- lib.clang_getTranslationUnitCursor.argtypes = [TranslationUnit]
- lib.clang_getTranslationUnitCursor.restype = Cursor
- lib.clang_getTranslationUnitCursor.errcheck = Cursor.from_result
-
- lib.clang_getTranslationUnitSpelling.argtypes = [TranslationUnit]
- lib.clang_getTranslationUnitSpelling.restype = _CXString
- lib.clang_getTranslationUnitSpelling.errcheck = _CXString.from_result
-
- lib.clang_getTUResourceUsageName.argtypes = [c_uint]
- lib.clang_getTUResourceUsageName.restype = c_char_p
-
- lib.clang_getTypeDeclaration.argtypes = [Type]
- lib.clang_getTypeDeclaration.restype = Cursor
- lib.clang_getTypeDeclaration.errcheck = Cursor.from_result
-
- lib.clang_getTypedefDeclUnderlyingType.argtypes = [Cursor]
- lib.clang_getTypedefDeclUnderlyingType.restype = Type
- lib.clang_getTypedefDeclUnderlyingType.errcheck = Type.from_result
-
- lib.clang_getTypeKindSpelling.argtypes = [c_uint]
- lib.clang_getTypeKindSpelling.restype = _CXString
- lib.clang_getTypeKindSpelling.errcheck = _CXString.from_result
-
- lib.clang_hashCursor.argtypes = [Cursor]
- lib.clang_hashCursor.restype = c_uint
-
- lib.clang_isAttribute.argtypes = [CursorKind]
- lib.clang_isAttribute.restype = bool
-
- lib.clang_isConstQualifiedType.argtypes = [Type]
- lib.clang_isConstQualifiedType.restype = bool
+ ("clang_Cursor_getArgument",
+ [Cursor, c_uint],
+ Cursor,
+ Cursor.from_result),
+]
- lib.clang_isCursorDefinition.argtypes = [Cursor]
- lib.clang_isCursorDefinition.restype = bool
+class LibclangError(Exception):
+ def __init__(self, message):
+ self.m = message
- lib.clang_isDeclaration.argtypes = [CursorKind]
- lib.clang_isDeclaration.restype = bool
+ def __str__(self):
+ return self.m
+
+def register_function(lib, item, ignore_errors):
+ # A function may not exist, if these bindings are used with an older or
+ # incompatible version of libclang.so.
+ try:
+ func = getattr(lib, item[0])
+ except AttributeError as e:
+ msg = str(e) + ". Please ensure that your python bindings are "\
+ "compatible with your libclang.so version."
+ if ignore_errors:
+ return
+ raise LibclangError(msg)
- lib.clang_isExpression.argtypes = [CursorKind]
- lib.clang_isExpression.restype = bool
+ if len(item) >= 2:
+ func.argtypes = item[1]
- lib.clang_isFileMultipleIncludeGuarded.argtypes = [TranslationUnit, File]
- lib.clang_isFileMultipleIncludeGuarded.restype = bool
+ if len(item) >= 3:
+ func.restype = item[2]
- lib.clang_isFunctionTypeVariadic.argtypes = [Type]
- lib.clang_isFunctionTypeVariadic.restype = bool
+ if len(item) == 4:
+ func.errcheck = item[3]
- lib.clang_isInvalid.argtypes = [CursorKind]
- lib.clang_isInvalid.restype = bool
+def register_functions(lib, ignore_errors):
+ """Register function prototypes with a libclang library instance.
- lib.clang_isPODType.argtypes = [Type]
- lib.clang_isPODType.restype = bool
+ This must be called as part of library instantiation so Python knows how
+ to call out to the shared library.
+ """
- lib.clang_isPreprocessing.argtypes = [CursorKind]
- lib.clang_isPreprocessing.restype = bool
+ def register(item):
+ return register_function(lib, item, ignore_errors)
- lib.clang_isReference.argtypes = [CursorKind]
- lib.clang_isReference.restype = bool
+ map(register, functionList)
- lib.clang_isRestrictQualifiedType.argtypes = [Type]
- lib.clang_isRestrictQualifiedType.restype = bool
+class Config:
+ library_path = None
+ library_file = None
+ compatibility_check = True
+ loaded = False
- lib.clang_isStatement.argtypes = [CursorKind]
- lib.clang_isStatement.restype = bool
+ @staticmethod
+ def set_library_path(path):
+ """Set the path in which to search for libclang"""
+ if Config.loaded:
+ raise Exception("library path must be set before before using " \
+ "any other functionalities in libclang.")
- lib.clang_isTranslationUnit.argtypes = [CursorKind]
- lib.clang_isTranslationUnit.restype = bool
+ Config.library_path = path
- lib.clang_isUnexposed.argtypes = [CursorKind]
- lib.clang_isUnexposed.restype = bool
+ @staticmethod
+ def set_library_file(file):
+ """Set the exact location of libclang from"""
+ if Config.loaded:
+ raise Exception("library file must be set before before using " \
+ "any other functionalities in libclang.")
- lib.clang_isVirtualBase.argtypes = [Cursor]
- lib.clang_isVirtualBase.restype = bool
+ Config.library_file = path
- lib.clang_isVolatileQualifiedType.argtypes = [Type]
- lib.clang_isVolatileQualifiedType.restype = bool
+ @staticmethod
+ def set_compatibility_check(check_status):
+ """ Perform compatibility check when loading libclang
+
+ The python bindings are only tested and evaluated with the version of
+ libclang they are provided with. To ensure correct behavior a (limited)
+ compatibility check is performed when loading the bindings. This check
+ will throw an exception, as soon as it fails.
+
+ In case these bindings are used with an older version of libclang, parts
+ that have been stable between releases may still work. Users of the
+ python bindings can disable the compatibility check. This will cause
+ the python bindings to load, even though they are written for a newer
+ version of libclang. Failures now arise if unsupported or incompatible
+ features are accessed. The user is required to test himself if the
+ features he is using are available and compatible between different
+ libclang versions.
+ """
+ if Config.loaded:
+ raise Exception("compatibility_check must be set before before " \
+ "using any other functionalities in libclang.")
+
+ Config.compatibility_check = check_status
+
+ @CachedProperty
+ def lib(self):
+ lib = self.get_cindex_library()
+ register_functions(lib, not Config.compatibility_check)
+ Config.loaded = True
+ return lib
+
+ def get_filename(self):
+ if Config.library_file:
+ return Config.library_file
+
+ import platform
+ name = platform.system()
+
+ if name == 'Darwin':
+ file = 'libclang.dylib'
+ elif name == 'Windows':
+ file = 'libclang.dll'
+ else:
+ file = 'libclang.so'
- lib.clang_parseTranslationUnit.argypes = [Index, c_char_p, c_void_p, c_int,
- c_void_p, c_int, c_int]
- lib.clang_parseTranslationUnit.restype = c_object_p
+ if Config.library_path:
+ file = Config.library_path + '/' + file
- lib.clang_reparseTranslationUnit.argtypes = [TranslationUnit, c_int,
- c_void_p, c_int]
- lib.clang_reparseTranslationUnit.restype = c_int
+ return file
- lib.clang_saveTranslationUnit.argtypes = [TranslationUnit, c_char_p,
- c_uint]
- lib.clang_saveTranslationUnit.restype = c_int
+ def get_cindex_library(self):
+ try:
+ library = cdll.LoadLibrary(self.get_filename())
+ except OSError as e:
+ msg = str(e) + ". To provide a path to libclang use " \
+ "Config.set_library_path() or " \
+ "Config.set_library_file()."
+ raise LibclangError(msg)
- lib.clang_tokenize.argtypes = [TranslationUnit, SourceRange,
- POINTER(POINTER(Token)), POINTER(c_uint)]
+ return library
- lib.clang_visitChildren.argtypes = [Cursor, callbacks['cursor_visit'],
- py_object]
- lib.clang_visitChildren.restype = c_uint
+ def function_exists(self, name):
+ try:
+ getattr(self.lib, name)
+ except AttributeError:
+ return False
-register_functions(lib)
+ return True
def register_enumerations():
for name, value in clang.enumerations.TokenKinds:
TokenKind.register(value, name)
+conf = Config()
register_enumerations()
__all__ = [
+ 'Config',
'CodeCompletionResults',
'CompilationDatabase',
'CompileCommands',
diff --git a/bindings/python/tests/cindex/test_code_completion.py b/bindings/python/tests/cindex/test_code_completion.py
new file mode 100644
index 000000000000..357d50db5131
--- /dev/null
+++ b/bindings/python/tests/cindex/test_code_completion.py
@@ -0,0 +1,75 @@
+from clang.cindex import TranslationUnit
+
+def check_completion_results(cr, expected):
+ assert cr is not None
+ assert len(cr.diagnostics) == 0
+
+ completions = [str(c) for c in cr.results]
+
+ for c in expected:
+ assert c in completions
+
+def test_code_complete():
+ files = [('fake.c', """
+/// Aaa.
+int test1;
+
+/// Bbb.
+void test2(void);
+
+void f() {
+
+}
+""")]
+
+ tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
+ options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
+
+ cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
+
+ expected = [
+ "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
+ "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
+ "{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
+
+def test_code_complete_availability():
+ files = [('fake.cpp', """
+class P {
+protected:
+ int member;
+};
+
+class Q : public P {
+public:
+ using P::member;
+};
+
+void f(P x, Q y) {
+ x.; // member is inaccessible
+ y.; // member is accessible
+}
+""")]
+
+ tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
+
+ cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
+
+ expected = [
+ "{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
+ "{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
+
+ cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
+ expected = [
+ "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
+ "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
+ "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
+ "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index 51695e20b0c7..edb209b52b96 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -241,3 +241,12 @@ def test_get_tokens():
assert len(tokens) == 7
assert tokens[0].spelling == 'int'
assert tokens[1].spelling == 'foo'
+
+def test_get_arguments():
+ tu = get_tu('void foo(int i, int j);')
+ foo = get_cursor(tu, 'foo')
+ arguments = list(foo.get_arguments())
+
+ assert len(arguments) == 2
+ assert arguments[0].spelling == "i"
+ assert arguments[1].spelling == "j"
diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng
index a0329f8c3d7b..d98f405cf9e7 100644
--- a/bindings/xml/comment-xml-schema.rng
+++ b/bindings/xml/comment-xml-schema.rng
@@ -25,6 +25,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
<optional>
@@ -71,6 +74,9 @@
</optional>
<!-- TODO: Add exception specification. -->
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
<optional>
@@ -79,6 +85,15 @@
<optional>
<ref name="Parameters" />
</optional>
+ <zeroOrMore>
+ <ref name="Availability" />
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="Deprecated" />
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="Unavailable" />
+ </zeroOrMore>
<optional>
<ref name="ResultDiscussion" />
</optional>
@@ -106,6 +121,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
<optional>
@@ -135,6 +153,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
@@ -165,6 +186,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
@@ -195,6 +219,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
@@ -225,6 +252,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Declaration" />
+ </optional>
+ <optional>
<ref name="Abstract" />
</optional>
@@ -292,11 +322,18 @@
</element>
</define>
+ <define name="Declaration">
+ <element name="Declaration">
+ <!-- Non-empty text content. -->
+ <data type="string"/>
+ </element>
+ </define>
+
<define name="Discussion">
<element name="Discussion">
- <oneOrMore>
+ <zeroOrMore>
<ref name="TextBlockContent" />
- </oneOrMore>
+ </zeroOrMore>
</element>
</define>
@@ -369,6 +406,59 @@
</element>
</define>
+ <define name="Availability">
+ <element name="Availability">
+ <attribute name="distribution">
+ <data type="string" />
+ </attribute>
+ <optional>
+ <element name="IntroducedInVersion">
+ <data type="string">
+ <param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
+ </data>
+ </element>
+ </optional>
+ <optional>
+ <element name="DeprecatedInVersion">
+ <data type="string">
+ <param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
+ </data>
+ </element>
+ </optional>
+ <optional>
+ <element name="RemovedAfterVersion">
+ <data type="string">
+ <param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
+ </data>
+ </element>
+ </optional>
+ <optional>
+ <element name="DeprecationSummary">
+ <data type="string" />
+ </element>
+ </optional>
+ <optional>
+ <ref name="Unavailable" />
+ </optional>
+ </element>
+ </define>
+
+ <define name="Deprecated">
+ <element name="Deprecated">
+ <optional>
+ <data type="string" />
+ </optional>
+ </element>
+ </define>
+
+ <define name="Unavailable">
+ <element name="Unavailable">
+ <optional>
+ <data type="string" />
+ </optional>
+ </element>
+ </define>
+
<define name="ResultDiscussion">
<element name="ResultDiscussion">
<zeroOrMore>
diff --git a/docs/AddressSanitizer.html b/docs/AddressSanitizer.html
index 98ea934d965c..397eafc2d51b 100644
--- a/docs/AddressSanitizer.html
+++ b/docs/AddressSanitizer.html
@@ -45,17 +45,21 @@ The tool can detect the following types of bugs:
Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
<h2 id="howtobuild">How to build</h2>
-Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
-Note: CMake build does not work yet.
-See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
+Follow the <a href="../get_started.html">clang build instructions</a>.
+CMake build is supported.<BR>
<h2 id="usage">Usage</h2>
-Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
+Simply compile and link your program with <tt>-fsanitize=address</tt> flag. <BR>
+The AddressSanitizer run-time library should be linked to the final executable,
+so make sure to use <tt>clang</tt> (not <tt>ld</tt>) for the final link step.<BR>
+When linking shared libraries, the AddressSanitizer run-time is not linked,
+so <tt>-Wl,-z,defs</tt> may cause link errors (don't use it with AddressSanitizer). <BR>
+
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
To get nicer stack traces in error messages add
<tt>-fno-omit-frame-pointer</tt>. <BR>
To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
-elimination (</tt>-fno-optimize-sibling-calls</tt>).
+elimination (<tt>-fno-optimize-sibling-calls</tt>).
<pre>
% cat example_UseAfterFree.cc
@@ -67,7 +71,15 @@ int main(int argc, char **argv) {
</pre>
<pre>
-% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
+# Compile and link
+% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
+</pre>
+OR
+<pre>
+# Compile
+% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
+# Link
+% clang -g -fsanitize=address example_UseAfterFree.o
</pre>
If a bug is detected, the program will print an error message to stderr and exit with a
@@ -93,6 +105,13 @@ previously allocated by thread T0 here:
==9442== ABORTING
</pre>
+AddressSanitizer exits on the first detected error. This is by design.
+One reason: it makes the generated code smaller and faster (both by ~5%).
+Another reason: this makes fixing bugs unavoidable. With Valgrind, it is often
+the case that users treat Valgrind warnings as false positives
+(which they are not) and don't fix them.
+
+
<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
In some cases one may need to execute different code depending on whether
AddressSanitizer is enabled.
@@ -107,8 +126,8 @@ can be used for this purpose.
</pre>
<h3 id="no_address_safety_analysis">__attribute__((no_address_safety_analysis))</h3>
-Some code should not be instrumentated by AddressSanitizer.
-One may use the function attribute
+Some code should not be instrumented by AddressSanitizer.
+One may use the function attribute
<a href="LanguageExtensions.html#address_sanitizer">
<tt>no_address_safety_analysis</tt></a>
to disable instrumentation of a particular function.
@@ -118,18 +137,18 @@ Note: currently, this attribute will be lost if the function is inlined.
<h2 id="platforms">Supported Platforms</h2>
AddressSanitizer is supported on
-<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
-<li>MacOS 10.6 and 10.7 (i386/x86_64).
+<ul><li>Linux i386/x86_64 (tested on Ubuntu 10.04 and 12.04).
+<li>MacOS 10.6, 10.7 and 10.8 (i386/x86_64).
</ul>
-Support for Linux i386/ARM is in progress
+Support for Linux ARM (and Android ARM) is in progress
(it may work, but is not guaranteed too).
<h2 id="limitations">Limitations</h2>
<ul>
<li> AddressSanitizer uses more real memory than a native run.
-How much -- depends on the allocations sizes. The smaller the
-allocations you make the bigger the overhead.
+Exact overhead depends on the allocations sizes. The smaller the
+allocations you make the bigger the overhead is.
<li> AddressSanitizer uses more stack memory. We have seen up to 3x increase.
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
16+ Terabytes of virtual address space.
@@ -140,8 +159,8 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
<h2 id="status">Current Status</h2>
AddressSanitizer is fully functional on supported platforms starting from LLVM 3.1.
-However, the test suite is not fully integrated yet and we lack the testing
-process (buildbots).
+The test suite is integrated into CMake build and can be run with
+<tt>make check-asan</tt> command.
<h2 id="moreinfo">More Information</h2>
<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
index 3f1ccaf672ca..5354f8af3466 100644
--- a/docs/AutomaticReferenceCounting.html
+++ b/docs/AutomaticReferenceCounting.html
@@ -888,6 +888,15 @@ from non-ARC practice was acceptable because we had conservatively
banned the synthesis in order to give ourselves exactly this
leeway.</p></div>
+<p>Applying <tt>__attribute__((NSObject))</tt> to a property not of
+retainable object pointer type has the same behavior it does outside
+of ARC: it requires the property type to be some sort of pointer and
+permits the use of modifiers other than <tt>assign</tt>. These
+modifiers only affect the synthesized getter and setter; direct
+accesses to the ivar (even if synthesized) still have primitive
+semantics, and the value in the ivar will not be automatically
+released during deallocation.</p>
+
</div> <!-- ownership.spelling.property -->
</div> <!-- ownership.spelling -->
@@ -1602,6 +1611,36 @@ implementation must be very careful to do all the other work
that <tt>NSObject</tt>'s <tt>dealloc</tt> would, which is outside the
scope of this document to describe.</p></div>
+<p>The instance variables for an ARC-compiled class will be destroyed
+at some point after control enters the <tt>dealloc</tt> method for the
+root class of the class. The ordering of the destruction of instance
+variables is unspecified, both within a single class and between
+subclasses and superclasses.</p>
+
+<div class="rationale"><p>Rationale: the traditional, non-ARC pattern
+for destroying instance variables is to destroy them immediately
+before calling <tt>[super&nbsp;dealloc]</tt>. Unfortunately, message
+sends from the superclass are quite capable of reaching methods in the
+subclass, and those methods may well read or write to those instance
+variables. Making such message sends from dealloc is generally
+discouraged, since the subclass may well rely on other invariants that
+were broken during <tt>dealloc</tt>, but it's not so inescapably
+dangerous that we felt comfortable calling it undefined behavior.
+Therefore we chose to delay destroying the instance variables to a
+point at which message sends are clearly disallowed: the point at
+which the root class's deallocation routines take over.</p>
+
+<p>In most code, the difference is not observable. It can, however,
+be observed if an instance variable holds a strong reference to an
+object whose deallocation will trigger a side-effect which must be
+carefully ordered with respect to the destruction of the super class.
+Such code violates the design principle that semantically important
+behavior should be explicit. A simple fix is to clear the instance
+variable manually during <tt>dealloc</tt>; a more holistic solution is
+to move semantically important side-effects out of
+<tt>dealloc</tt> and into a separate teardown phase which can rely on
+working with well-formed objects.</p></div>
+
</div>
</div> <!-- misc.special_methods -->
@@ -1865,9 +1904,9 @@ and <tt>cf_unknown_transfer</tt>.</p>
<p>A pragma is provided to facilitate the mass annotation of interfaces:</p>
-<pre>#pragma arc_cf_code_audited begin
+<pre>#pragma clang arc_cf_code_audited begin
...
-#pragma arc_cf_code_audited end</pre>
+#pragma clang arc_cf_code_audited end</pre>
<p>All C functions declared within the extent of this pragma are
treated as if annotated with the <tt>cf_audited_transfer</tt>
diff --git a/docs/BlockLanguageSpec.txt b/docs/BlockLanguageSpec.txt
index f7bbda365184..4cdf75a27871 100644
--- a/docs/BlockLanguageSpec.txt
+++ b/docs/BlockLanguageSpec.txt
@@ -81,6 +81,10 @@ The compound statement body establishes a new lexical scope within that of its p
Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.
+The compiler is not required to capture a variable if it can prove that no references to the variable will actually be evaluated. Programmers can force a variable to be captured by referencing it in a statement at the beginning of the Block, like so:
+ (void) foo;
+This matters when capturing the variable has side-effects, as it can in Objective-C or C++.
+
The lifetime of variables declared in a Block is that of a function; each activation frame contains a new copy of variables declared within the local scope of the Block. Such variable declarations should be allowed anywhere [testme] rather than only when C99 parsing is requested, including for statements. [testme]
Block literal expressions may occur within Block literal expressions (nest) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.
@@ -143,23 +147,25 @@ C++ Extensions
Block literal expressions within functions are extended to allow const use of C++ objects, pointers, or references held in automatic storage.
-For example, given class Foo with member function fighter(void):
+As usual, within the block, references to captured variables become const-qualified, as if they were references to members of a const object. Note that this does not change the type of a variable of reference type.
+
+For example, given a class Foo:
Foo foo;
Foo &fooRef = foo;
Foo *fooPtr = &foo;
-...a Block that used foo would import the variables as const variations:
- const Foo block_foo = foo; // const copy constructor
- const Foo &block_fooRef = fooRef;
- Foo *const block_fooPtr = fooPtr;
+A Block that referenced these variables would import the variables as const variations:
+ const Foo block_foo = foo;
+ Foo &block_fooRef = fooRef;
+ Foo *const block_fooPtr = fooPtr;
-Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression.
+Captured variables are copied into the Block at the instant of evaluating the Block literal expression. They are also copied when calling Block_copy() on a Block allocated on the stack. In both cases, they are copied as if the variable were const-qualified, and it's an error if there's no such constructor.
-If a Block originates on the stack, a const copy constructor of the stack-based Block const copy is performed when a Block_copy operation is called; when the last Block_release (or subsequently GC) occurs, a destructor is run on the heap copy.
+Captured variables in Blocks on the stack are destroyed when control leaves the compound statement that contains the Block literal expression. Captured variables in Blocks on the heap are destroyed when the reference count of the Block drops to zero.
-Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, a normal copy constructor is used to initialize the heap-based version from the original stack version. The destructor for a const copied object is run at the normal end of scope. The destructor for any initial stack based version is also called at normal end of scope.
+Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, __block variables are copied using their normal qualification (i.e. without adding const). In C++11, __block variables are copied as x-values if that is possible, then as l-values if not; if both fail, it's an error. The destructor for any initial stack-based version is called at the variable's normal end of scope.
-Within a member function, access to member functions and variables is done via an implicit const copy of a this pointer.
+References to 'this', as well as references to non-static members of any enclosing class, are evaluated by capturing 'this' just like a normal variable of C pointer type.
Member variables that are Blocks may not be overloaded by the types of their arguments.
diff --git a/docs/ClangTools.html b/docs/ClangTools.html
index 0dfdc6a73701..4de57bd2185d 100644
--- a/docs/ClangTools.html
+++ b/docs/ClangTools.html
@@ -87,22 +87,14 @@ specific functionality.</p>
<h3 id="clang-check"><tt>clang-check</tt></h3>
<p>This tool combines the LibTooling framework for running a Clang tool with the
-basic Clang diagnostics by syntax checking specific files in a fast, command line
-interface. It can also accept flags to re-display the diagnostics in different
-formats with different flags, suitable for use driving an IDE or editor.</p>
+basic Clang diagnostics by syntax checking specific files in a fast, command
+line interface. It can also accept flags to re-display the diagnostics in
+different formats with different flags, suitable for use driving an IDE or
+editor. Furthermore, it can be used in fixit-mode to directly apply fixit-hints
+offered by clang.</p>
<p>FIXME: Link to user-oriented clang-check documentation.</p>
-<h3 id="clang-fixit"><tt>clang-fixit</tt> (Not yet implemented!)</h3>
-<p>A tool which specifically applies the Clang fix-it hint diagnostic technology
-on top of a dedicated tool. It is designed to explore alternative interfaces for
-applying fix-it hints, including automatic application, prompting users with
-options for different fixes, etc.</p>
-
-<p><b>NB:</b> The clang-fixit tool is planned, but not yet implemented.</p>
-
-<p>FIXME: Link to user-oriented clang-fixit documentation.</p>
-
<!-- ======================================================================= -->
<h2 id="registerplugin">Extra Clang Tools</h2>
<!-- ======================================================================= -->
diff --git a/docs/HowToSetupToolingForLLVM.html b/docs/HowToSetupToolingForLLVM.html
index 493c8820fc4f..022ed9ce9cb3 100644
--- a/docs/HowToSetupToolingForLLVM.html
+++ b/docs/HowToSetupToolingForLLVM.html
@@ -77,12 +77,38 @@ $PATH. Try to run it on any .cpp file inside the LLVM source tree:</p>
<p>If you're using vim, it's convenient to have clang-check integrated. Put this
into your .vimrc:</p>
<pre>
- set makeprg=clang-check\ %
- map &lt;F5&gt; :make&lt;CR&gt;&lt;CR&gt;
+function! ClangCheckImpl(cmd)
+ if &amp;autowrite | wall | endif
+ echo "Running " . a:cmd . " ..."
+ let l:output = system(a:cmd)
+ cexpr l:output
+ cwindow
+ let w:quickfix_title = a:cmd
+ if v:shell_error != 0
+ cc
+ endif
+ let g:clang_check_last_cmd = a:cmd
+endfunction
+
+function! ClangCheck()
+ let l:filename = expand('%')
+ if l:filename =~ '\.\(cpp\|cxx\|cc\|c\)$'
+ call ClangCheckImpl("clang-check " . l:filename)
+ elseif exists("g:clang_check_last_cmd")
+ call ClangCheckImpl(g:clang_check_last_cmd)
+ else
+ echo "Can't detect file's compilation arguments and no previous clang-check invocation!"
+ endif
+endfunction
+
+nmap &lt;silent&gt; &lt;F5&gt; :call ClangCheck()&lt;CR&gt;&lt;CR&gt;
</pre>
-<p>When editing C++ code, hit F5 to reparse the current buffer. The output will
-go into the error window, which you can enable with <code>:cope</code>.</p>
+<p>When editing a .cpp/.cxx/.cc/.c file, hit F5 to reparse the file. In case
+the current file has a different extension (for example, .h), F5 will re-run
+the last clang-check invocation made from this vim instance (if any). The
+output will go into the error window, which is opened automatically when
+clang-check finds errors, and can be re-opened with <code>:cope</code>.</p>
<p>Other <code>clang-check</code> options that can be useful when working with
clang AST:</p>
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 3f3e124ae640..57f06316b1b1 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -502,7 +502,9 @@ code, the source ranges, and the caret. However, this behavior isn't required.
Instead of formatting and printing out the diagnostics, this implementation just
captures and remembers the diagnostics as they fly by. Then -verify compares
the list of produced diagnostics to the list of expected ones. If they disagree,
-it prints out its own output.
+it prints out its own output. Full documentation for the -verify mode can be
+found in the Clang API documentation for VerifyDiagnosticConsumer, <a
+href="/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details">here</a>.
</p>
<p>There are many other possible implementations of this interface, and this is
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 40477b82f5f2..8c0e5b7ffcb0 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -1007,6 +1007,7 @@ struct is_convertible_to {
<li><code>__is_convertible_to</code> (Microsoft)</li>
<li><code>__is_empty</code> (GNU, Microsoft)</li>
<li><code>__is_enum</code> (GNU, Microsoft)</li>
+ <li><code>__is_interface_class</code> (Microsoft)</li>
<li><code>__is_pod</code> (GNU, Microsoft)</li>
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
<li><code>__is_union</code> (GNU, Microsoft)</li>
@@ -1582,7 +1583,8 @@ path between it and the next switch label.</p>
<pre>
// compile with -Wimplicit-fallthrough
switch (n) {
-case 33:
+case 22:
+case 33: // no warning: no statements between case labels
f();
case 44: // warning: unannotated fall-through
g();
@@ -1981,8 +1983,8 @@ int fcntl(int fd, int cmd, ...)
<p>Use <tt>__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx,
type_tag_idx)))</tt> on a function declaration to specify that the
-function a type tag that determines the pointee type of some other pointer
-argument.</p>
+function accepts a type tag that determines the pointee type of some other
+pointer argument.</p>
<p>For example:</p>
<blockquote>
diff --git a/docs/LibASTMatchers.html b/docs/LibASTMatchers.html
new file mode 100644
index 000000000000..8142c191a37b
--- /dev/null
+++ b/docs/LibASTMatchers.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Matching the Clang AST</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Matching the Clang AST</h1>
+<p>This document explains how to use Clang's LibASTMatchers to match interesting
+nodes of the AST and execute code that uses the matched nodes. Combined with
+<a href="LibTooling.html">LibTooling</a>, LibASTMatchers helps to write
+code-to-code transformation tools or query tools.</p>
+
+<p>We assume basic knowledge about the Clang AST. See the
+<a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a> if
+you want to learn more about how the AST is structured.</p>
+
+<!-- FIXME: create tutorial and link to the tutorial -->
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>LibASTMatchers provides a domain specific language to create predicates on Clang's
+AST. This DSL is written in and can be used from C++, allowing users to write
+a single program to both match AST nodes and access the node's C++ interface
+to extract attributes, source locations, or any other information provided on
+the AST level.</p>
+
+<p>AST matchers are predicates on nodes in the AST. Matchers are created
+by calling creator functions that allow building up a tree of matchers, where
+inner matchers are used to make the match more specific.</p>
+
+</p>For example, to create a matcher that matches all class or union declarations
+in the AST of a translation unit, you can call
+<a href="LibASTMatchersReference.html#recordDecl0Anchor">recordDecl()</a>.
+To narrow the match down, for example to find all class or union declarations with the name "Foo",
+insert a <a href="LibASTMatchersReference.html#hasName0Anchor">hasName</a>
+matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes
+or unions that are named "Foo", in any namespace. By default, matchers that accept
+multiple inner matchers use an implicit <a href="LibASTMatchersReference.html#allOf0Anchor">allOf()</a>.
+This allows further narrowing down the match, for example to match all classes
+that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).</p>
+
+<!-- ======================================================================= -->
+<h2 id="writing">How to create a matcher</h2>
+<!-- ======================================================================= -->
+
+<p>With more than a thousand classes in the Clang AST, one can quickly get lost
+when trying to figure out how to create a matcher for a specific pattern. This
+section will teach you how to use a rigorous step-by-step pattern to build the
+matcher you are interested in. Note that there will always be matchers missing
+for some part of the AST. See the section about <a href="#writing">how to write
+your own AST matchers</a> later in this document.</p>
+
+<p>The precondition to using the matchers is to understand how the AST
+for what you want to match looks like. The <a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a>
+teaches you how to dump a translation unit's AST into a human readable format.</p>
+
+<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
+<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
+
+<p>In general, the strategy to create the right matchers is:</p>
+<ol>
+<li>Find the outermost class in Clang's AST you want to match.</li>
+<li>Look at the <a href="LibASTMatchersReference.html">AST Matcher Reference</a> for matchers that either match the
+node you're interested in or narrow down attributes on the node.</li>
+<li>Create your outer match expression. Verify that it works as expected.</li>
+<li>Examine the matchers for what the next inner node you want to match is.</li>
+<li>Repeat until the matcher is finished.</li>
+</ol>
+
+<!-- ======================================================================= -->
+<h2 id="binding">Binding nodes in match expressions</h2>
+<!-- ======================================================================= -->
+
+<p>Matcher expressions allow you to specify which parts of the AST are interesting
+for a certain task. Often you will want to then do something with the nodes
+that were matched, like building source code transformations.</p>
+
+<p>To that end, matchers that match specific AST nodes (so called node matchers)
+are bindable; for example, recordDecl(hasName("MyClass")).bind("id") will bind
+the matched recordDecl node to the string "id", to be later retrieved in the
+<a href="http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html">match callback</a>.</p>
+
+<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
+<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
+
+<!-- ======================================================================= -->
+<h2 id="writing">Writing your own matchers</h2>
+<!-- ======================================================================= -->
+
+<p>There are multiple different ways to define a matcher, depending on its
+type and flexibility.</p>
+<ul>
+<li><b>VariadicDynCastAllOfMatcher&ltBase, Derived></b><p>Those match all nodes
+of type <i>Base</i> if they can be dynamically casted to <i>Derived</i>. The
+names of those matchers are nouns, which closely resemble <i>Derived</i>.
+VariadicDynCastAllOfMatchers are the backbone of the matcher hierarchy. Most
+often, your match expression will start with one of them, and you can
+<a href="#binding">bind</a> the node they represent to ids for later processing.</p>
+<p>VariadicDynCastAllOfMatchers are callable classes that model variadic
+template functions in C++03. They take an aribtrary number of Matcher&lt;Derived>
+and return a Matcher&lt;Base>.</p></li>
+<li><b>AST_MATCHER_P(Type, Name, ParamType, Param)</b><p> Most matcher definitions
+use the matcher creation macros. Those define both the matcher of type Matcher&lt;Type>
+itself, and a matcher-creation function named <i>Name</i> that takes a parameter
+of type <i>ParamType</i> and returns the corresponding matcher.</p>
+<p>There are multiple matcher definition macros that deal with polymorphic return
+values and different parameter counts. See <a href="http://clang.llvm.org/doxygen/ASTMatchersMacros_8h.html">ASTMatchersMacros.h</a>.
+</p></li>
+<li><b>Matcher creation functions</b><p>Matchers are generated by nesting
+calls to matcher creation functions. Most of the time those functions are either
+created by using VariadicDynCastAllOfMatcher or the matcher creation macros
+(see below). The free-standing functions are an indication that this matcher
+is just a combination of other matchers, as is for example the case with
+<a href="LibASTMatchersReference.html#callee1Anchor">callee</a>.</p></li>
+</ul>
+
+</div>
+</body>
+</html>
+
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
new file mode 100644
index 000000000000..ea038e38c83d
--- /dev/null
+++ b/docs/LibASTMatchersReference.html
@@ -0,0 +1,1938 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>AST Matcher Reference</title>
+<link type="text/css" rel="stylesheet" href="../menu.css" />
+<link type="text/css" rel="stylesheet" href="../content.css" />
+<style type="text/css">
+td {
+ padding: .33em;
+}
+td.doc {
+ display: none;
+ border-bottom: 1px solid black;
+}
+td.name:hover {
+ color: blue;
+ cursor: pointer;
+}
+</style>
+<script type="text/javascript">
+function toggle(id) {
+ if (!id) return;
+ row = document.getElementById(id);
+ if (row.style.display != 'table-cell')
+ row.style.display = 'table-cell';
+ else
+ row.style.display = 'none';
+}
+</script>
+</head>
+<body onLoad="toggle(location.hash.substring(1, location.hash.length - 6))">
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>AST Matcher Reference</h1>
+
+<p>This document shows all currently implemented matchers. The matchers are grouped
+by category and node type they match. You can click on matcher names to show the
+matcher's source documentation.</p>
+
+<p>There are three different basic categories of matchers:
+<ul>
+<li><a href="#decl-matchers">Node Matchers:</a> Matchers that match a specific type of AST node.</li>
+<li><a href="#narrowing-matchers">Narrowing Matchers:</a> Matchers that match attributes on AST nodes.</li>
+<li><a href="#traversal-matchers">Traversal Matchers:</a> Matchers that allow traversal between AST nodes.</li>
+</ul>
+</p>
+
+<p>Within each category the matchers are ordered by node type they match on.
+Note that if a matcher can match multiple node types, it will it will appear
+multiple times. This means that by searching for Matcher&lt;Stmt&gt; you can
+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>
+
+<!-- ======================================================================= -->
+<h2 id="decl-matchers">Node Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Node matchers are at the core of matcher expressions - they specify the type
+of node that is expected. Every match expression starts with a node matcher,
+which can then be further refined with a narrowing or traversal matcher. All
+traversal matchers take node matchers as their arguments.</p>
+
+<p>For convenience, all node matchers take an arbitrary number of arguments
+and implicitly act as allOf matchers.</p>
+
+<p>Node matchers are the only matchers that support the bind("id") call to
+bind the matched node to the given string, to be later retrieved from the
+match callback.</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_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('classTemplateDecl0')"><a name="classTemplateDecl0Anchor">classTemplateDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="classTemplateDecl0"><pre>Matches C++ class template declarations.
+
+Example matches Z
+ template&lt;class T&gt; class 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('classTemplateSpecializationDecl0')"><a name="classTemplateSpecializationDecl0Anchor">classTemplateSpecializationDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="classTemplateSpecializationDecl0"><pre>Matches C++ class template specializations.
+
+Given
+ template&lt;typename T&gt; class A {};
+ template&lt;&gt; class A&lt;double&gt; {};
+ A&lt;int&gt; a;
+classTemplateSpecializationDecl()
+ matches the specializations A&lt;int&gt; and A&lt;double&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('constructorDecl0')"><a name="constructorDecl0Anchor">constructorDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructorDecl.html">CXXConstructorDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constructorDecl0"><pre>Matches C++ constructor declarations.
+
+Example matches Foo::Foo() and Foo::Foo(int)
+ class Foo {
+ public:
+ Foo();
+ Foo(int);
+ int DoSomething();
+ };
+</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('decl0')"><a name="decl0Anchor">decl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="decl0"><pre>Matches declarations.
+
+Examples matches X, C, and the friend declaration inside C;
+ void X();
+ class C {
+ friend 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('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.
+
+Example matches Foo::~Foo()
+ class Foo {
+ public:
+ virtual ~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('enumConstantDecl0')"><a name="enumConstantDecl0Anchor">enumConstantDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumConstantDecl.html">EnumConstantDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="enumConstantDecl0"><pre>Matches enum constants.
+
+Example matches A, B, C
+ enum X {
+ A, B, 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('enumDecl0')"><a name="enumDecl0Anchor">enumDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1EnumDecl.html">EnumDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="enumDecl0"><pre>Matches enum declarations.
+
+Example matches X
+ enum X {
+ A, B, 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('fieldDecl0')"><a name="fieldDecl0Anchor">fieldDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.
+
+Given
+ class X { int m; };
+fieldDecl()
+ matches 'm'.
+</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.
+
+Example matches f
+ void f();
+</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('functionTemplateDecl0')"><a name="functionTemplateDecl0Anchor">functionTemplateDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTemplateDecl.html">FunctionTemplateDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="functionTemplateDecl0"><pre>Matches C++ function template declarations.
+
+Example matches f
+ template&lt;class T&gt; void f(T t) {}
+</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('methodDecl0')"><a name="methodDecl0Anchor">methodDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="methodDecl0"><pre>Matches method declarations.
+
+Example matches y
+ class X { void 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('namedDecl0')"><a name="namedDecl0Anchor">namedDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="namedDecl0"><pre>Matches a declaration of anything that could have a name.
+
+Example matches X, S, the anonymous union type, i, and U;
+ typedef int X;
+ struct S {
+ union {
+ int i;
+ } 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('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.
+
+Example matches X, Z
+ class X;
+ template&lt;class T&gt; class 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('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.
+
+Given
+ namespace X { int x; }
+ using X::x;
+usingDecl()
+ 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('varDecl0')"><a name="varDecl0Anchor">varDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="varDecl0"><pre>Matches variable declarations.
+
+Note: this does not match declarations of member variables, which are
+"field" declarations in Clang parlance.
+
+Example matches a
+ int a;
+</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('boolLiteral0')"><a name="boolLiteral0Anchor">boolLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="boolLiteral0"><pre>Matches bool literals.
+
+Example matches true
+ true
+</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('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.
+
+Example: castExpr() matches each of the following:
+ (int) 3;
+ const_cast&lt;Expr *&gt;(SubExpr);
+ char c = 0;
+but does not match
+ int i = (0);
+ int k = 0;
+</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('characterLiteral0')"><a name="characterLiteral0Anchor">characterLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="characterLiteral0"><pre>Matches character literals (also matches wchar_t).
+
+Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
+though.
+
+Example matches 'a', L'a'
+ char ch = 'a'; wchar_t chw = L'a';
+</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('constCastExpr0')"><a name="constCastExpr0Anchor">constCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constCastExpr0"><pre>Matches a const_cast expression.
+
+Example: Matches const_cast&lt;int*&gt;(&amp;r) in
+ int n = 42;
+ const int &amp;r(n);
+ int* p = const_cast&lt;int*&gt;(&amp;r);
+</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('dynamicCastExpr0')"><a name="dynamicCastExpr0Anchor">dynamicCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="dynamicCastExpr0"><pre>Matches a dynamic_cast expression.
+
+Example:
+ dynamicCastExpr()
+matches
+ dynamic_cast&lt;D*&gt;(&amp;b);
+in
+ struct B { virtual ~B() {} }; struct D : B {};
+ B b;
+ D* p = dynamic_cast&lt;D*&gt;(&amp;b);
+</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('explicitCastExpr0')"><a name="explicitCastExpr0Anchor">explicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="explicitCastExpr0"><pre>Matches explicit cast expressions.
+
+Matches any cast expression written in user code, whether it be a
+C-style cast, a functional-style cast, or a keyword cast.
+
+Does not match implicit conversions.
+
+Note: the name "explicitCast" is chosen to match Clang's terminology, as
+Clang uses the term "cast" to apply to implicit conversions as well as to
+actual cast expressions.
+
+hasDestinationType.
+
+Example: matches all five of the casts in
+ int((int)(reinterpret_cast&lt;int&gt;(static_cast&lt;int&gt;(const_cast&lt;int&gt;(42)))))
+but does not match the implicit conversion in
+ long ell = 42;
+</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('functionalCastExpr0')"><a name="functionalCastExpr0Anchor">functionalCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="functionalCastExpr0"><pre>Matches functional cast expressions
+
+Example: Matches Foo(bar);
+ Foo f = bar;
+ Foo g = (Foo) bar;
+ Foo h = Foo(bar);
+</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('implicitCastExpr0')"><a name="implicitCastExpr0Anchor">implicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="implicitCastExpr0"><pre>Matches the implicit cast nodes of Clang's AST.
+
+This matches many different places, including function call return value
+eliding, as well as any type conversions.
+</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('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.
+
+Not matching character-encoded integers such as L'a'.
+
+Example matches 1, 1L, 0x1, 1U
+</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('reinterpretCastExpr0')"><a name="reinterpretCastExpr0Anchor">reinterpretCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="reinterpretCastExpr0"><pre>Matches a reinterpret_cast expression.
+
+Either the source expression or the destination type can be matched
+using has(), but hasDestinationType() is more specific and can be
+more readable.
+
+Example matches reinterpret_cast&lt;char*&gt;(&amp;p) in
+ void* p = reinterpret_cast&lt;char*&gt;(&amp;p);
+</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('staticCastExpr0')"><a name="staticCastExpr0Anchor">staticCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="staticCastExpr0"><pre>Matches a C++ static_cast expression.
+
+hasDestinationType
+reinterpretCast
+
+Example:
+ staticCastExpr()
+matches
+ static_cast&lt;long&gt;(8)
+in
+ long eight(static_cast&lt;long&gt;(8));
+</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('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
+
+Example matches "abcd", L"abcd"
+ char *s = "abcd"; wchar_t *ws = L"abcd"
+</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('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
+
+Given
+ int i = a[1];
+arraySubscriptExpr()
+ matches "a[1]"
+</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('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
+
+Example matches a || b
+ !(a || b)
+</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('bindTemporaryExpr0')"><a name="bindTemporaryExpr0Anchor">bindTemporaryExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="bindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
+
+Example matches FunctionTakesString(GetStringByValue())
+ (matcher = bindTemporaryExpr())
+ FunctionTakesString(GetStringByValue());
+ FunctionTakesStringByPointer(GetStringPointer());
+</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('callExpr0')"><a name="callExpr0Anchor">callExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
+
+Example matches x.y() and y()
+ X x;
+ x.y();
+ 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('compoundStmt0')"><a name="compoundStmt0Anchor">compoundStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="compoundStmt0"><pre>Matches compound statements.
+
+Example matches '{}' and '{{}}'in 'for (;;) {{}}'
+ for (;;) {{}}
+</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('conditionalOperator0')"><a name="conditionalOperator0Anchor">conditionalOperator</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="conditionalOperator0"><pre>Matches conditional operator expressions.
+
+Example matches a ? b : c
+ (a ? b : c) + 42
+</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('constructExpr0')"><a name="constructExpr0Anchor">constructExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constructExpr0"><pre>Matches constructor call expressions (including implicit ones).
+
+Example matches string(ptr, n) and ptr within arguments of f
+ (matcher = constructExpr())
+ void f(const string &amp;a, const string &amp;b);
+ char *ptr;
+ int n;
+ f(string(ptr, n), ptr);
+</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('declRefExpr0')"><a name="declRefExpr0Anchor">declRefExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="declRefExpr0"><pre>Matches expressions that refer to declarations.
+
+Example matches x in if (x)
+ bool x;
+ if (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('declStmt0')"><a name="declStmt0Anchor">declStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="declStmt0"><pre>Matches declaration statements.
+
+Given
+ int a;
+declStmt()
+ matches 'int 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('defaultArgExpr0')"><a name="defaultArgExpr0Anchor">defaultArgExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDefaultArgExpr.html">CXXDefaultArgExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="defaultArgExpr0"><pre>Matches the value of a default argument at the call site.
+
+Example matches the CXXDefaultArgExpr placeholder inserted for the
+ default value of the second parameter in the call expression f(42)
+ (matcher = defaultArgExpr())
+ void f(int x, int y = 0);
+ f(42);
+</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.
+
+Given
+ delete X;
+deleteExpr()
+ matches 'delete 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('doStmt0')"><a name="doStmt0Anchor">doStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="doStmt0"><pre>Matches do statements.
+
+Given
+ do {} while (true);
+doStmt()
+ matches 'do {} while(true)'
+</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('expr0')"><a name="expr0Anchor">expr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="expr0"><pre>Matches expressions.
+
+Example matches x()
+ void f() { 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('forStmt0')"><a name="forStmt0Anchor">forStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="forStmt0"><pre>Matches for statements.
+
+Example matches 'for (;;) {}'
+ for (;;) {}
+</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('ifStmt0')"><a name="ifStmt0Anchor">ifStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="ifStmt0"><pre>Matches if statements.
+
+Example matches 'if (x) {}'
+ if (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('initListExpr0')"><a name="initListExpr0Anchor">initListExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="initListExpr0"><pre>Matches init list expressions.
+
+Given
+ int a[] = { 1, 2 };
+ struct B { int x, y; };
+ B b = { 5, 6 };
+initList()
+ matches "{ 1, 2 }" and "{ 5, 6 }"
+</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('materializeTemporaryExpr0')"><a name="materializeTemporaryExpr0Anchor">materializeTemporaryExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MaterializeTemporaryExpr.html">MaterializeTemporaryExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
+
+Example: Given
+ struct T {void func()};
+ T f();
+ void g(T);
+materializeTemporaryExpr() matches 'f()' in these statements
+ T u(f());
+ g(f());
+but does not match
+ f();
+ f().func();
+</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('memberCallExpr0')"><a name="memberCallExpr0Anchor">memberCallExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMemberCallExpr.html">CXXMemberCallExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="memberCallExpr0"><pre>Matches member call expressions.
+
+Example matches x.y()
+ X x;
+ x.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('memberExpr0')"><a name="memberExpr0Anchor">memberExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="memberExpr0"><pre>Matches member expressions.
+
+Given
+ class Y {
+ void x() { this-&gt;x(); x(); Y y; y.x(); a; this-&gt;b; Y::b; }
+ int a; static int b;
+ };
+memberExpr()
+ matches this-&gt;x, x, y.x, a, this-&gt;b
+</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('newExpr0')"><a name="newExpr0Anchor">newExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="newExpr0"><pre>Matches new expressions.
+
+Given
+ new X;
+newExpr()
+ matches 'new 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('operatorCallExpr0')"><a name="operatorCallExpr0Anchor">operatorCallExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="operatorCallExpr0"><pre>Matches overloaded operator calls.
+
+Note that if an operator isn't overloaded, it won't match. Instead, use
+binaryOperator matcher.
+Currently it does not match operators such as new delete.
+FIXME: figure out why these do not match?
+
+Example matches both operator&lt;&lt;((o &lt;&lt; b), c) and operator&lt;&lt;(o, b)
+ (matcher = operatorCallExpr())
+ ostream &amp;operator&lt;&lt; (ostream &amp;out, int i) { };
+ ostream &amp;o; int b = 1, c = 1;
+ o &lt;&lt; b &lt;&lt; c;
+</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('stmt0')"><a name="stmt0Anchor">stmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
+
+Given
+ { ++a; }
+stmt()
+ matches both the compound statement '{ ++a; }' and '++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('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+switchCase()
+ matches 'case 42: break;' and '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('unaryExprOrTypeTraitExpr0')"><a name="unaryExprOrTypeTraitExpr0Anchor">unaryExprOrTypeTraitExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryExprOrTypeTraitExpr0"><pre>Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
+
+Given
+ Foo x = bar;
+ int y = sizeof(x) + alignof(x);
+unaryExprOrTypeTraitExpr()
+ matches sizeof(x) and alignof(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('unaryOperator0')"><a name="unaryOperator0Anchor">unaryOperator</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="unaryOperator0"><pre>Matches unary operator expressions.
+
+Example matches !a
+ !a || b
+</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('whileStmt0')"><a name="whileStmt0Anchor">whileStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="whileStmt0"><pre>Matches while statements.
+
+Given
+ while (true) {}
+whileStmt()
+ matches 'while (true) {}'.
+</pre></td></tr>
+
+<!--END_DECL_MATCHERS -->
+</table>
+
+<!-- ======================================================================= -->
+<h2 id="narrowing-matchers">Narrowing Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Narrowing matchers match certain attributes on the current node, thus
+narrowing down the set of nodes of the current type to match on.</p>
+
+<p>There are special logical narrowing matchers (allOf, anyOf, anything and unless)
+which allow users to create more powerful match expressions.</p>
+
+<table>
+<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 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 colspan="4" class="doc" id="anyOf0"><pre>Matches if any of the given matchers matches.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('anything0')"><a name="anything0Anchor">anything</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="anything0"><pre>Matches any node.
+
+Useful when another matcher requires a child matcher, but there's no
+additional constraint. This will often be used with an explicit conversion
+to an internal::Matcher&lt;&gt; type such as TypeMatcher.
+
+Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
+"int* p" and "void f()" in
+ int* p;
+ void f();
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('unless0')"><a name="unless0Anchor">unless</a></td><td>Matcher&lt;*&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="unless0"><pre>Matches if the provided matcher does not match.
+
+Example matches Y (matcher = recordDecl(unless(hasName("X"))))
+ class X {};
+ class Y {};
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasOperatorName0')"><a name="hasOperatorName0Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions (binary or
+unary).
+
+Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+ !(a || b)
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;CXXBoolLiteral&gt;</td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = boolLiteral(equals(true)))
+ true
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_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).
+</pre></td></tr>
+
+
+<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
+code (as opposed to implicitly added by the compiler).
+
+Given
+ struct Foo {
+ Foo() { }
+ Foo(int) : foo_("A") { }
+ string foo_;
+ };
+constructorDecl(hasAnyConstructorInitializer(isWritten()))
+ will match Foo(int), but not Foo()
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix, such as "&lt;&lt;", for OverloadedOperatorCall's.
+
+Example matches a &lt;&lt; b
+ (matcher == operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;")))
+ a &lt;&lt; b;
+ c &amp;&amp; d; assuming both operator&lt;&lt;
+ and operator&amp;&amp; are overloaded somewhere.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isA1')"><a name="isA1Anchor">isA</a></td><td>StringRef BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="isA1"><pre>Overloaded method as shortcut for isA(hasName(...)).
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>StringRef BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template&lt;typename T&gt; void A(T t) { }
+ template&lt;&gt; void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A&lt;int&gt;().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation0')"><a name="isTemplateInstantiation0Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation0"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template &lt;typename T&gt; class X {}; class A {}; X&lt;A&gt; x;
+or
+ template &lt;typename T&gt; class X {}; class A {}; template class X&lt;A&gt;;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X&lt;A&gt;.
+
+But given
+ template &lt;typename T&gt; class X {}; class A {};
+ template &lt;&gt; class X&lt;A&gt; {}; X&lt;A&gt; x;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X&lt;A&gt; is an explicit template specialization.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('argumentCountIs0')"><a name="argumentCountIs0Anchor">argumentCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="argumentCountIs0"><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_1CharacterLiteral.html">CharacterLiteral</a>&gt;</td><td class="name" onclick="toggle('equals3')"><a name="equals3Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = boolLiteral(equals(true)))
+ true
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>&gt;</td><td class="name" onclick="toggle('statementCountIs0')"><a name="statementCountIs0Anchor">statementCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="statementCountIs0"><pre>Checks that a compound statement contains a specific number of
+child statements.
+
+Example: Given
+ { for (;;) {} }
+compoundStmt(statementCountIs(0)))
+ matches '{}'
+ but does not match the outer compound statement.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt;</td><td class="name" onclick="toggle('declCountIs0')"><a name="declCountIs0Anchor">declCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="declCountIs0"><pre>Matches declaration statements that contain a specific number of
+declarations.
+
+Example: Given
+ int a, b;
+ int c;
+ int d = 2, e;
+declCountIs(2)
+ matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;</td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = boolLiteral(equals(true)))
+ true
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template&lt;typename T&gt; void A(T t) { }
+ template&lt;&gt; void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A&lt;int&gt;().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function declarations.
+
+Given:
+ extern "C" void f() {}
+ extern "C" { void g() {} }
+ void h() {}
+functionDecl(isExternC())
+ matches the declaration of f and g, but not the declaration h
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template &lt;typename T&gt; class X {}; class A {}; X&lt;A&gt; x;
+or
+ template &lt;typename T&gt; class X {}; class A {}; template class X&lt;A&gt;;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X&lt;A&gt;.
+
+But given
+ template &lt;typename T&gt; class X {}; class A {};
+ template &lt;&gt; class X&lt;A&gt; {}; X&lt;A&gt; x;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X&lt;A&gt; is an explicit template specialization.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
+
+Example matches true (matcher = boolLiteral(equals(true)))
+ true
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;</td><td class="name" onclick="toggle('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '-&gt;' as opposed
+to '.'.
+
+Member calls on the implicit this pointer match as called with '-&gt;'.
+
+Given
+ class Y {
+ void x() { this-&gt;x(); x(); Y y; y.x(); a; this-&gt;b; Y::b; }
+ int a;
+ static int b;
+ };
+memberExpr(isArrow())
+ matches this-&gt;x, x, y.x, a, this-&gt;b
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('hasName0')"><a name="hasName0Anchor">hasName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasName0"><pre>Matches NamedDecl nodes that have the specified name.
+
+Supports specifying enclosing namespaces or classes by prefixing the name
+with '&lt;enclosing&gt;::'.
+Does not match typedefs of an underlying type with the given name.
+
+Example matches X (Name == "X")
+ class X;
+
+Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
+ namespace a { namespace b { class X; } }
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr>
+<tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose full names partially match the
+given RegExp.
+
+Supports specifying enclosing namespaces or classes by
+prefixing the name with '&lt;enclosing&gt;::'. Does not match typedefs
+of an underlying type with the given name.
+
+Example matches X (regexp == "::X")
+ class X;
+
+Example matches X (regexp is one of "::X", "^foo::.*X", among others)
+ namespace foo { namespace bar { class X; } }
+</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('asString0')"><a name="asString0Anchor">asString</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="asString0"><pre>Matches if the matched type is represented by the given string.
+
+Given
+ class Y { public: void x(); };
+ void z() { Y* y; y-&gt;x(); }
+callExpr(on(hasType(asString("class Y *"))))
+ matches y-&gt;x()
+</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('isConstQualified0')"><a name="isConstQualified0Anchor">isConstQualified</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isConstQualified0"><pre>Matches QualType nodes that are const-qualified, i.e., that
+include "top-level" const.
+
+Given
+ void a(int);
+ void b(int const);
+ void c(const int);
+ void d(const int*);
+ void e(int const) {};
+functionDecl(hasAnyParameter(hasType(isConstQualified())))
+ matches "void b(int const)", "void c(const int)" and
+ "void e(int const) {}". It does not match d as there
+ is no top-level const on the parameter type "const int *".
+</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('isInteger0')"><a name="isInteger0Anchor">isInteger</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInteger0"><pre>Matches QualType nodes that are of integer type.
+
+Given
+ void a(int);
+ void b(long);
+ void c(double);
+functionDecl(hasAnyParameter(hasType(isInteger())))
+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_1TagDecl.html">TagDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
+</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.
+
+Given
+ int x;
+ int s = sizeof(x) + alignof(x)
+unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
+ matches sizeof(x)
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasOperatorName1')"><a name="hasOperatorName1Anchor">hasOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions (binary or
+unary).
+
+Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+ !(a || b)
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition1')"><a name="isDefinition1Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition1"><pre>Matches if a declaration has a body attached.
+
+Example matches A, va, fa
+ class A {};
+ class B; Doesn't match, as it has no body.
+ int va;
+ extern int vb; Doesn't match, as it doesn't define the variable.
+ void fa() {}
+ void fb(); Doesn't match, as it has no body.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization1')"><a name="isExplicitTemplateSpecialization1Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization1"><pre>Matches explicit template specializations of function, class, or
+static member variable template instantiations.
+
+Given
+ template&lt;typename T&gt; void A(T t) { }
+ template&lt;&gt; void A(int N) { }
+functionDecl(isExplicitTemplateSpecialization())
+ matches the specialization A&lt;int&gt;().
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation1')"><a name="isTemplateInstantiation1Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation1"><pre>Matches template instantiations of function, class, or static
+member variable template instantiations.
+
+Given
+ template &lt;typename T&gt; class X {}; class A {}; X&lt;A&gt; x;
+or
+ template &lt;typename T&gt; class X {}; class A {}; template class X&lt;A&gt;;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ matches the template instantiation of X&lt;A&gt;.
+
+But given
+ template &lt;typename T&gt; class X {}; class A {};
+ template &lt;&gt; class X&lt;A&gt; {}; X&lt;A&gt; x;
+recordDecl(hasName("::X"), isTemplateInstantiation())
+ does not match, as X&lt;A&gt; is an explicit template specialization.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
+</pre></td></tr>
+
+<!--END_NARROWING_MATCHERS -->
+</table>
+
+<!-- ======================================================================= -->
+<h2 id="traversal-matchers">AST Traversal Matchers</h2>
+<!-- ======================================================================= -->
+
+<p>Traversal matchers specify the relationship to other nodes that are
+reachable from the current node.</p>
+
+<p>Note that there are special traversal matchers (has, hasDescendant, forEach and
+forEachDescendant) which work on all nodes and allow users to write more generic
+match expressions.</p>
+
+<table>
+<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('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher&lt;ChildT&gt; ChildMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
+provided matcher.
+
+Example matches X, Y (matcher = recordDecl(forEach(recordDecl(hasName("X")))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; }; Does not match Z.
+
+ChildT must be an AST base type.
+
+As opposed to 'has', 'forEach' will cause a match for each result that
+matches instead of only on the first one.
+
+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 colspan="4" class="doc" id="forEachDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
+provided matcher.
+
+Example matches X, A, B, C
+ (matcher = recordDecl(forEachDescendant(recordDecl(hasName("X")))))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class A { class X {}; };
+ class B { class C { class X {}; }; };
+
+DescendantT must be an AST base type.
+
+As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
+each result that matches instead of only on the first one.
+
+Note: Recursively combined ForEachDescendant can cause many matches:
+ recordDecl(forEachDescendant(recordDecl(forEachDescendant(recordDecl()))))
+will match 10 times (plus injected class name matches) on:
+ class A { class B { class C { class D { class E {}; }; }; }; };
+
+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 colspan="4" class="doc" id="has0"><pre>Matches AST nodes that have child AST nodes that match the
+provided matcher.
+
+Example matches X, Y (matcher = recordDecl(has(recordDecl(hasName("X")))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; }; Does not match Z.
+
+ChildT must be an AST base type.
+
+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 colspan="4" class="doc" id="hasAncestor0"><pre>Matches AST nodes that have an ancestor that matches the provided
+matcher.
+
+Given
+void f() { if (true) { int x = 42; } }
+void g() { for (;;) { int x = 43; } }
+expr(integerLiteral(hasAncsestor(ifStmt()))) matches 42, but not 43.
+
+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 colspan="4" class="doc" id="hasDescendant0"><pre>Matches AST nodes that have descendant AST nodes that match the
+provided matcher.
+
+Example matches X, Y, Z
+ (matcher = recordDecl(hasDescendant(recordDecl(hasName("X")))))
+ class X {}; Matches X, because X::X is a class of name X inside X.
+ class Y { class X {}; };
+ class Z { class Y { class X {}; }; };
+
+DescendantT must be an AST base type.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;</td><td class="name" onclick="toggle('hasBase0')"><a name="hasBase0Anchor">hasBase</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="hasBase0"><pre>Matches the base expression of an array subscript expression.
+
+Given
+ int i[5];
+ void f() { i[1] = 42; }
+arraySubscriptExpression(hasBase(implicitCastExpr(
+ hasSourceExpression(declRefExpr()))))
+ matches i[1] with the declRefExpr() matching i
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;</td><td class="name" onclick="toggle('hasIndex0')"><a name="hasIndex0Anchor">hasIndex</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="hasIndex0"><pre>Matches the index expression of an array subscript expression.
+
+Given
+ int i[5];
+ void f() { i[1] = 42; }
+arraySubscriptExpression(hasIndex(integerLiteral()))
+ matches i[1] with the integerLiteral() matching 1
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</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="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a
+binary operator matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasLHS0')"><a name="hasLHS0Anchor">hasLHS</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="hasLHS0"><pre>Matches the left hand side of binary operator expressions.
+
+Example matches a (matcher = binaryOperator(hasLHS()))
+ a || b
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasRHS0')"><a name="hasRHS0Anchor">hasRHS</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="hasRHS0"><pre>Matches the right hand side of binary operator expressions.
+
+Example matches b (matcher = binaryOperator(hasRHS()))
+ a || b
+</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('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.
+
+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;
+</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('hasAnyConstructorInitializer0')"><a name="hasAnyConstructorInitializer0Anchor">hasAnyConstructorInitializer</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="hasAnyConstructorInitializer0"><pre>Matches a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+recordDecl(has(constructorDecl(hasAnyConstructorInitializer(anything()))))
+ record matches Foo, hasAnyConstructorInitializer matches foo_(1)
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt;</td><td class="name" onclick="toggle('forField0')"><a name="forField0Anchor">forField</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forField0"><pre>Matches the field declaration of a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+recordDecl(has(constructorDecl(hasAnyConstructorInitializer(
+ forField(hasName("foo_"))))))
+ matches Foo
+with forField matching foo_
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>&gt;</td><td class="name" onclick="toggle('withInitializer0')"><a name="withInitializer0Anchor">withInitializer</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="withInitializer0"><pre>Matches the initializer expression of a constructor initializer.
+
+Given
+ struct Foo {
+ Foo() : foo_(1) { }
+ int foo_;
+ };
+recordDecl(has(constructorDecl(hasAnyConstructorInitializer(
+ withInitializer(integerLiteral(equals(1)))))))
+ matches Foo
+with withInitializer matching (1)
+</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('on0')"><a name="on0Anchor">on</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="on0"><pre>Matches on the implicit object argument of a member call expression.
+
+Example matches y.x() (matcher = callExpr(on(hasType(recordDecl(hasName("Y"))))))
+ class Y { public: void x(); };
+ void z() { Y y; y.x(); }",
+
+FIXME: Overload to allow directly matching types?
+</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('onImplicitObjectArgument0')"><a name="onImplicitObjectArgument0Anchor">onImplicitObjectArgument</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="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 colspan="4" class="doc" id="thisPointerType1"><pre>Overloaded to match the type's declaration.
+</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('ofClass0')"><a name="ofClass0Anchor">ofClass</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ofClass0"><pre>Matches the class declaration that the given method declaration
+belongs to.
+
+FIXME: Generalize this for other kinds of declarations.
+FIXME: What other kind of declarations would we need to generalize
+this to?
+
+Example matches A() in the last line
+ (matcher = constructExpr(hasDeclaration(methodDecl(
+ ofClass(hasName("A"))))))
+ class A {
+ public:
+ A();
+ };
+ A a = A();
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isA0')"><a name="isA0Anchor">isA</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
+<tr><td colspan="4" class="doc" id="isA0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
+<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>Matches C++ classes that are directly or indirectly derived from
+a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, C (Base == hasName("X"))
+ class X;
+ class Y : public X {}; directly derived
+ class Z : public Y {}; indirectly derived
+ typedef X A;
+ typedef A B;
+ class C : public B {}; derived from a typedef of X
+
+In the following example, Bar matches isDerivedFrom(hasName("X")):
+ class Foo;
+ typedef Foo X;
+ class Bar : public Foo {}; derived from a type that X is a typedef of
+</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 colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
+given matcher.
+
+Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
+ class Y { public: void x(); };
+ void z() { Y y; y.x();
+</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('hasAnyArgument0')"><a name="hasAnyArgument0Anchor">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="hasAnyArgument0"><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
+</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('hasArgument0')"><a name="hasArgument0Anchor">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="hasArgument0"><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_1CallExpr.html">CallExpr</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.
+
+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;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>&gt;</td><td class="name" onclick="toggle('hasSourceExpression0')"><a name="hasSourceExpression0Anchor">hasSourceExpression</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="hasSourceExpression0"><pre>Matches if the cast's source expression matches the given matcher.
+
+Example: matches "a string" (matcher =
+ hasSourceExpression(constructExpr()))
+class URL { URL(string); };
+URL url = "a string";
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations that have at least one
+TemplateArgument matching the given InnerMatcher.
+
+Given
+ template&lt;typename T&gt; class A {};
+ template&lt;&gt; class A&lt;double&gt; {};
+ A&lt;int&gt; a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToType(asString("int"))))
+ matches the specialization A&lt;int&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasTemplateArgument0')"><a name="hasTemplateArgument0Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTemplateArgument0"><pre>Matches classTemplateSpecializations where the n'th TemplateArgument
+matches the given InnerMatcher.
+
+Given
+ template&lt;typename T, typename U&gt; class A {};
+ A&lt;bool, int&gt; b;
+ A&lt;int, bool&gt; c;
+classTemplateSpecializationDecl(hasTemplateArgument(
+ 1, refersToType(asString("int"))))
+ matches the specialization A&lt;bool, int&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>&gt;</td><td class="name" onclick="toggle('hasAnySubstatement0')"><a name="hasAnySubstatement0Anchor">hasAnySubstatement</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnySubstatement0"><pre>Matches compound statements where at least one substatement matches
+a given matcher.
+
+Given
+ { {}; 1+2; }
+hasAnySubstatement(compoundStmt())
+ matches '{ {}; 1+2; }'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>&gt;</td><td class="name" onclick="toggle('hasCondition4')"><a name="hasCondition4Anchor">hasCondition</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="hasCondition4"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>&gt;</td><td class="name" onclick="toggle('hasFalseExpression0')"><a name="hasFalseExpression0Anchor">hasFalseExpression</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="hasFalseExpression0"><pre>Matches the false branch expression of a conditional operator.
+
+Example matches b
+ condition ? a : b
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConditionalOperator.html">ConditionalOperator</a>&gt;</td><td class="name" onclick="toggle('hasTrueExpression0')"><a name="hasTrueExpression0Anchor">hasTrueExpression</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="hasTrueExpression0"><pre>Matches the true branch expression of a conditional operator.
+
+Example matches a
+ condition ? a : b
+</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.
+
+FIXME: This currently only works for functions. Fix.
+
+Given
+ namespace a { void f() {} }
+ using a::f;
+ void g() {
+ f(); Matches this ..
+ a::f(); .. but not this.
+ }
+declRefExpr(throughUsingDeclaration(anything()))
+ matches f()
+</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('to0')"><a name="to0Anchor">to</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="to0"><pre>Matches a DeclRefExpr that refers to a declaration that matches the
+specified matcher.
+
+Example matches x in if(x)
+ (matcher = declRefExpr(to(varDecl(hasName("x")))))
+ bool x;
+ if (x) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt;</td><td class="name" onclick="toggle('containsDeclaration0')"><a name="containsDeclaration0Anchor">containsDeclaration</a></td><td>unsigned N, 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="containsDeclaration0"><pre>Matches the n'th declaration of a declaration statement.
+
+Note that this does not work for global declarations because the AST
+breaks up multiple-declaration DeclStmt's into multiple single-declaration
+DeclStmt's.
+Example: Given non-global declarations
+ int a, b = 0;
+ int c;
+ int d = 2, e;
+declStmt(containsDeclaration(
+ 0, varDecl(hasInitializer(anything()))))
+ matches only 'int d = 2, e;', and
+declStmt(containsDeclaration(1, varDecl()))
+ matches 'int a, b = 0' as well as 'int d = 2, e;'
+ but 'int c;' is not matched.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt;</td><td class="name" onclick="toggle('hasSingleDecl0')"><a name="hasSingleDecl0Anchor">hasSingleDecl</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="hasSingleDecl0"><pre>Matches the Decl of a DeclStmt which has a single declaration.
+
+Given
+ int a, b;
+ int c;
+declStmt(hasSingleDecl(anything()))
+ matches 'int c;' but not 'int a, b;'.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody0"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>&gt;</td><td class="name" onclick="toggle('hasCondition3')"><a name="hasCondition3Anchor">hasCondition</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="hasCondition3"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+ if (true) {}
+</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.
+
+(Note: Clang's AST refers to other conversions as "casts" too, and calls
+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
+declaration's type.
+
+In case of a value declaration (for example a variable declaration),
+this resolves one layer of indirection. For example, in the value
+declaration "X x;", recordDecl(hasName("X")) matches the declaration of X,
+while varDecl(hasType(recordDecl(hasName("X")))) matches the declaration
+of x."
+
+Example matches x (matcher = expr(hasType(recordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(recordDecl(hasName("X")))))
+ class X {};
+ void y(X &amp;x) { x; X z; }
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt;
+</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('ignoringImpCasts0')"><a name="ignoringImpCasts0Anchor">ignoringImpCasts</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="ignoringImpCasts0"><pre>Matches expressions that match InnerMatcher after any implicit casts
+are stripped off.
+
+Parentheses and explicit casts are not discarded.
+Given
+ int arr[5];
+ int a = 0;
+ char b = 0;
+ const int c = a;
+ int *d = arr;
+ long e = (long) 0l;
+The matchers
+ varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
+ varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
+would match the declarations for a, b, c, and d, but not e.
+While
+ varDecl(hasInitializer(integerLiteral()))
+ varDecl(hasInitializer(declRefExpr()))
+only match the declarations for b, c, and d.
+</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('ignoringParenCasts0')"><a name="ignoringParenCasts0Anchor">ignoringParenCasts</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="ignoringParenCasts0"><pre>Matches expressions that match InnerMatcher after parentheses and
+casts are stripped off.
+
+Implicit and non-C Style casts are also discarded.
+Given
+ int a = 0;
+ char b = (0);
+ void* c = reinterpret_cast&lt;char*&gt;(0);
+ char d = char(0);
+The matcher
+ varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
+would match the declarations for a, b, c, and d.
+while
+ varDecl(hasInitializer(integerLiteral()))
+only match the declaration for a.
+</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('ignoringParenImpCasts0')"><a name="ignoringParenImpCasts0Anchor">ignoringParenImpCasts</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="ignoringParenImpCasts0"><pre>Matches expressions that match InnerMatcher after implicit casts and
+parentheses are stripped off.
+
+Explicit casts are not discarded.
+Given
+ int arr[5];
+ int a = 0;
+ char b = (0);
+ const int c = a;
+ int *d = (arr);
+ long e = ((long) 0l);
+The matchers
+ varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
+ varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
+would match the declarations for a, b, c, and d, but not e.
+while
+ varDecl(hasInitializer(integerLiteral()))
+ varDecl(hasInitializer(declRefExpr()))
+would only match the declaration for a.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody1')"><a name="hasBody1Anchor">hasBody</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody1"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;</td><td class="name" onclick="toggle('hasCondition1')"><a name="hasCondition1Anchor">hasCondition</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="hasCondition1"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;</td><td class="name" onclick="toggle('hasIncrement0')"><a name="hasIncrement0Anchor">hasIncrement</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasIncrement0"><pre>Matches the increment statement of a for loop.
+
+Example:
+ forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
+matches '++x' in
+ for (x; x &lt; N; ++x) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;</td><td class="name" onclick="toggle('hasLoopInit0')"><a name="hasLoopInit0Anchor">hasLoopInit</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasLoopInit0"><pre>Matches the initialization statement of a for loop.
+
+Example:
+ forStmt(hasLoopInit(declStmt()))
+matches 'int x = 0' in
+ for (int x = 0; x &lt; N; ++x) { }
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyParameter0')"><a name="hasAnyParameter0Anchor">hasAnyParameter</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasAnyParameter0"><pre>Matches any parameter of a function declaration.
+
+Does not match the 'this' parameter of a method.
+
+Given
+ class X { void f(int x, int y, int z) {} };
+methodDecl(hasAnyParameter(hasName("y")))
+ matches f(int x, int y, int z) {}
+with hasAnyParameter(...)
+ matching int y
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('hasParameter0')"><a name="hasParameter0Anchor">hasParameter</a></td><td>unsigned N, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasParameter0"><pre>Matches the n'th parameter of a function declaration.
+
+Given
+ class X { void f(int x) {} };
+methodDecl(hasParameter(0, hasType(varDecl())))
+ matches f(int x) {}
+with hasParameter(...)
+ matching int x
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('returns0')"><a name="returns0Anchor">returns</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="returns0"><pre>Matches the return type of a function declaration.
+
+Given:
+ class X { int f() { return 1; } };
+methodDecl(returns(asString("int")))
+ matches int f() { return 1; }
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>&gt;</td><td class="name" onclick="toggle('hasCondition0')"><a name="hasCondition0Anchor">hasCondition</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="hasCondition0"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IfStmt.html">IfStmt</a>&gt;</td><td class="name" onclick="toggle('hasConditionVariableStatement0')"><a name="hasConditionVariableStatement0Anchor">hasConditionVariableStatement</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasConditionVariableStatement0"><pre>Matches the condition variable statement in an if statement.
+
+Given
+ if (A* a = GetAPointer()) {}
+hasConditionVariableStatment(...)
+ matches 'A* a = GetAPointer()'.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>&gt;</td><td class="name" onclick="toggle('hasImplicitDestinationType0')"><a name="hasImplicitDestinationType0Anchor">hasImplicitDestinationType</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="hasImplicitDestinationType0"><pre>Matches implicit casts whose destination type matches a given
+matcher.
+
+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('hasObjectExpression0')"><a name="hasObjectExpression0Anchor">hasObjectExpression</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="hasObjectExpression0"><pre>Matches a member expression where the object expression is
+matched by a given matcher.
+
+Given
+ struct X { int m; };
+ void f(X x) { x.m; m; }
+memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))))
+ matches "x.m" and "m"
+with hasObjectExpression(...)
+ matching "x" and the implicit object expression of "m" which has type X*.
+</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('member0')"><a name="member0Anchor">member</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="member0"><pre>Matches a member expression where the member is matched by a
+given matcher.
+
+Given
+ struct { int first, second; } first, second;
+ int i(second.first);
+ int j(first.second);
+memberExpr(member(hasName("first")))
+ matches second.first
+ but not first.second (because the member name there is "second").
+</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('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.
+
+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;
+</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 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 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_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('alignOfExpr0')"><a name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
+alignof.
+</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('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="sizeOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
+sizeof.
+</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.
+
+Given
+ template&lt;typename T&gt; struct A {};
+ struct B { B* next; };
+ A&lt;&amp;B::next&gt; a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(fieldDecl(hasName("next"))))
+ matches the specialization A&lt;&amp;B::next&gt; with fieldDecl(...) matching
+ B::next
+</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('refersToType0')"><a name="refersToType0Anchor">refersToType</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="refersToType0"><pre>Matches a TemplateArgument that refers to a certain type.
+
+Given
+ struct X {};
+ template&lt;typename T&gt; struct A {};
+ A&lt;X&gt; a;
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToType(class(hasName("X")))))
+ matches the specialization A&lt;X&gt;
+</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('hasArgumentOfType0')"><a name="hasArgumentOfType0Anchor">hasArgumentOfType</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="hasArgumentOfType0"><pre>Matches unary expressions that have a specific type of argument.
+
+Given
+ int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
+unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
+ matches sizeof(a) and alignof(c)
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasUnaryOperand0')"><a name="hasUnaryOperand0Anchor">hasUnaryOperand</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="hasUnaryOperand0"><pre>Matches if the operand of a unary operator matches.
+
+Example matches true (matcher = hasOperand(boolLiteral(equals(true))))
+ !true
+</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.
+
+Given
+ namespace X { void b(); }
+ using X::b;
+usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
+ matches using X::b </pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UsingShadowDecl.html">UsingShadowDecl</a>&gt;</td><td class="name" onclick="toggle('hasTargetDecl0')"><a name="hasTargetDecl0Anchor">hasTargetDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasTargetDecl0"><pre>Matches a using shadow declaration where the target declaration is
+matched by the given matcher.
+
+Given
+ namespace X { int a; void b(); }
+ using X::a;
+ using X::b;
+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
+declaration's type.
+
+In case of a value declaration (for example a variable declaration),
+this resolves one layer of indirection. For example, in the value
+declaration "X x;", recordDecl(hasName("X")) matches the declaration of X,
+while varDecl(hasType(recordDecl(hasName("X")))) matches the declaration
+of x."
+
+Example matches x (matcher = expr(hasType(recordDecl(hasName("X")))))
+ and z (matcher = varDecl(hasType(recordDecl(hasName("X")))))
+ class X {};
+ void y(X &amp;x) { x; X z; }
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('hasInitializer0')"><a name="hasInitializer0Anchor">hasInitializer</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="hasInitializer0"><pre>Matches a variable declaration that has an initializer expression
+that matches the given matcher.
+
+Example matches x (matcher = varDecl(hasInitializer(callExpr())))
+ bool y() { return true; }
+ bool x = y();
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody2')"><a name="hasBody2Anchor">hasBody</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasBody2"><pre>Matches a 'for', 'while', or 'do while' statement that has
+a given body.
+
+Given
+ for (;;) {}
+hasBody(compoundStmt())
+ matches 'for (;;) {}'
+with compoundStmt()
+ matching '{}'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>&gt;</td><td class="name" onclick="toggle('hasCondition2')"><a name="hasCondition2Anchor">hasCondition</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="hasCondition2"><pre>Matches the condition expression of an if statement, for loop,
+or conditional operator.
+
+Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+ if (true) {}
+</pre></td></tr>
+
+<!--END_TRAVERSAL_MATCHERS -->
+</table>
+
+</div>
+</body>
+</html>
+
+
diff --git a/docs/LibTooling.html b/docs/LibTooling.html
index ed0ad45e4e7f..163d24a7f1a1 100644
--- a/docs/LibTooling.html
+++ b/docs/LibTooling.html
@@ -16,24 +16,27 @@
<p>LibTooling is a library to support writing standalone tools based on
Clang. This document will provide a basic walkthrough of how to write
a tool using LibTooling.</p>
+<p>For the information on how to setup Clang Tooling for LLVM see
+<a href="HowToSetupToolingForLLVM.html">HowToSetupToolingForLLVM.html</a></p>
<!-- ======================================================================= -->
<h2 id="intro">Introduction</h2>
<!-- ======================================================================= -->
-<p>Tools built with LibTooling, like Clang Plugins, run FrontendActions over
-code. <!-- See FIXME for a tutorial on how to write FrontendActions. -->
+<p>Tools built with LibTooling, like Clang Plugins, run
+<code>FrontendActions</code> over code.
+<!-- See FIXME for a tutorial on how to write FrontendActions. -->
In this tutorial, we'll demonstrate the different ways of running clang's
-SyntaxOnlyAction, which runs a quick syntax check, over a bunch of
+<code>SyntaxOnlyAction</code>, which runs a quick syntax check, over a bunch of
code.</p>
<!-- ======================================================================= -->
<h2 id="runoncode">Parsing a code snippet in memory.</h2>
<!-- ======================================================================= -->
-<p>If you ever wanted to run a FrontendAction over some sample code, for example
-to unit test parts of the Clang AST, runToolOnCode is what you looked for. Let
-me give you an example:
+<p>If you ever wanted to run a <code>FrontendAction</code> over some sample
+code, for example to unit test parts of the Clang AST,
+<code>runToolOnCode</code> is what you looked for. Let me give you an example:
<pre>
#include "clang/Tooling/Tooling.h"
@@ -48,53 +51,44 @@ me give you an example:
<h2 id="standalonetool">Writing a standalone tool.</h2>
<!-- ======================================================================= -->
-<p>Once you unit tested your FrontendAction to the point where it cannot
-possibly break, it's time to create a standalone tool. For a standalone tool
-to run clang, it first needs to figure out what command line arguments to use
-for a specified file. To that end we create a CompilationDatabase.</p>
+<p>Once you unit tested your <code>FrontendAction</code> to the point where it
+cannot possibly break, it's time to create a standalone tool. For a standalone
+tool to run clang, it first needs to figure out what command line arguments to
+use for a specified file. To that end we create a
+<code>CompilationDatabase</code>. There are different ways to create a
+compilation database, and we need to support all of them depending on
+command-line options. There's the <code>CommonOptionsParser</code> class
+that takes the responsibility to parse command-line parameters related to
+compilation databases and inputs, so that all tools share the implementation.
+</p>
-<h3 id="compilationdb">Creating a compilation database.</h3>
-<p>CompilationDatabase provides static factory functions to help with parsing
-compile commands from a build directory or the command line. The following code
-allows for both explicit specification of a compile command line, as well as
-retrieving the compile commands lines from a database.
+<h3 id="parsingcommonoptions">Parsing common tools options.</h3>
+<p><code>CompilationDatabase</code> can be read from a build directory or the
+command line. Using <code>CommonOptionsParser</code> allows for explicit
+specification of a compile command line, specification of build path using the
+<code>-p</code> command-line option, and automatic location of the compilation
+database using source files paths.
<pre>
+#include "clang/Tooling/CommonOptionsParser.h"
+
+using namespace clang::tooling;
+
int main(int argc, const char **argv) {
- // First, try to create a fixed compile command database from the command line
- // arguments.
- llvm::OwningPtr&lt;CompilationDatabase> Compilations(
- FixedCompilationDatabase::loadFromCommandLine(argc, argv));
-
- // Next, use normal llvm command line parsing to get the tool specific
- // parameters.
- cl::ParseCommandLineOptions(argc, argv);
-
- if (!Compilations) {
- // In case the user did not specify the compile command line via positional
- // command line arguments after "--", try to load the compile commands from
- // a database in the specified build directory or auto-detect it from a
- // source file.
- std::string ErrorMessage;
- if (!BuildPath.empty()) {
- Compilations.reset(
- CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage));
- } else {
- Compilations.reset(CompilationDatabase::autoDetectFromSource(
- SourcePaths[0], ErrorMessage));
- }
- // If there is still no valid compile command database, we don't know how
- // to run the tool.
- if (!Compilations)
- llvm::report_fatal_error(ErrorMessage);
- }
+ // CommonOptionsParser constructor will parse arguments and create a
+ // CompilationDatabase. In case of error it will terminate the program.
+ CommonOptionsParser OptionsParser(argc, argv);
+
+ // Use OptionsParser.GetCompilations() and OptionsParser.GetSourcePathList()
+ // to retrieve CompilationDatabase and the list of input file paths.
}
</pre>
</p>
<h3 id="tool">Creating and running a ClangTool.</h3>
-<p>Once we have a CompilationDatabase, we can create a ClangTool and run our
-FrontendAction over some code. For example, to run the SyntaxOnlyAction over
-the files "a.cc" and "b.cc" one would write:
+<p>Once we have a <code>CompilationDatabase</code>, we can create a
+<code>ClangTool</code> and run our <code>FrontendAction</code> over some code.
+For example, to run the <code>SyntaxOnlyAction</code> over the files "a.cc" and
+"b.cc" one would write:
<pre>
// A clang tool can run over a number of sources in the same process...
std::vector&lt;std::string> Sources;
@@ -103,7 +97,7 @@ the files "a.cc" and "b.cc" one would write:
// We hand the CompilationDatabase we created and the sources to run over into
// the tool constructor.
- ClangTool Tool(*Compilations, Sources);
+ ClangTool Tool(OptionsParser.GetCompilations(), Sources);
// The ClangTool needs a new FrontendAction for each translation unit we run
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
@@ -117,40 +111,29 @@ the files "a.cc" and "b.cc" one would write:
<p>Now we combine the two previous steps into our first real tool. This example
tool is also checked into the clang tree at tools/clang-check/ClangCheck.cpp.
<pre>
-#include "llvm/Support/CommandLine.h"
+// Declares clang::SyntaxOnlyAction.
#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
+// Declares llvm::cl::extrahelp.
+#include "llvm/Support/CommandLine.h"
using namespace clang::tooling;
using namespace llvm;
-cl::opt&lt;std::string> BuildPath(
- "p",
- cl::desc("&lt;build-path>"),
- cl::Optional);
+// CommonOptionsParser declares HelpMessage with a description of the common
+// command-line options related to the compilation database and input files.
+// It's nice to have this help message in all tools.
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
-cl::list&lt;std::string> SourcePaths(
- cl::Positional,
- cl::desc("&lt;source0> [... &lt;sourceN>]"),
- cl::OneOrMore);
+// A help message for this specific tool can be added afterwards.
+static cl::extrahelp MoreHelp("\nMore help text...");
int main(int argc, const char **argv) {
- llvm::OwningPtr&lt;CompilationDatabase> Compilations(
- FixedCompilationDatabase::loadFromCommandLine(argc, argv));
- cl::ParseCommandLineOptions(argc, argv);
- if (!Compilations) {
- std::string ErrorMessage;
- Compilations.reset(
- !BuildPath.empty() ?
- CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
- CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
- );
- if (!Compilations)
- llvm::report_fatal_error(ErrorMessage);
- }
- ClangTool Tool(*Compilations, SourcePaths);
- return Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction>());
+ CommonOptionsParser OptionsParser(argc, argv);
+ ClangTool Tool(OptionsParser.GetCompilations(),
+ OptionsParser.GetSourcePathList());
+ return Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction&gt;());
}
</pre>
</p>
diff --git a/docs/ObjectiveCLiterals.html b/docs/ObjectiveCLiterals.html
index 11751a6acda8..d5a8a9eca0c6 100644
--- a/docs/ObjectiveCLiterals.html
+++ b/docs/ObjectiveCLiterals.html
@@ -178,7 +178,7 @@ A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSStr
<pre>
// Partition command line arguments into positional and option arguments.
NSMutableArray *args = [NSMutableArray new];
-NSMutableDictionary *options = [NSMutableArray new];
+NSMutableDictionary *options = [NSMutableDictionary new];
while (--argc) {
const char *arg = *++argv;
if (strncmp(arg, "--", 2) == 0) {
diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html
index 28ce1ce53efb..7fed5bab84e1 100644
--- a/docs/PCHInternals.html
+++ b/docs/PCHInternals.html
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <title>Precompiled Headers (PCH)</title>
+ <title>Precompiled Header and Modules Internals</title>
<link type="text/css" rel="stylesheet" href="../menu.css">
<link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
@@ -18,10 +18,10 @@
<div id="content">
-<h1>Precompiled Headers</h1>
+<h1>Precompiled Header and Modules Internals</h1>
<p>This document describes the design and implementation of Clang's
- precompiled headers (PCH). If you are interested in the end-user
+ precompiled headers (PCH) and modules. If you are interested in the end-user
view, please see the <a
href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
@@ -30,7 +30,7 @@
<li><a href="#usage">Using Precompiled Headers with
<tt>clang</tt></a></li>
<li><a href="#philosophy">Design Philosophy</a></li>
- <li><a href="#contents">Precompiled Header Contents</a>
+ <li><a href="#contents">Serialized AST File Contents</a>
<ul>
<li><a href="#metadata">Metadata Block</a></li>
<li><a href="#sourcemgr">Source Manager Block</a></li>
@@ -42,8 +42,9 @@
<li><a href="#method-pool">Method Pool Block</a></li>
</ul>
</li>
- <li><a href="#tendrils">Precompiled Header Integration
- Points</a></li>
+ <li><a href="#tendrils">AST Reader Integration Points</a></li>
+ <li><a href="#chained">Chained precompiled headers</a></li>
+ <li><a href="#modules">Modules</a></li>
</ul>
<h2 id="usage">Using Precompiled Headers with <tt>clang</tt></h2>
@@ -94,30 +95,39 @@ with the <b><tt>-include-pch</tt></b> option:</p>
require the PCH file to be up-to-date.</li>
</ul>
-<p>Clang's precompiled headers are designed with a compact on-disk
-representation, which minimizes both PCH creation time and the time
-required to initially load the PCH file. The PCH file itself contains
+<p>Modules, as implemented in Clang, use the same mechanisms as
+precompiled headers to save a serialized AST file (one per module) and
+use those AST modules. From an implementation standpoint, modules are
+a generalization of precompiled headers, lifting a number of
+restrictions placed on precompiled headers. In particular, there can
+only be one precompiled header and it must be included at the
+beginning of the translation unit. The extensions to the AST file
+format required for modules are discussed in the section on <a href="#modules">modules</a>.</p>
+
+<p>Clang's AST files are designed with a compact on-disk
+representation, which minimizes both creation time and the time
+required to initially load the AST file. The AST file itself contains
a serialized representation of Clang's abstract syntax trees and
supporting data structures, stored using the same compressed bitstream
as <a href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitcode
file format</a>.</p>
-<p>Clang's precompiled headers are loaded "lazily" from disk. When a
-PCH file is initially loaded, Clang reads only a small amount of data
-from the PCH file to establish where certain important data structures
+<p>Clang's AST files are loaded "lazily" from disk. When an
+AST file is initially loaded, Clang reads only a small amount of data
+from the AST file to establish where certain important data structures
are stored. The amount of data read in this initial load is
-independent of the size of the PCH file, such that a larger PCH file
-does not lead to longer PCH load times. The actual header data in the
-PCH file--macros, functions, variables, types, etc.--is loaded only
+independent of the size of the AST file, such that a larger AST file
+does not lead to longer AST load times. The actual header data in the
+AST file--macros, functions, variables, types, etc.--is loaded only
when it is referenced from the user's code, at which point only that
entity (and those entities it depends on) are deserialized from the
-PCH file. With this approach, the cost of using a precompiled header
+AST file. With this approach, the cost of using an AST file
for a translation unit is proportional to the amount of code actually
-used from the header, rather than being proportional to the size of
-the header itself.</p>
+used from the AST file, rather than being proportional to the size of
+the AST file itself.</p>
<p>When given the <code>-print-stats</code> option, Clang produces
-statistics describing how much of the precompiled header was actually
+statistics describing how much of the AST file was actually
loaded from disk. For a simple "Hello, World!" program that includes
the Apple <code>Cocoa.h</code> header (which is built as a precompiled
header), this option illustrates how little of the actual precompiled
@@ -143,7 +153,7 @@ header is required:</p>
<p>For this small program, only a tiny fraction of the source
locations, types, declarations, identifiers, and macros were actually
deserialized from the precompiled header. These statistics can be
-useful to determine whether the precompiled header implementation can
+useful to determine whether the AST file implementation can
be improved by making more of the implementation lazy.</p>
<p>Precompiled headers can be chained. When you create a PCH while
@@ -153,13 +163,15 @@ example, you could create a PCH out of all the headers that are very
commonly used throughout your project, and then create a PCH for every
single source file in the project that includes the code that is
specific to that file, so that recompiling the file itself is very fast,
-without duplicating the data from the common headers for every file.</p>
+without duplicating the data from the common headers for every
+file. The mechanisms behind chained precompiled headers are discussed
+in a <a href="#chained">later section</a>.
-<h2 id="contents">Precompiled Header Contents</h2>
+<h2 id="contents">AST File Contents</h2>
<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
-<p>Clang's precompiled headers are organized into several different
+<p>Clang's AST files are organized into several different
blocks, each of which contains the serialized representation of a part
of Clang's internal representation. Each of the blocks corresponds to
either a block or a record within <a
@@ -167,19 +179,19 @@ either a block or a record within <a
format</a>. The contents of each of these logical blocks are described
below.</p>
-<p>For a given precompiled header, the <a
+<p>For a given AST file, the <a
href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a>
utility can be used to examine the actual structure of the bitstream
-for the precompiled header. This information can be used both to help
-understand the structure of the precompiled header and to isolate
-areas where precompiled headers can still be optimized, e.g., through
+for the AST file. This information can be used both to help
+understand the structure of the AST file and to isolate
+areas where AST files can still be optimized, e.g., through
the introduction of abbreviations.</p>
<h3 id="metadata">Metadata Block</h3>
<p>The metadata block contains several records that provide
-information about how the precompiled header was built. This metadata
-is primarily used to validate the use of a precompiled header. For
+information about how the AST file was built. This metadata
+is primarily used to validate the use of an AST file. For
example, a precompiled header built for a 32-bit x86 target cannot be used
when compiling for a 64-bit x86 target. The metadata block contains
information about:</p>
@@ -187,17 +199,17 @@ information about:</p>
<dl>
<dt>Language options</dt>
<dd>Describes the particular language dialect used to compile the
-PCH file, including major options (e.g., Objective-C support) and more
+AST file, including major options (e.g., Objective-C support) and more
minor options (e.g., support for "//" comments). The contents of this
record correspond to the <code>LangOptions</code> class.</dd>
<dt>Target architecture</dt>
<dd>The target triple that describes the architecture, platform, and
-ABI for which the PCH file was generated, e.g.,
+ABI for which the AST file was generated, e.g.,
<code>i386-apple-darwin9</code>.</dd>
- <dt>PCH version</dt>
- <dd>The major and minor version numbers of the precompiled header
+ <dt>AST version</dt>
+ <dd>The major and minor version numbers of the AST file
format. Changes in the minor version number should not affect backward
compatibility, while changes in the major version number imply that a
newer compiler cannot read an older precompiled header (and
@@ -205,11 +217,11 @@ vice-versa).</dd>
<dt>Original file name</dt>
<dd>The full path of the header that was used to generate the
-precompiled header.</dd>
+AST file.</dd>
<dt>Predefines buffer</dt>
<dd>Although not explicitly stored as part of the metadata, the
-predefines buffer is used in the validation of the precompiled header.
+predefines buffer is used in the validation of the AST file.
The predefines buffer itself contains code generated by the compiler
to initialize the preprocessor state according to the current target,
platform, and command-line options. For example, the predefines buffer
@@ -220,26 +232,14 @@ contents are verified along with the rest of the metadata.</dd>
</dl>
-<p>A chained PCH file (that is, one that references another PCH) has
-a slightly different metadata block, which contains the following
-information:</p>
+<p>A chained PCH file (that is, one that references another PCH) and a
+module (which may import other modules) have additional metadata
+containing the list of all AST files that this AST file depends
+on. Each of those files will be loaded along with this AST file.</p>
-<dl>
- <dt>Referenced file</dt>
- <dd>The name of the referenced PCH file. It is looked up like a file
-specified using -include-pch.</dd>
-
- <dt>PCH version</dt>
- <dd>This is the same as in normal PCH files.</dd>
-
- <dt>Original file name</dt>
- <dd>The full path of the header that was used to generate this
-precompiled header.</dd>
-
-</dl>
-
-<p>The language options, target architecture and predefines buffer data
-is taken from the end of the chain, since they have to match anyway.</p>
+<p>For chained precompiled headers, the language options, target
+architecture and predefines buffer data is taken from the end of the
+chain, since they have to match anyway.</p>
<h3 id="sourcemgr">Source Manager Block</h3>
@@ -248,10 +248,10 @@ Clang's <a
href="InternalsManual.html#SourceLocation">SourceManager</a> class,
which handles the mapping from source locations (as represented in
Clang's abstract syntax tree) into actual column/line positions within
-a source file or macro instantiation. The precompiled header's
+a source file or macro instantiation. The AST file's
representation of the source manager also includes information about
all of the headers that were (transitively) included when building the
-precompiled header.</p>
+AST file.</p>
<p>The bulk of the source manager block is dedicated to information
about the various files, buffers, and macro instantiations into which
@@ -259,18 +259,18 @@ a source location can refer. Each of these is referenced by a numeric
"file ID", which is a unique number (allocated starting at 1) stored
in the source location. Clang serializes the information for each kind
of file ID, along with an index that maps file IDs to the position
-within the PCH file where the information about that file ID is
+within the AST file where the information about that file ID is
stored. The data associated with a file ID is loaded only when
required by the front end, e.g., to emit a diagnostic that includes a
macro instantiation history inside the header itself.</p>
<p>The source manager block also contains information about all of the
-headers that were included when building the precompiled header. This
+headers that were included when building the AST file. This
includes information about the controlling macro for the header (e.g.,
when the preprocessor identified that the contents of the header
dependent on a macro like <code>LLVM_CLANG_SOURCEMANAGER_H</code>)
along with a cached version of the results of the <code>stat()</code>
-system calls performed when building the precompiled header. The
+system calls performed when building the AST file. The
latter is particularly useful in reducing system time when searching
for include files.</p>
@@ -279,8 +279,8 @@ for include files.</p>
<p>The preprocessor block contains the serialized representation of
the preprocessor. Specifically, it contains all of the macros that
have been defined by the end of the header used to build the
-precompiled header, along with the token sequences that comprise each
-macro. The macro definitions are only read from the PCH file when the
+AST file, along with the token sequences that comprise each
+macro. The macro definitions are only read from the AST file when the
name of the macro first occurs in the program. This lazy loading of
macro definitions is triggered by lookups into the <a
href="#idtable">identifier table</a>.</p>
@@ -290,8 +290,8 @@ macro definitions is triggered by lookups into the <a
<p>The types block contains the serialized representation of all of
the types referenced in the translation unit. Each Clang type node
(<code>PointerType</code>, <code>FunctionProtoType</code>, etc.) has a
-corresponding record type in the PCH file. When types are deserialized
-from the precompiled header, the data within the record is used to
+corresponding record type in the AST file. When types are deserialized
+from the AST file, the data within the record is used to
reconstruct the appropriate type node using the AST context.</p>
<p>Each type has a unique type ID, which is an integer that uniquely
@@ -300,10 +300,10 @@ less than <code>NUM_PREDEF_TYPE_IDS</code> represent predefined types
(<code>void</code>, <code>float</code>, etc.), while other
"user-defined" type IDs are assigned consecutively from
<code>NUM_PREDEF_TYPE_IDS</code> upward as the types are encountered.
-The PCH file has an associated mapping from the user-defined types
+The AST file has an associated mapping from the user-defined types
block to the location within the types block where the serialized
representation of that type resides, enabling lazy deserialization of
-types. When a type is referenced from within the PCH file, that
+types. When a type is referenced from within the AST file, that
reference is encoded using the type ID shifted left by 3 bits. The
lower three bits are used to represent the <code>const</code>,
<code>volatile</code>, and <code>restrict</code> qualifiers, as in
@@ -316,19 +316,20 @@ class.</p>
<p>The declarations block contains the serialized representation of
all of the declarations referenced in the translation unit. Each Clang
declaration node (<code>VarDecl</code>, <code>FunctionDecl</code>,
-etc.) has a corresponding record type in the PCH file. When
-declarations are deserialized from the precompiled header, the data
+etc.) has a corresponding record type in the AST file. When
+declarations are deserialized from the AST file, the data
within the record is used to build and populate a new instance of the
corresponding <code>Decl</code> node. As with types, each declaration
node has a numeric ID that is used to refer to that declaration within
-the PCH file. In addition, a lookup table provides a mapping from that
+the AST file. In addition, a lookup table provides a mapping from that
numeric ID to the offset within the precompiled header where that
declaration is described.</p>
<p>Declarations in Clang's abstract syntax trees are stored
hierarchically. At the top of the hierarchy is the translation unit
(<code>TranslationUnitDecl</code>), which contains all of the
-declarations in the translation unit. These declarations (such as
+declarations in the translation unit but is not actually written as a
+specific declaration node. Its child declarations (such as
functions or struct types) may also contain other declarations inside
them, and so on. Within Clang, each declaration is stored within a <a
href="http://clang.llvm.org/docs/InternalsManual.html#DeclContext">declaration
@@ -339,7 +340,7 @@ in a structure) and iterate over the declarations stored within a
context (e.g., iterate over all of the fields of a structure for
structure layout).</p>
-<p>In Clang's precompiled header format, deserializing a declaration
+<p>In Clang's AST file format, deserializing a declaration
that is a <code>DeclContext</code> is a separate operation from
deserializing all of the declarations stored within that declaration
context. Therefore, Clang will deserialize the translation unit
@@ -354,14 +355,11 @@ the name-lookup and iteration behavior described above:</p>
<code>x</code> within a given declaration context (for example,
during semantic analysis of the expression <code>p-&gt;x</code>,
where <code>p</code>'s type is defined in the precompiled header),
- Clang deserializes a hash table mapping from the names within that
- declaration context to the declaration IDs that represent each
- visible declaration with that name. The entire hash table is
- deserialized at this point (into the <code>llvm::DenseMap</code>
- stored within each <code>DeclContext</code> object), but the actual
- declarations are not yet deserialized. In a second step, those
- declarations with the name <code>x</code> will be deserialized and
- will be used as the result of name lookup.</li>
+ Clang refers to an on-disk hash table that maps from the names
+ within that declaration context to the declaration IDs that
+ represent each visible declaration with that name. The actual
+ declarations will then be deserialized to provide the results of
+ name lookup.</li>
<li>When the front end performs iteration over all of the
declarations within a declaration context, all of those declarations
@@ -376,7 +374,7 @@ the name-lookup and iteration behavior described above:</p>
<h3 id="stmt">Statements and Expressions</h3>
-<p>Statements and expressions are stored in the precompiled header in
+<p>Statements and expressions are stored in the AST file in
both the <a href="#types">types</a> and the <a
href="#decls">declarations</a> blocks, because every statement or
expression will be associated with either a type or declaration. The
@@ -389,10 +387,10 @@ function.</p>
<p>As with types and declarations, each statement and expression kind
in Clang's abstract syntax tree (<code>ForStmt</code>,
<code>CallExpr</code>, etc.) has a corresponding record type in the
-precompiled header, which contains the serialized representation of
+AST file, which contains the serialized representation of
that statement or expression. Each substatement or subexpression
within an expression is stored as a separate record (which keeps most
-records to a fixed size). Within the precompiled header, the
+records to a fixed size). Within the AST file, the
subexpressions of an expression are stored, in reverse order, prior to the expression
that owns those expression, using a form of <a
href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
@@ -420,7 +418,7 @@ they are part of a different expression.</p>
<h3 id="idtable">Identifier Table Block</h3>
<p>The identifier table block contains an on-disk hash table that maps
-each identifier mentioned within the precompiled header to the
+each identifier mentioned within the AST file to the
serialized representation of the identifier's information (e.g, the
<code>IdentifierInfo</code> structure). The serialized representation
contains:</p>
@@ -438,17 +436,20 @@ contains:</p>
declarations.</li>
</ul>
-<p>When a precompiled header is loaded, the precompiled header
+<p>When an AST file is loaded, the AST file reader
mechanism introduces itself into the identifier table as an external
lookup source. Thus, when the user program refers to an identifier
that has not yet been seen, Clang will perform a lookup into the
identifier table. If an identifier is found, its contents (macro
-definitions, flags, top-level declarations, etc.) will be deserialized, at which point the corresponding <code>IdentifierInfo</code> structure will have the same contents it would have after parsing the headers in the precompiled header.</p>
+definitions, flags, top-level declarations, etc.) will be
+deserialized, at which point the corresponding
+<code>IdentifierInfo</code> structure will have the same contents it
+would have after parsing the headers in the AST file.</p>
-<p>Within the PCH file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
+<p>Within the AST file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
hash table where that identifier is stored. This mapping is used when
deserializing the name of a declaration, the identifier of a token, or
-any other construct in the PCH file that refers to a name.</p>
+any other construct in the AST file that refers to a name.</p>
<h3 id="method-pool">Method Pool Block</h3>
@@ -457,7 +458,7 @@ serves two purposes: it provides a mapping from the names of
Objective-C selectors to the set of Objective-C instance and class
methods that have that particular selector (which is required for
semantic analysis in Objective-C) and also stores all of the selectors
-used by entities within the precompiled header. The design of the
+used by entities within the AST file. The design of the
method pool is similar to that of the <a href="#idtable">identifier
table</a>: the first time a particular selector is formed during the
compilation of the program, Clang will search in the on-disk hash
@@ -468,25 +469,25 @@ structure (<code>Sema::InstanceMethodPool</code> and
respectively).</p>
<p>As with identifiers, selectors are represented by numeric values
-within the PCH file. A separate index maps these numeric selector
+within the AST file. A separate index maps these numeric selector
values to the offset of the selector within the on-disk hash table,
and will be used when de-serializing an Objective-C method declaration
(or other Objective-C construct) that refers to the selector.</p>
-<h2 id="tendrils">Precompiled Header Integration Points</h2>
+<h2 id="tendrils">AST Reader Integration Points</h2>
-<p>The "lazy" deserialization behavior of precompiled headers requires
+<p>The "lazy" deserialization behavior of AST files requires
their integration into several completely different submodules of
Clang. For example, lazily deserializing the declarations during name
lookup requires that the name-lookup routines be able to query the
-precompiled header to find entities within the PCH file.</p>
+AST file to find entities stored there.</p>
<p>For each Clang data structure that requires direct interaction with
-the precompiled header logic, there is an abstract class that provides
-the interface between the two modules. The <code>PCHReader</code>
-class, which handles the loading of a precompiled header, inherits
+the AST reader logic, there is an abstract class that provides
+the interface between the two modules. The <code>ASTReader</code>
+class, which handles the loading of an AST file, inherits
from all of these abstract classes to provide lazy deserialization of
-Clang's data structures. <code>PCHReader</code> implements the
+Clang's data structures. <code>ASTReader</code> implements the
following abstract classes:</p>
<dl>
@@ -505,7 +506,7 @@ following abstract classes:</p>
<dd>This abstract interface is associated with the
<code>IdentifierTable</code> class, and is used whenever the
program source refers to an identifier that has not yet been seen.
- In this case, the precompiled header implementation searches for
+ In this case, the AST reader searches for
this identifier within its <a href="#idtable">identifier table</a>
to load any top-level declarations or macros associated with that
identifier.</dd>
@@ -513,7 +514,7 @@ following abstract classes:</p>
<dt><code>ExternalASTSource</code></dt>
<dd>This abstract interface is associated with the
<code>ASTContext</code> class, and is used whenever the abstract
- syntax tree nodes need to loaded from the precompiled header. It
+ syntax tree nodes need to loaded from the AST file. It
provides the ability to de-serialize declarations and types
identified by their numeric values, read the bodies of functions
when required, and read the declarations stored within a
@@ -526,6 +527,131 @@ following abstract classes:</p>
pool</a>.</dd>
</dl>
+<h2 id="chained">Chained precompiled headers</h2>
+
+<p>Chained precompiled headers were initially intended to improve the
+performance of IDE-centric operations such as syntax highlighting and
+code completion while a particular source file is being edited by the
+user. To minimize the amount of reparsing required after a change to
+the file, a form of precompiled header--called a precompiled
+<i>preamble</i>--is automatically generated by parsing all of the
+headers in the source file, up to and including the last
+#include. When only the source file changes (and none of the headers
+it depends on), reparsing of that source file can use the precompiled
+preamble and start parsing after the #includes, so parsing time is
+proportional to the size of the source file (rather than all of its
+includes). However, the compilation of that translation unit
+may already use a precompiled header: in this case, Clang will create
+the precompiled preamble as a chained precompiled header that refers
+to the original precompiled header. This drastically reduces the time
+needed to serialize the precompiled preamble for use in reparsing.</p>
+
+<p>Chained precompiled headers get their name because each precompiled header
+can depend on one other precompiled header, forming a chain of
+dependencies. A translation unit will then include the precompiled
+header that starts the chain (i.e., nothing depends on it). This
+linearity of dependencies is important for the semantic model of
+chained precompiled headers, because the most-recent precompiled
+header can provide information that overrides the information provided
+by the precompiled headers it depends on, just like a header file
+<code>B.h</code> that includes another header <code>A.h</code> can
+modify the state produced by parsing <code>A.h</code>, e.g., by
+<code>#undef</code>'ing a macro defined in <code>A.h</code>.</p>
+
+<p>There are several ways in which chained precompiled headers
+generalize the AST file model:</p>
+
+<dl>
+ <dt>Numbering of IDs</dt>
+ <dd>Many different kinds of entities--identifiers, declarations,
+ types, etc.---have ID numbers that start at 1 or some other
+ predefined constant and grow upward. Each precompiled header records
+ the maximum ID number it has assigned in each category. Then, when a
+ new precompiled header is generated that depends on (chains to)
+ another precompiled header, it will start counting at the next
+ available ID number. This way, one can determine, given an ID
+ number, which AST file actually contains the entity.</dd>
+
+ <dt>Name lookup</dt>
+ <dd>When writing a chained precompiled header, Clang attempts to
+ write only information that has changed from the precompiled header
+ on which it is based. This changes the lookup algorithm for the
+ various tables, such as the <a href="#idtable">identifier table</a>:
+ the search starts at the most-recent precompiled header. If no entry
+ is found, lookup then proceeds to the identifier table in the
+ precompiled header it depends on, and so one. Once a lookup
+ succeeds, that result is considered definitive, overriding any
+ results from earlier precompiled headers.</dd>
+
+ <dt>Update records</dt>
+ <dd>There are various ways in which a later precompiled header can
+ modify the entities described in an earlier precompiled header. For
+ example, later precompiled headers can add entries into the various
+ name-lookup tables for the translation unit or namespaces, or add
+ new categories to an Objective-C class. Each of these updates is
+ captured in an "update record" that is stored in the chained
+ precompiled header file and will be loaded along with the original
+ entity.</dd>
+</dl>
+
+<h2 id="modules">Modules</h2>
+
+<p>Modules generalize the chained precompiled header model yet
+further, from a linear chain of precompiled headers to an arbitrary
+directed acyclic graph (DAG) of AST files. All of the same techniques
+used to make chained precompiled headers work---ID number, name
+lookup, update records---are shared with modules. However, the DAG
+nature of modules introduce a number of additional complications to
+the model:
+
+<dl>
+ <dt>Numbering of IDs</dt>
+ <dd>The simple, linear numbering scheme used in chained precompiled
+ headers falls apart with the module DAG, because different modules
+ may end up with different numbering schemes for entities they
+ imported from common shared modules. To account for this, each
+ module file provides information about which modules it depends on
+ and which ID numbers it assigned to the entities in those modules,
+ as well as which ID numbers it took for its own new entities. The
+ AST reader then maps these "local" ID numbers into a "global" ID
+ number space for the current translation unit, providing a 1-1
+ mapping between entities (in whatever AST file they inhabit) and
+ global ID numbers. If that translation unit is then serialized into
+ an AST file, this mapping will be stored for use when the AST file
+ is imported.</dd>
+
+ <dt>Declaration merging</dt>
+ <dd>It is possible for a given entity (from the language's
+ perspective) to be declared multiple times in different places. For
+ example, two different headers can have the declaration of
+ <tt>printf</tt> or could forward-declare <tt>struct stat</tt>. If
+ each of those headers is included in a module, and some third party
+ imports both of those modules, there is a potentially serious
+ problem: name lookup for <tt>printf</tt> or <tt>struct stat</tt> will
+ find both declarations, but the AST nodes are unrelated. This would
+ result in a compilation error, due to an ambiguity in name
+ lookup. Therefore, the AST reader performs declaration merging
+ according to the appropriate language semantics, ensuring that the
+ two disjoint declarations are merged into a single redeclaration
+ chain (with a common canonical declaration), so that it is as if one
+ of the headers had been included before the other.</dd>
+
+ <dt>Name Visibility</dt>
+ <dd>Modules allow certain names that occur during module creation to
+ be "hidden", so that they are not part of the public interface of
+ the module and are not visible to its clients. The AST reader
+ maintains a "visible" bit on various AST nodes (declarations, macros,
+ etc.) to indicate whether that particular AST node is currently
+ visible; the various name lookup mechanisms in Clang inspect the
+ visible bit to determine whether that entity, which is still in the
+ AST (because other, visible AST nodes may depend on it), can
+ actually be found by name lookup. When a new (sub)module is
+ imported, it may make existing, non-visible, already-deserialized
+ AST nodes visible; it is the responsibility of the AST reader to
+ find and update these AST nodes when it is notified of the import.</dd>
+
+</dl>
+
</div>
</body>
diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html
index 7a6a508bb54d..8a195f0b83e5 100644
--- a/docs/ReleaseNotes.html
+++ b/docs/ReleaseNotes.html
@@ -170,6 +170,16 @@ int f(vector&lt;map&lt;int, double&gt;&gt;);
</li>
+ <li>Clang's <tt>-fcatch-undefined-behavior</tt> option has been renamed to
+ <tt>-fsanitize=undefined</tt> and has grown the ability to check for several
+ new types of undefined behavior. See the Users Manual for more information.
+
+ <!-- Flesh this out prior to release. -->
+
+ <!-- Document renaming of -faddress-sanitizer and -fthread-sanitizer. -->
+
+ </li>
+
</ul>
<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>
diff --git a/docs/ThreadSanitizer.html b/docs/ThreadSanitizer.html
index 7a1d075f1e6c..aa251c115313 100644
--- a/docs/ThreadSanitizer.html
+++ b/docs/ThreadSanitizer.html
@@ -37,9 +37,8 @@ Typical slowdown introduced by ThreadSanitizer is <b>5x-15x</b> (TODO: these num
approximate so far).
<h2 id="howtobuild">How to build</h2>
-Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
-Note: CMake build does not work yet.
-See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
+Follow the <a href="../get_started.html">clang build instructions</a>.
+CMake build is supported.<BR>
<h2 id="platforms">Supported Platforms</h2>
ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04). <BR>
@@ -49,8 +48,8 @@ Support for 32-bit platforms is problematic and not yet planned.
<h2 id="usage">Usage</h2>
-Simply compile your program with <tt>-fthread-sanitizer -fPIE</tt> and link it
-with <tt>-fthread-sanitizer -pie</tt>.<BR>
+Simply compile your program with <tt>-fsanitize=thread -fPIE</tt> and link it
+with <tt>-fsanitize=thread -pie</tt>.<BR>
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
Use <tt>-g</tt> to get file names and line numbers in the warning messages. <BR>
@@ -73,7 +72,7 @@ int main() {
</pre>
<pre>
-% clang -fthread-sanitizer -g -O1 tiny_race.c -fPIE -pie
+% clang -fsanitize=thread -g -O1 tiny_race.c -fPIE -pie
</pre>
If a bug is detected, the program will print an error message to stderr.
@@ -111,7 +110,9 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
ThreadSanitizer is in alpha stage.
It is known to work on large C++ programs using pthreads, but we do not promise
anything (yet). <BR>
-C++11 threading is not yet supported.
+C++11 threading is not yet supported. <BR>
+The test suite is integrated into CMake build and can be run with
+<tt>make check-tsan</tt> command. <BR>
We are actively working on enhancing the tool -- stay tuned.
Any help, especially in the form of minimized standalone tests is more than welcome.
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 69f916c94e84..35fc5dca3315 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -874,33 +874,77 @@ likely to affect PCH files that reference a large number of headers.</p>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<dl>
-<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>: Turn
-on runtime code generation to check for undefined behavior.</dt>
+<dt id="opt_fsanitize"><b>-fsanitize=check1,check2</b>: Turn on runtime checks
+for various forms of undefined behavior.</dt>
+
+<dd>This option controls whether Clang adds runtime checks for various forms of
+undefined behavior, and is disabled by default. If a check fails, a diagnostic
+message is produced at runtime explaining the problem. The main checks are:
-<dd>This option, which defaults to off, controls whether or not Clang
-adds runtime checks for undefined runtime behavior. If a check fails,
-<tt>__builtin_trap()</tt> is used to indicate failure.
-The checks are:
<ul>
-<li>Subscripting where the static type of one operand is a variable
- which is decayed from an array type and the other operand is
- greater than the size of the array or less than zero.</li>
-<li>Shift operators where the amount shifted is greater or equal to the
- promoted bit-width of the left-hand-side or less than zero.</li>
-<li>If control flow reaches __builtin_unreachable.
-<li>When llvm implements more __builtin_object_size support, reads and
- writes for objects that __builtin_object_size indicates we aren't
- accessing valid memory. Bit-fields and vectors are not yet checked.
+<li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
+ <a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
+ detector.</li>
+<li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
+ <a href="ThreadSanitizer.html">ThreadSanitizer</a>, an <em>experimental</em>
+ data race detector. Not ready for widespread use.</li>
+<li id="opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt>:
+ Enables all the checks listed below.</li>
</ul>
+
+The following more fine-grained checks are also available:
+
+<ul>
+<li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
+ Use of a misaligned pointer or creation of a misaligned reference.</li>
+<li id="opt_fsanitize_divide-by-zero"><tt>-fsanitize=divide-by-zero</tt>:
+ Division by zero.</li>
+<li id="opt_fsanitize_float-cast-overflow"><tt>-fsanitize=float-cast-overflow</tt>:
+ Conversion to, from, or between floating-point types which would overflow
+ the destination.</li>
+<li id="opt_fsanitize_null"><tt>-fsanitize=null</tt>:
+ Use of a null pointer or creation of a null reference.</li>
+<li id="opt_fsanitize_object-size"><tt>-fsanitize=object-size</tt>:
+ An attempt to use bytes which the optimizer can determine are not part of
+ the object being accessed.
+ The sizes of objects are determined using <tt>__builtin_object_size</tt>, and
+ consequently may be able to detect more problems at higher optimization
+ levels.</li>
+<li id="opt_fsanitize_return"><tt>-fsanitize=return</tt>:
+ In C++, reaching the end of a value-returning function without returning a
+ value.</li>
+<li id="opt_fsanitize_shift"><tt>-fsanitize=shift</tt>:
+ Shift operators where the amount shifted is greater or equal to the
+ promoted bit-width of the left hand side or less than zero, or where
+ the left hand side is negative. For a signed left shift, also checks
+ for signed overflow in C, and for unsigned overflow in C++.</li>
+<li id="opt_fsanitize_signed-integer-overflow"><tt>-fsanitize=signed-integer-overflow</tt>:
+ Signed integer overflow, including all the checks added by <tt>-ftrapv</tt>,
+ and checking for overflow in signed division (<tt>INT_MIN / -1</tt>).</li>
+<li id="opt_fsanitize_unreachable"><tt>-fsanitize=unreachable</tt>:
+ If control flow reaches __builtin_unreachable.</li>
+<li id="opt_fsanitize_vla-bound"><tt>-fsanitize=vla-bound</tt>:
+ A variable-length array whose bound does not evaluate to a positive value.</li>
+<li id="opt_fsanitize_vptr"><tt>-fsanitize=vptr</tt>:
+ Use of an object whose vptr indicates that it is of the wrong dynamic type,
+ or that its lifetime has not begun or has ended. Incompatible with
+ <tt>-fno-rtti</tt>.</li>
+</ul>
+
+The <tt>-fsanitize=</tt> argument must also be provided when linking, in order
+to link to the appropriate runtime library. It is not possible to combine the
+<tt>-fsanitize=address</tt> and <tt>-fsanitize=thread</tt> checkers in the same
+program.
</dd>
<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
-Turn on <a href="AddressSanitizer.html">AddressSanitizer</a>,
-a memory error detector.
+Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=address</tt></a>.
<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
-Turn on ThreadSanitizer, an <em>experimental</em> data race detector.
-Not ready for widespread use.
+Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=thread</tt></a>.
+
+<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>:
+Deprecated synonym for <a href="#opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt></a>.
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
Don't assume that the C++'s new operator is sane.</dt>
diff --git a/docs/analyzer/IPA.txt b/docs/analyzer/IPA.txt
index 569197712894..016cea9cd297 100644
--- a/docs/analyzer/IPA.txt
+++ b/docs/analyzer/IPA.txt
@@ -1,96 +1,355 @@
Inlining
========
-Inlining Modes
------------------------
--analyzer-ipa=none - All inlining is disabled.
--analyzer-ipa=inlining - Turns on inlining when we can confidently find the function/method body corresponding to the call. (C functions, static functions, devirtualized C++ methods, ObjC class methods, ObjC instance methods when we are confident about the dynamic type of the instance).
--analyzer-ipa=dynamic - Inline instance methods for which the type is determined at runtime and we are not 100% sure that our type info is correct. For virtual calls, inline the most plausible definition.
--analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path is split. We inline on one branch and do not inline on the other. This mode does not drop the coverage in cases when the parent class has code that is only exercised when some of its methods are overriden.
+There are several options that control which calls the analyzer will consider for
+inlining. The major one is -analyzer-ipa:
+
+ -analyzer-ipa=none - All inlining is disabled. This is the only mode available
+ in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
+
+ -analyzer-ipa=basic-inlining - Turns on inlining for C functions, C++ static
+ member functions, and blocks -- essentially, the calls that behave like
+ simple C function calls. This is essentially the mode used in Xcode 4.4.
+
+ -analyzer-ipa=inlining - Turns on inlining when we can confidently find the
+ function/method body corresponding to the call. (C functions, static
+ functions, devirtualized C++ methods, Objective-C class methods, Objective-C
+ instance methods when ExprEngine is confident about the dynamic type of the
+ instance).
+
+ -analyzer-ipa=dynamic - Inline instance methods for which the type is
+ determined at runtime and we are not 100% sure that our type info is
+ correct. For virtual calls, inline the most plausible definition.
+
+ -analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path
+ is split. We inline on one branch and do not inline on the other. This mode
+ does not drop the coverage in cases when the parent class has code that is
+ only exercised when some of its methods are overridden.
+
+Currently, -analyzer-ipa=dynamic-bifurcate is the default mode.
+
+While -analyzer-ipa determines in general how aggressively the analyzer will try to
+inline functions, several additional options control which types of functions can
+inlined, in an all-or-nothing way. These options use the analyzer's configuration
+table, so they are all specified as follows:
+
+ -analyzer-config OPTION=VALUE
+
+### c++-inlining ###
+
+This option controls which C++ member functions may be inlined.
+
+ -analyzer-config c++-inlining=[none | methods | constructors | destructors]
+
+Each of these modes implies that all the previous member function kinds will be
+inlined as well; it doesn't make sense to inline destructors without inlining
+constructors, for example.
+
+The default c++-inlining mode is 'methods', meaning only regular member
+functions and overloaded operators will be inlined. Note that no C++ member
+functions will be inlined under -analyzer-ipa=none or
+-analyzer-ipa=basic-inlining.
+
+### c++-template-inlining ###
+
+This option controls whether C++ templated functions may be inlined.
+
+ -analyzer-config c++-template-inlining=[true | false]
+
+Currently, template functions are considered for inlining by default.
+
+The motivation behind this option is that very generic code can be a source
+of false positives, either by considering paths that the caller considers
+impossible (by some unstated precondition), or by inlining some but not all
+of a deep implementation of a function.
+
+### c++-stdlib-inlining ###
+
+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]
+
+Currently, C++ standard library functions are NOT considered for inlining by default.
+
+The standard library functions and the STL in particular are used ubiquitously
+enough that our tolerance for false positives is even lower here. A false
+positive due to poor modeling of the STL leads to a poor user experience, since
+most users would not be comfortable adding assertions to system headers in order
+to silence analyzer warnings.
-Currently, -analyzer-ipa=inlining is the default mode.
Basics of Implementation
-----------------------
-The low-level mechanism of inlining a function is handled in ExprEngine::inlineCall and ExprEngine::processCallExit. If the conditions are right for inlining, a CallEnter node is created and added to the analysis work list. The CallEnter node marks the change to a new LocationContext representing the called function, and its state includes the contents of the new stack frame. When the CallEnter node is actually processed, its single successor will be a edge to the first CFG block in the function.
+The low-level mechanism of inlining a function is handled in
+ExprEngine::inlineCall and ExprEngine::processCallExit.
+
+If the conditions are right for inlining, a CallEnter node is created and added
+to the analysis work list. The CallEnter node marks the change to a new
+LocationContext representing the called function, and its state includes the
+contents of the new stack frame. When the CallEnter node is actually processed,
+its single successor will be a edge to the first CFG block in the function.
+
+Exiting an inlined function is a bit more work, fortunately broken up into
+reasonable steps:
+
+1. The CoreEngine realizes we're at the end of an inlined call and generates a
+ CallExitBegin node.
-Exiting an inlined function is a bit more work, fortunately broken up into reasonable steps:
-1. The CoreEngine realizes we're at the end of an inlined call and generates a CallExitBegin node.
-2. ExprEngine takes over (in processCallExit) and finds the return value of the function, if it has one. This is bound to the expression that triggered the call. (In the case of calls without origin expressions, such as destructors, this step is skipped.)
-3. Dead symbols and bindings are cleaned out from the state, including any local bindings.
-4. A CallExitEnd node is generated, which marks the transition back to the caller's LocationContext.
-5. Custom post-call checks are processed and the final nodes are pushed back onto the work list, so that evaluation of the caller can continue.
+2. ExprEngine takes over (in processCallExit) and finds the return value of the
+ function, if it has one. This is bound to the expression that triggered the
+ call. (In the case of calls without origin expressions, such as destructors,
+ this step is skipped.)
+
+3. Dead symbols and bindings are cleaned out from the state, including any local
+ bindings.
+
+4. A CallExitEnd node is generated, which marks the transition back to the
+ caller's LocationContext.
+
+5. Custom post-call checks are processed and the final nodes are pushed back
+ onto the work list, so that evaluation of the caller can continue.
Retry Without Inlining
------------------------
+----------------------
-In some cases, we would like to retry analyzes without inlining the particular call. Currently, we use this technique to recover the coverage in case we stop analyzing a path due to exceeding the maximum block count inside an inlined function. When this situation is detected, we walk up the path to find the first node before inlining was started and enqueue it on the WorkList with a special ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining).
+In some cases, we would like to retry analysis without inlining a particular
+call.
-Deciding when to inline
+Currently, we use this technique to recover coverage in case we stop
+analyzing a path due to exceeding the maximum block count inside an inlined
+function.
+
+When this situation is detected, we walk up the path to find the first node
+before inlining was started and enqueue it on the WorkList with a special
+ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining). The
+path is then re-analyzed from that point without inlining that particular call.
+
+Deciding When to Inline
-----------------------
-In general, we try to inline as much as possible, since it provides a better summary of what actually happens in the program. However, there are some cases where we choose not to inline:
-- if there is no definition available (of course)
-- if we can't create a CFG or compute variable liveness for the function
-- if we reach a cutoff of maximum stack depth (to avoid infinite recursion)
-- if the function is variadic
-- in C++, we don't inline constructors unless we know the destructor will be inlined as well
-- in C++, we don't inline allocators (custom operator new implementations), since we don't properly handle deallocators (at the time of this writing)
-- "Dynamic" calls are handled specially; see below.
-- Engine:FunctionSummaries map stores additional information about declarations, some of which is collected at runtime based on previous analyzes of the function. We do not inline functions which were not profitable to inline in a different context (for example, if the maximum block count was exceeded, see Retry Without Inlining).
-
-
-Dynamic calls and devirtualization
+
+In general, the analyzer attempts to inline as much as possible, since it
+provides a better summary of what actually happens in the program. There are
+some cases, however, where the analyzer chooses not to inline:
+
+- If there is no definition available for the called function or method. In
+ this case, there is no opportunity to inline.
+
+- If the CFG cannot be constructed for a called function, or the liveness
+ cannot be computed. These are prerequisites for analyzing a function body,
+ with or without inlining.
+
+- If the LocationContext chain for a given ExplodedNode reaches a maximum cutoff
+ depth. This prevents unbounded analysis due to infinite recursion, but also
+ serves as a useful cutoff for performance reasons.
+
+- If the function is variadic. This is not a hard limitation, but an engineering
+ limitation.
+
+ Tracked by: <rdar://problem/12147064> Support inlining of variadic functions
+
+- In C++, constructors are not inlined unless the destructor call will be
+ processed by the ExprEngine. Thus, if the CFG was built without nodes for
+ implicit destructors, or if the destructors for the given object are not
+ represented in the CFG, the constructor will not be inlined. (As an exception,
+ constructors for objects with trivial constructors can still be inlined.)
+ See "C++ Caveats" below.
+
+- In C++, ExprEngine does not inline custom implementations of operator 'new'
+ or operator 'delete', nor does it inline the constructors and destructors
+ associated with these. See "C++ Caveats" below.
+
+- Calls resulting in "dynamic dispatch" are specially handled. See more below.
+
+- The FunctionSummaries map stores additional information about declarations,
+ some of which is collected at runtime based on previous analyses.
+ We do not inline functions which were not profitable to inline in a different
+ context (for example, if the maximum block count was exceeded; see
+ "Retry Without Inlining").
+
+
+Dynamic Calls and Devirtualization
----------------------------------
-"Dynamic" calls are those that are resolved at runtime, such as C++ virtual method calls and Objective-C message sends. Due to the path-sensitive nature of the analyzer, we may be able to figure out the dynamic type of the object whose method is being called and thus "devirtualize" the call, i.e. find the actual method that will be called at runtime. (Obviously this is not always possible.) This is handled by CallEvent's getRuntimeDefinition method.
-Type information is tracked as DynamicTypeInfo, stored within the program state. If no DynamicTypeInfo has been explicitly set for a region, it will be inferred from the region's type or associated symbol. Information from symbolic regions is weaker than from true typed regions; a C++ object declared "A obj" is known to have the class 'A', but a reference "A &ref" may dynamically be a subclass of 'A'. The DynamicTypePropagation checker gathers and propagates the type information.
+"Dynamic" calls are those that are resolved at runtime, such as C++ virtual
+method calls and Objective-C message sends. Due to the path-sensitive nature of
+the analysis, the analyzer may be able to reason about the dynamic type of the
+object whose method is being called and thus "devirtualize" the call.
+
+This path-sensitive devirtualization occurs when the analyzer can determine what
+method would actually be called at runtime. This is possible when the type
+information is constrained enough for a simulated C++/Objective-C object that
+the analyzer can make such a decision.
+
+ == DynamicTypeInfo ==
+
+As the analyzer analyzes a path, it may accrue information to refine the
+knowledge about the type of an object. This can then be used to make better
+decisions about the target method of a call.
+
+Such type information is tracked as DynamicTypeInfo. This is path-sensitive
+data that is stored in ProgramState, which defines a mapping from MemRegions to
+an (optional) DynamicTypeInfo.
+
+If no DynamicTypeInfo has been explicitly set for a MemRegion, it will be lazily
+inferred from the region's type or associated symbol. Information from symbolic
+regions is weaker than from true typed regions.
+
+ EXAMPLE: A C++ object declared "A obj" is known to have the class 'A', but a
+ reference "A &ref" may dynamically be a subclass of 'A'.
+
+The DynamicTypePropagation checker gathers and propagates DynamicTypeInfo,
+updating it as information is observed along a path that can refine that type
+information for a region.
-(Warning: not all of the existing analyzer code has been retrofitted to use DynamicTypeInfo, nor is it universally appropriate. In particular, DynamicTypeInfo always applies to a region with all casts stripped off, but sometimes the information provided by casts can be useful.)
+ WARNING: Not all of the existing analyzer code has been retrofitted to use
+ DynamicTypeInfo, nor is it universally appropriate. In particular,
+ DynamicTypeInfo always applies to a region with all casts stripped
+ off, but sometimes the information provided by casts can be useful.
-When asked to provide a definition, the CallEvents for dynamic calls will use the type info in their state to provide the best definition of the method to be called. In some cases this devirtualization can be perfect or near-perfect, and we can inline the definition as usual. In others we can make a guess, but report that our guess may not be the method actually called at runtime.
-The -analyzer-ipa option has four different modes: none, inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all dynamic calls are inlined, whether we are certain or not that this will actually be the definition used at runtime. Under -analyzer-ipa=inlining, only "near-perfect" devirtualized calls are inlined*, and other dynamic calls are evaluated conservatively (as if no definition were available).
+ == RuntimeDefinition ==
-* Currently, no Objective-C messages are not inlined under -analyzer-ipa=inlining, even if we are reasonably confident of the type of the receiver. We plan to enable this once we have tested our heuristics more thoroughly.
+The basis of devirtualization is CallEvent's getRuntimeDefinition() method,
+which returns a RuntimeDefinition object. When asked to provide a definition,
+the CallEvents for dynamic calls will use the DynamicTypeInfo in their
+ProgramState to attempt to devirtualize the call. In the case of no dynamic
+dispatch, or perfectly constrained devirtualization, the resulting
+RuntimeDefinition contains a Decl corresponding to the definition of the called
+function, and RuntimeDefinition::mayHaveOtherDefinitions will return FALSE.
-The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to "dynamic", but performs a conservative invalidation in the general virtual case in /addition/ to inlining. The details of this are discussed below.
+In the case of dynamic dispatch where our information is not perfect, CallEvent
+can make a guess, but RuntimeDefinition::mayHaveOtherDefinitions will return
+TRUE. The RuntimeDefinition object will then also include a MemRegion
+corresponding to the object being called (i.e., the "receiver" in Objective-C
+parlance), which ExprEngine uses to decide whether or not the call should be
+inlined.
+
+ == Inlining Dynamic Calls ==
+
+The -analyzer-ipa option has five different modes: none, basic-inlining,
+inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all
+dynamic calls are inlined, whether we are certain or not that this will actually
+be the definition used at runtime. Under -analyzer-ipa=inlining, only
+"near-perfect" devirtualized calls are inlined*, and other dynamic calls are
+evaluated conservatively (as if no definition were available).
+
+* Currently, no Objective-C messages are not inlined under
+ -analyzer-ipa=inlining, even if we are reasonably confident of the type of the
+ receiver. We plan to enable this once we have tested our heuristics more
+ thoroughly.
+
+The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to
+"dynamic", but performs a conservative invalidation in the general virtual case
+in *addition* to inlining. The details of this are discussed below.
+
+As stated above, -analyzer-ipa=basic-inlining does not inline any C++ member
+functions or Objective-C method calls, even if they are non-virtual or can be
+safely devirtualized.
Bifurcation
-----------
-ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate mode. When a call is made on a region with dynamic type information, we bifurcate the path and add the region's processing mode to the GDM. Currently, there are 2 modes: DynamicDispatchModeInlined and DynamicDispatchModeConservative. Going forward, we consult the state of the region to make decisions on whether the calls should be inlined or not, which ensures that we have at most one split per region. The modes model the cases when the dynamic type information is perfectly correct and when the info is not correct (i.e. where the region is a subclass of the type we store in DynamicTypeInfo).
-Bifurcation mode allows for increased coverage in cases where the parent method contains code which is only executed when the class is subclassed. The disadvantages of this mode are a (considerable?) performance hit and the possibility of false positives on the path where the conservative mode is used.
+ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate
+mode.
+
+When a call is made on an object with imprecise dynamic type information
+(RuntimeDefinition::mayHaveOtherDefinitions() evaluates to TRUE), ExprEngine
+bifurcates the path and marks the object's region (retrieved from the
+RuntimeDefinition object) with a path-sensitive "mode" in the ProgramState.
+
+Currently, there are 2 modes:
+
+ DynamicDispatchModeInlined - Models the case where the dynamic type information
+ of the receiver (MemoryRegion) is assumed to be perfectly constrained so
+ that a given definition of a method is expected to be the code actually
+ called. When this mode is set, ExprEngine uses the Decl from
+ RuntimeDefinition to inline any dynamically dispatched call sent to this
+ receiver because the function definition is considered to be fully resolved.
+
+ DynamicDispatchModeConservative - Models the case where the dynamic type
+ information is assumed to be incorrect, for example, implies that the method
+ definition is overriden in a subclass. In such cases, ExprEngine does not
+ inline the methods sent to the receiver (MemoryRegion), even if a candidate
+ definition is available. This mode is conservative about simulating the
+ effects of a call.
+Going forward along the symbolic execution path, ExprEngine consults the mode
+of the receiver's MemRegion to make decisions on whether the calls should be
+inlined or not, which ensures that there is at most one split per region.
+
+At a high level, "bifurcation mode" allows for increased semantic coverage in
+cases where the parent method contains code which is only executed when the
+class is subclassed. The disadvantages of this mode are a (considerable?)
+performance hit and the possibility of false positives on the path where the
+conservative mode is used.
Objective-C Message Heuristics
------------------------------
-We rely on a set of heuristics to partition the set of ObjC method calls into ones that require bifurcation and ones that do not (can or cannot be a subclass). Below are the cases when we consider that the dynamic type of the object is precise (cannot be a subclass):
- - If the object was created with +alloc or +new and initialized with an -init method.
- - If the calls are property accesses using dot syntax. This is based on the assumption that children rarely override properties, or do so in an essentially compatible way.
- - If the class interface is declared inside the main source file. In this case it is unlikely that it will be subclassed.
- - If the method is not declared outside of main source file, either by the receiver's class or by any superclasses.
+ExprEngine relies on a set of heuristics to partition the set of Objective-C
+method calls into those that require bifurcation and those that do not. Below
+are the cases when the DynamicTypeInfo of the object is considered precise
+(cannot be a subclass):
+
+ - If the object was created with +alloc or +new and initialized with an -init
+ method.
+
+ - If the calls are property accesses using dot syntax. This is based on the
+ assumption that children rarely override properties, or do so in an
+ essentially compatible way.
+
+ - If the class interface is declared inside the main source file. In this case
+ it is unlikely that it will be subclassed.
-C++ Inlining Caveats
+ - If the method is not declared outside of main source file, either by the
+ receiver's class or by any superclasses.
+
+C++ Caveats
--------------------
-C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is being constructed or destructed; that is, the type of the object depends on which base constructors have been completed. This is tracked using dynamic type info in the DynamicTypePropagation checker.
-Temporaries are poorly modelled right now because we're not confident in the placement
+C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is
+being constructed or destructed; that is, the type of the object depends on
+which base constructors have been completed. This is tracked using
+DynamicTypeInfo in the DynamicTypePropagation checker.
+
+There are several limitations in the current implementation:
-'new' is poorly modelled due to some nasty CFG/design issues (elaborated in PR12014). 'delete' is essentially not modelled at all.
+- Temporaries are poorly modeled right now because we're not confident in the
+ placement of their destructors in the CFG. We currently won't inline their
+ constructors unless the destructor is trivial, and don't process their
+ destructors at all, not even to invalidate the region.
-Arrays of objects are modeled very poorly right now. We run only the first constructor and first destructor. Because of this, we don't inline any constructors or destructors for arrays.
+- 'new' is poorly modeled due to some nasty CFG/design issues. This is tracked
+ in PR12014. 'delete' is not modeled at all.
+
+- Arrays of objects are modeled very poorly right now. ExprEngine currently
+ only simulates the first constructor and first destructor. Because of this,
+ ExprEngine does not inline any constructors or destructors for arrays.
CallEvent
=========
-A CallEvent represents a specific call to a function, method, or other body of code. It is path-sensitive, containing both the current state (ProgramStateRef) and stack space (LocationContext), and provides uniform access to the argument values and return type of a call, no matter how the call is written in the source or what sort of code body is being invoked.
+A CallEvent represents a specific call to a function, method, or other body of
+code. It is path-sensitive, containing both the current state (ProgramStateRef)
+and stack space (LocationContext), and provides uniform access to the argument
+values and return type of a call, no matter how the call is written in the
+source or what sort of code body is being invoked.
+
+ NOTE: For those familiar with Cocoa, CallEvent is roughly equivalent to
+ NSInvocation.
-(For those familiar with Cocoa, CallEvent is roughly equivalent to NSInvocation.)
+CallEvent should be used whenever there is logic dealing with function calls
+that does not care how the call occurred.
-CallEvent should be used whenever there is logic dealing with function calls that does not care how the call occurred. Examples include checking that arguments satisfy preconditions (such as __attribute__((nonnull))), and attempting to inline a call.
+Examples include checking that arguments satisfy preconditions (such as
+__attribute__((nonnull))), and attempting to inline a call.
-CallEvents are reference-counted objects managed by a CallEventManager. While there is no inherent issue with persisting them (say, in the state's GDM), they are intended for short-lived use, and can be recreated from CFGElements or StackFrameContexts fairly easily.
+CallEvents are reference-counted objects managed by a CallEventManager. While
+there is no inherent issue with persisting them (say, in a ProgramState's GDM),
+they are intended for short-lived use, and can be recreated from CFGElements or
+non-top-level StackFrameContexts fairly easily.
diff --git a/docs/analyzer/debug-checks.txt b/docs/analyzer/debug-checks.txt
new file mode 100644
index 000000000000..6ac451fbbbd1
--- /dev/null
+++ b/docs/analyzer/debug-checks.txt
@@ -0,0 +1,89 @@
+The analyzer contains a number of checkers which can aid in debugging. Enable them by using the "-analyzer-checker=" flag, followed by the name of the checker.
+
+General Analysis Dumpers
+========================
+These checkers are used to dump the results of various infrastructural analyses to stderr. Some checkers also have "view" variants, which will display a graph using a 'dot' format viewer (such as Graphviz on OS X) instead.
+
+- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for the current translation unit. This is used to determine the order in which to analyze functions when inlining is enabled.
+- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level function being analyzed.
+- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level function.
+- debug.DumpLiveVars: Show the results of live variable analysis for each top-level function being analyzed.
+
+
+Path Tracking
+=============
+These checkers print information about the path taken by the analyzer engine.
+
+- debug.DumpCalls: Prints out every function or method call encountered during a path traversal. This is indented to show the call stack, but does NOT do any special handling of branches, meaning different paths could end up interleaved.
+- debug.DumpTraversal: Prints the name of each branch statement encountered during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check whether the analysis engine is doing BFS or DFS.
+
+
+State Checking
+==============
+These checkers will print out information about the analyzer state in the form of analysis warnings. They are intended for use with the -verify functionality in regression tests.
+
+- debug.TaintTest: Prints out the word "tainted" for every expression that carries taint. At the time of this writing, taint was only introduced by the checks under experimental.security.taint.TaintPropagation; this checker may eventually move to the security.taint package.
+- debug.ExprInspection: Responds to certain function calls, which are modeled after builtins. These function calls should affect the program state other than the evaluation of their arguments; to use them, you will need to declare them within your test file. The available functions are described below.
+
+(FIXME: debug.ExprInspection should probably be renamed, since it no longer only inspects expressions.)
+
+
+ExprInspection checks
+---------------------
+
+- void clang_analyzer_eval(bool);
+
+Prints TRUE if the argument is known to have a non-zero value,
+ FALSE if the argument is known to have a zero or null value, and
+ UNKNOWN if the argument isn't sufficiently constrained on this path.
+You can use this to test other values by using expressions like "x == 5".
+Note that this functionality is currently DISABLED in inlined functions,
+since different calls to the same inlined function could provide different
+information, making it difficult to write proper -verify directives.
+
+In C, the argument can be typed as 'int' or as '_Bool'.
+
+Example usage:
+ clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
+ if (!x) return;
+ clang_analyzer_eval(x); // expected-warning{{TRUE}}
+
+
+- void clang_analyzer_checkInlined(bool);
+
+If a call occurs within an inlined function, prints TRUE or FALSE according to
+the value of its argument. If a call occurs outside an inlined function,
+nothing is printed.
+
+The intended use of this checker is to assert that a function is inlined at
+least once (by passing 'true' and expecting a warning), or to assert that a
+function is never inlined (by passing 'false' and expecting no warning). The
+argument is technically unnecessary but is intended to clarify intent.
+
+You might wonder why we can't print TRUE if a function is ever inlined and
+FALSE if it is not. The problem is that any inlined function could conceivably
+also be analyzed as a top-level function (in which case both TRUE and FALSE
+would be printed), depending on the value of the -analyzer-inlining option.
+
+In C, the argument can be typed as 'int' or as '_Bool'.
+
+Example usage:
+ int inlined() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ return 42;
+ }
+
+ void topLevel() {
+ clang_analyzer_checkInlined(false); // no-warning (not inlined)
+ int value = inlined();
+ // This assertion will not be valid if the previous call was not inlined.
+ clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
+ }
+
+
+
+Statistics
+==========
+The debug.Stats checker collects various information about the analysis of each function, such as how many blocks were reached and if the analyzer timed out.
+
+There is also an additional -analyzer-stats flag, which enables various statistics within the analyzer engine. Note the Stats checker (which produces at least one bug report per function) may actually change the values reported by -analyzer-stats.
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 425a91ef037d..9628d473b7c7 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -132,7 +132,7 @@ Treat subsequent input files as having type I<language>.
Specify the language standard to compile for.
-=item B<-stdlib>=I<language>
+=item B<-stdlib>=I<library>
Specify the C++ standard library to use; supported options are libstdc++ and
libc++.
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
new file mode 100644
index 000000000000..bc5f1a64a5c6
--- /dev/null
+++ b/docs/tools/dump_ast_matchers.py
@@ -0,0 +1,264 @@
+#!/usr/bin/env python
+# A tool to parse ASTMatchers.h and update the documentation in
+# ../LibASTMatchersReference.html automatically. Run from the
+# directory in which this file is located to update the docs.
+
+import collections
+import re
+import urllib2
+
+MATCHERS_FILE = '../../include/clang/ASTMatchers/ASTMatchers.h'
+
+# Each matcher is documented in one row of the form:
+# result | name | argA
+# The subsequent row contains the documentation and is hidden by default,
+# becoming visible via javascript when the user clicks the matcher name.
+TD_TEMPLATE="""
+<tr><td>%(result)s</td><td class="name" onclick="toggle('%(id)s')"><a name="%(id)sAnchor">%(name)s</a></td><td>%(args)s</td></tr>
+<tr><td colspan="4" class="doc" id="%(id)s"><pre>%(comment)s</pre></td></tr>
+"""
+
+# We categorize the matchers into these three categories in the reference:
+node_matchers = {}
+narrowing_matchers = {}
+traversal_matchers = {}
+
+# We output multiple rows per matcher if the matcher can be used on multiple
+# node types. Thus, we need a new id per row to control the documentation
+# pop-up. ids[name] keeps track of those ids.
+ids = collections.defaultdict(int)
+
+# Cache for doxygen urls we have already verified.
+doxygen_probes = {}
+
+def esc(text):
+ """Escape any html in the given text."""
+ text = re.sub(r'&', '&amp;', text)
+ text = re.sub(r'<', '&lt;', text)
+ text = re.sub(r'>', '&gt;', text)
+ def link_if_exists(m):
+ name = m.group(1)
+ url = 'http://clang.llvm.org/doxygen/classclang_1_1%s.html' % name
+ if url not in doxygen_probes:
+ try:
+ print 'Probing %s...' % url
+ urllib2.urlopen(url)
+ doxygen_probes[url] = True
+ except:
+ doxygen_probes[url] = False
+ if doxygen_probes[url]:
+ return r'Matcher&lt<a href="%s">%s</a>&gt;' % (url, name)
+ else:
+ return m.group(0)
+ text = re.sub(
+ r'Matcher&lt;([^\*&]+)&gt;', link_if_exists, text)
+ return text
+
+def extract_result_types(comment):
+ """Extracts a list of result types from the given comment.
+
+ We allow annotations in the comment of the matcher to specify what
+ nodes a matcher can match on. Those comments have the form:
+ Usable as: Any Matcher | (Matcher<T1>[, Matcher<t2>[, ...]])
+
+ Returns ['*'] in case of 'Any Matcher', or ['T1', 'T2', ...].
+ Returns the empty list if no 'Usable as' specification could be
+ parsed.
+ """
+ result_types = []
+ m = re.search(r'Usable as: Any Matcher[\s\n]*$', comment, re.S)
+ if m:
+ return ['*']
+ while True:
+ m = re.match(r'^(.*)Matcher<([^>]+)>\s*,?[\s\n]*$', comment, re.S)
+ if not m:
+ if re.search(r'Usable as:\s*$', comment):
+ return result_types
+ else:
+ return None
+ result_types += [m.group(2)]
+ comment = m.group(1)
+
+def strip_doxygen(comment):
+ """Returns the given comment without \-escaped words."""
+ # If there is only a doxygen keyword in the line, delete the whole line.
+ comment = re.sub(r'^\\[^\s]+\n', r'', comment, flags=re.M)
+ # Delete the doxygen command and the following whitespace.
+ comment = re.sub(r'\\[^\s]+\s+', r'', comment)
+ return comment
+
+def unify_arguments(args):
+ """Gets rid of anything the user doesn't care about in the argument list."""
+ args = re.sub(r'internal::', r'', args)
+ args = re.sub(r'const\s+', r'', args)
+ args = re.sub(r'&', r' ', args)
+ args = re.sub(r'(^|\s)M\d?(\s)', r'\1Matcher<*>\2', args)
+ return args
+
+def add_matcher(result_type, name, args, comment, is_dyncast=False):
+ """Adds a matcher to one of our categories."""
+ if name == 'id':
+ # FIXME: Figure out whether we want to support the 'id' matcher.
+ return
+ matcher_id = '%s%d' % (name, ids[name])
+ ids[name] += 1
+ args = unify_arguments(args)
+ matcher_html = TD_TEMPLATE % {
+ 'result': esc('Matcher<%s>' % result_type),
+ 'name': name,
+ 'args': esc(args),
+ 'comment': esc(strip_doxygen(comment)),
+ 'id': matcher_id,
+ }
+ if is_dyncast:
+ node_matchers[result_type + name] = matcher_html
+ # Use a heuristic to figure out whether a matcher is a narrowing or
+ # traversal matcher. By default, matchers that take other matchers as
+ # arguments (and are not node matchers) do traversal. We specifically
+ # exclude known narrowing matchers that also take other matchers as
+ # arguments.
+ elif ('Matcher<' not in args or
+ name in ['allOf', 'anyOf', 'anything', 'unless']):
+ narrowing_matchers[result_type + name] = matcher_html
+ else:
+ traversal_matchers[result_type + name] = matcher_html
+
+def act_on_decl(declaration, comment, allowed_types):
+ """Parse the matcher out of the given declaration and comment.
+
+ If 'allowed_types' is set, it contains a list of node types the matcher
+ can match on, as extracted from the static type asserts in the matcher
+ definition.
+ """
+ if declaration.strip():
+ # Node matchers are defined by writing:
+ # VariadicDynCastAllOfMatcher<ResultType, ArgumentType> name;
+ m = re.match(r""".*VariadicDynCastAllOfMatcher\s*<
+ \s*([^\s,]+)\s*,
+ \s*([^\s>]+)\s*>
+ \s*([^\s;]+)\s*;\s*$""", declaration, flags=re.X)
+ if m:
+ result, inner, name = m.groups()
+ add_matcher(result, name, 'Matcher<%s>...' % inner,
+ comment, is_dyncast=True)
+ return
+
+ # Parse the various matcher definition macros.
+ m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)\(
+ (?:\s*([^\s,]+)\s*,)?
+ \s*([^\s,]+)\s*
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ \)\s*{\s*$""", declaration, flags=re.X)
+ if m:
+ p, n, result, name = m.groups()[1:5]
+ args = m.groups()[5:]
+ if not result:
+ if not allowed_types:
+ raise Exception('Did not find allowed result types for: %s' % name)
+ result_types = allowed_types
+ else:
+ result_types = [result]
+ 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
+
+ # Parse free standing matcher functions, like:
+ # Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
+ m = re.match(r"""^\s*(.*)\s+
+ ([^\s\(]+)\s*\(
+ (.*)
+ \)\s*{""", declaration, re.X)
+ if m:
+ result, name, args = m.groups()
+ args = ', '.join(p.strip() for p in args.split(','))
+ m = re.match(r'.*\s+internal::Matcher<([^>]+)>$', result)
+ if m:
+ result_types = [m.group(1)]
+ else:
+ result_types = extract_result_types(comment)
+ if not result_types:
+ if not comment:
+ # Only overloads don't have their own doxygen comments; ignore those.
+ print 'Ignoring "%s"' % name
+ else:
+ print 'Cannot determine result type for "%s"' % name
+ else:
+ for result_type in result_types:
+ add_matcher(result_type, name, args, comment)
+ else:
+ print '*** Unparsable: "' + declaration + '" ***'
+
+def sort_table(matcher_type, matcher_map):
+ """Returns the sorted html table for the given row map."""
+ table = ''
+ for key in sorted(matcher_map.keys()):
+ table += matcher_map[key] + '\n'
+ return ('<!-- START_%(type)s_MATCHERS -->\n' +
+ '%(table)s' +
+ '<!--END_%(type)s_MATCHERS -->') % {
+ 'type': matcher_type,
+ 'table': table,
+ }
+
+# Parse the ast matchers.
+# We alternate between two modes:
+# body = True: We parse the definition of a matcher. We need
+# to parse the full definition before adding a matcher, as the
+# definition might contain static asserts that specify the result
+# type.
+# body = False: We parse the comments and declaration of the matcher.
+comment = ''
+declaration = ''
+allowed_types = []
+body = False
+for line in open(MATCHERS_FILE).read().splitlines():
+ if body:
+ if line.strip() and line[0] == '}':
+ if declaration:
+ act_on_decl(declaration, comment, allowed_types)
+ comment = ''
+ declaration = ''
+ allowed_types = []
+ body = False
+ else:
+ m = re.search(r'is_base_of<([^,]+), NodeType>', line)
+ if m and m.group(1):
+ allowed_types += [m.group(1)]
+ continue
+ if line.strip() and line.lstrip()[0] == '/':
+ comment += re.sub(r'/+\s?', '', line) + '\n'
+ else:
+ declaration += ' ' + line
+ if ((not line.strip()) or
+ line.rstrip()[-1] == ';' or
+ line.rstrip()[-1] == '{'):
+ if line.strip() and line.rstrip()[-1] == '{':
+ body = True
+ else:
+ act_on_decl(declaration, comment, allowed_types)
+ comment = ''
+ declaration = ''
+ allowed_types = []
+
+node_matcher_table = sort_table('DECL', node_matchers)
+narrowing_matcher_table = sort_table('NARROWING', narrowing_matchers)
+traversal_matcher_table = sort_table('TRAVERSAL', traversal_matchers)
+
+reference = open('../LibASTMatchersReference.html').read()
+reference = re.sub(r'<!-- START_DECL_MATCHERS.*END_DECL_MATCHERS -->',
+ '%s', reference, flags=re.S) % node_matcher_table
+reference = re.sub(r'<!-- START_NARROWING_MATCHERS.*END_NARROWING_MATCHERS -->',
+ '%s', reference, flags=re.S) % narrowing_matcher_table
+reference = re.sub(r'<!-- START_TRAVERSAL_MATCHERS.*END_TRAVERSAL_MATCHERS -->',
+ '%s', reference, flags=re.S) % traversal_matcher_table
+
+with open('../LibASTMatchersReference.html', 'w') as output:
+ output.write(reference)
+
diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp
index 48a979548f9b..0b3c0cf6dc90 100644
--- a/examples/analyzer-plugin/MainCallChecker.cpp
+++ b/examples/analyzer-plugin/MainCallChecker.cpp
@@ -39,7 +39,7 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const
BugReport *report = new BugReport(*BT, BT->getName(), N);
report->addRange(Callee->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index 9abefc274b1e..06d3d03320ca 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -29,7 +29,8 @@ target_link_libraries(clang-interpreter
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangAnalysis
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangAST
clangParse
clangLex
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index 420a066caaaf..0c4d35c8ebd2 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -20,7 +20,7 @@ LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
- clangAnalysis.a clangRewrite.a \
+ clangAnalysis.a clangRewriteCore.a clangRewriteFrontend.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index c39468a3fd9c..84e4c7137eb2 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -13,9 +13,9 @@
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/Module.h"
#include "llvm/ADT/OwningPtr.h"
@@ -69,11 +69,12 @@ 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]);
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- DiagnosticsEngine Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
"a.out", /*IsProduction=*/false, Diags);
TheDriver.setTitle("clang interpreter");
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index edd3cbb4a7f4..aa3403cc80c4 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -23,6 +23,34 @@
#include "clang-c/Platform.h"
#include "clang-c/CXString.h"
+/**
+ * \brief The version constants for the libclang API.
+ * CINDEX_VERSION_MINOR should increase when there are API additions.
+ * CINDEX_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
+ *
+ * The policy about the libclang API was always to keep it source and ABI
+ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
+ */
+#define CINDEX_VERSION_MAJOR 0
+#define CINDEX_VERSION_MINOR 6
+
+#define CINDEX_VERSION_ENCODE(major, minor) ( \
+ ((major) * 10000) \
+ + ((minor) * 1))
+
+#define CINDEX_VERSION CINDEX_VERSION_ENCODE( \
+ CINDEX_VERSION_MAJOR, \
+ CINDEX_VERSION_MINOR )
+
+#define CINDEX_VERSION_STRINGIZE_(major, minor) \
+ #major"."#minor
+#define CINDEX_VERSION_STRINGIZE(major, minor) \
+ CINDEX_VERSION_STRINGIZE_(major, minor)
+
+#define CINDEX_VERSION_STRING CINDEX_VERSION_STRINGIZE( \
+ CINDEX_VERSION_MAJOR, \
+ CINDEX_VERSION_MINOR)
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -383,7 +411,7 @@ CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1,
CXSourceRange range2);
/**
- * \brief Returns non-zero if \arg range is null.
+ * \brief Returns non-zero if \p range is null.
*/
CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range);
@@ -1035,13 +1063,15 @@ enum CXTranslationUnit_Flags {
* code-completion operations.
*/
CXTranslationUnit_CacheCompletionResults = 0x08,
+
/**
- * \brief DEPRECATED: Enable precompiled preambles in C++.
+ * \brief Used to indicate that the translation unit will be serialized with
+ * \c clang_saveTranslationUnit.
*
- * Note: this is a *temporary* option that is available only while
- * we are testing C++ precompiled preamble support. It is deprecated.
+ * This option is typically used when parsing a header with the intent of
+ * producing a precompiled header.
*/
- CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
+ CXTranslationUnit_ForSerialization = 0x10,
/**
* \brief DEPRECATED: Enabled chained precompiled preambles in C++.
@@ -1904,9 +1934,10 @@ enum CXCursorKind {
*/
CXCursor_ReturnStmt = 214,
- /** \brief A GNU inline assembly statement extension.
+ /** \brief A GCC inline assembly statement extension.
*/
- CXCursor_AsmStmt = 215,
+ CXCursor_GCCAsmStmt = 215,
+ CXCursor_AsmStmt = CXCursor_GCCAsmStmt,
/** \brief Objective-C's overall \@try-\@catch-\@finally statement.
*/
@@ -2009,7 +2040,15 @@ enum CXCursorKind {
CXCursor_MacroInstantiation = CXCursor_MacroExpansion,
CXCursor_InclusionDirective = 503,
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
- CXCursor_LastPreprocessing = CXCursor_InclusionDirective
+ CXCursor_LastPreprocessing = CXCursor_InclusionDirective,
+
+ /* Extra Declarations */
+ /**
+ * \brief A module import declaration.
+ */
+ CXCursor_ModuleImportDecl = 600,
+ CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
+ CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl
};
/**
@@ -2040,7 +2079,8 @@ typedef struct {
* \brief A comment AST node.
*/
typedef struct {
- const void *Data;
+ const void *ASTNode;
+ CXTranslationUnit TranslationUnit;
} CXComment;
/**
@@ -2068,9 +2108,9 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
/**
- * \brief Returns non-zero if \arg cursor is null.
+ * \brief Returns non-zero if \p cursor is null.
*/
-CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor);
+CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor cursor);
/**
* \brief Compute a hash value for the given cursor.
@@ -2585,6 +2625,7 @@ enum CXCallingConv {
CXCallingConv_X86Pascal = 5,
CXCallingConv_AAPCS = 6,
CXCallingConv_AAPCS_VFP = 7,
+ CXCallingConv_PnaclCall = 8,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@@ -3164,6 +3205,12 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
/**
+ * \brief Given a cursor pointing to an ObjC message, returns the CXType of the
+ * receiver.
+ */
+CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
+
+/**
* \brief Given a cursor that represents a declaration, return the associated
* comment's source range. The range may include multiple consecutive comments
* with whitespace in between.
@@ -3195,6 +3242,65 @@ CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C);
*/
/**
+ * \defgroup CINDEX_MODULE Module introspection
+ *
+ * The functions in this group provide access to information about modules.
+ *
+ * @{
+ */
+
+typedef void *CXModule;
+
+/**
+ * \brief Given a CXCursor_ModuleImportDecl cursor, return the associated module.
+ */
+CINDEX_LINKAGE CXModule clang_Cursor_getModule(CXCursor C);
+
+/**
+ * \param Module a module object.
+ *
+ * \returns the parent of a sub-module or NULL if the given module is top-level,
+ * e.g. for 'std.vector' it will return the 'std' module.
+ */
+CINDEX_LINKAGE CXModule clang_Module_getParent(CXModule Module);
+
+/**
+ * \param Module a module object.
+ *
+ * \returns the name of the module, e.g. for the 'std.vector' sub-module it
+ * will return "vector".
+ */
+CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module);
+
+/**
+ * \param Module a module object.
+ *
+ * \returns the full name of the module, e.g. "std.vector".
+ */
+CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module);
+
+/**
+ * \param Module a module object.
+ *
+ * \returns the number of top level headers associated with this module.
+ */
+CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXModule Module);
+
+/**
+ * \param Module a module object.
+ *
+ * \param Index top level header index (zero-based).
+ *
+ * \returns the specified top level header associated with the module.
+ */
+CINDEX_LINKAGE
+CXFile clang_Module_getTopLevelHeader(CXModule Module, unsigned Index);
+
+/**
+ * @}
+ */
+
+/**
* \defgroup CINDEX_COMMENT Comment AST introspection
*
* The routines in this group provide access to information in the
@@ -3272,7 +3378,7 @@ enum CXCommentKind {
* \brief A \\param or \\arg command that describes the function parameter
* (name, passing direction, description).
*
- * \brief For example: \\param [in] ParamName description.
+ * For example: \\param [in] ParamName description.
*/
CXComment_ParamCommand = 7,
@@ -3280,7 +3386,7 @@ enum CXCommentKind {
* \brief A \\tparam command that describes a template parameter (name and
* description).
*
- * \brief For example: \\tparam T description.
+ * For example: \\tparam T description.
*/
CXComment_TParamCommand = 8,
@@ -3379,7 +3485,7 @@ CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment);
/**
* \param Comment AST node of any kind.
*
- * \param ArgIdx argument index (zero-based).
+ * \param ChildIdx child index (zero-based).
*
* \returns the specified child of the AST node.
*/
@@ -3692,14 +3798,11 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment);
* A Relax NG schema for the XML can be found in comment-xml-schema.rng file
* inside clang source tree.
*
- * \param TU the translation unit \c Comment belongs to.
- *
* \param Comment a \c CXComment_FullComment AST node.
*
* \returns string containing an XML document.
*/
-CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXTranslationUnit TU,
- CXComment Comment);
+CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
/**
* @}
@@ -4323,8 +4426,7 @@ clang_getCompletionAnnotation(CXCompletionString completion_string,
* \param completion_string The code completion string whose parent is
* being queried.
*
- * \param kind If non-NULL, will be set to the kind of the parent context,
- * or CXCursor_NotImplemented if there is no context.
+ * \param kind DEPRECATED: always set to CXCursor_NotImplemented if non-NULL.
*
* \returns The name of the completion parent, e.g., "NSObject" if
* the completion string represents a method in the NSObject class.
@@ -4917,22 +5019,35 @@ typedef struct {
CXFile file;
int isImport;
int isAngled;
+ /**
+ * \brief Non-zero if the directive was automatically turned into a module
+ * import.
+ */
+ int isModuleImport;
} CXIdxIncludedFileInfo;
/**
* \brief Data for IndexerCallbacks#importedASTFile.
*/
typedef struct {
+ /**
+ * \brief Top level AST file containing the imported PCH, module or submodule.
+ */
CXFile file;
/**
- * \brief Location where the file is imported. It is useful mostly for
- * modules.
+ * \brief The imported module or NULL if the AST file is a PCH.
+ */
+ CXModule module;
+ /**
+ * \brief Location where the file is imported. Applicable only for modules.
*/
CXIdxLoc loc;
/**
- * \brief Non-zero if the AST file is a module otherwise it's a PCH.
+ * \brief Non-zero if an inclusion directive was automatically turned into
+ * a module import. Applicable only for modules.
*/
- int isModule;
+ int isImplicit;
+
} CXIdxImportedASTFileInfo;
typedef enum {
@@ -4965,7 +5080,8 @@ typedef enum {
CXIdxEntity_CXXConstructor = 22,
CXIdxEntity_CXXDestructor = 23,
CXIdxEntity_CXXConversionFunction = 24,
- CXIdxEntity_CXXTypeAlias = 25
+ CXIdxEntity_CXXTypeAlias = 25,
+ CXIdxEntity_CXXInterface = 26
} CXIdxEntityKind;
@@ -5183,8 +5299,8 @@ typedef struct {
*
* AST files will not get indexed (there will not be callbacks to index all
* the entities in an AST file). The recommended action is that, if the AST
- * file is not already indexed, to block further indexing and initiate a new
- * indexing job specific to the AST file.
+ * file is not already indexed, to initiate a new indexing job specific to
+ * the AST file.
*/
CXIdxClientASTFile (*importedASTFile)(CXClientData client_data,
const CXIdxImportedASTFileInfo *);
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index 86a6cbb22aae..cce866165210 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -12,6 +12,7 @@
#include "clang/ARCMigrate/FileRemapper.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/SourceLocation.h"
namespace clang {
class ASTContext;
@@ -51,7 +52,7 @@ bool applyTransformations(CompilerInvocation &origCI,
DiagnosticConsumer *DiagClient);
/// \brief Applies automatic modifications and produces temporary files
-/// and metadata into the \arg outputDir path.
+/// and metadata into the \p outputDir path.
///
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
/// even if the migrator can fix them, but the function will still return false
@@ -68,7 +69,7 @@ bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
bool emitPremigrationARCErrors,
StringRef plistOut);
-/// \brief Get the set of file remappings from the \arg outputDir path that
+/// \brief Get the set of file remappings from the \p outputDir path that
/// migrateWithTemporaryFiles produced.
///
/// \returns false if no error is produced, true otherwise.
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 69a3866969d2..37b0740cb98b 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -19,12 +19,14 @@ namespace clang {
class CXXRecordDecl;
class DeclGroupRef;
class HandleTagDeclDefinition;
+ class PPMutationListener;
class ASTMutationListener;
class ASTDeserializationListener; // layering violation because void* is ugly
class SemaConsumer; // layering violation required for safe SemaConsumer
class TagDecl;
class VarDecl;
class FunctionDecl;
+ class ImportDecl;
/// ASTConsumer - This is an abstract interface that should be implemented by
/// clients that read ASTs. This abstraction layer allows the client to be
@@ -79,6 +81,11 @@ public:
/// The default implementation ignored them.
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
+ /// \brief Handle an ImportDecl that was implicitly created due to an
+ /// inclusion directive.
+ /// The default implementation passes it to HandleTopLevelDecl.
+ virtual void HandleImplicitImportDecl(ImportDecl *D);
+
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be
/// completed.
@@ -105,6 +112,11 @@ public:
/// it was actually used.
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
+ /// \brief If the consumer is interested in preprocessor entities getting
+ /// modified after their initial creation, it should return a pointer to
+ /// a PPMutationListener here.
+ virtual PPMutationListener *GetPPMutationListener() { return 0; }
+
/// \brief If the consumer is interested in entities getting modified after
/// their initial creation, it should return a pointer to
/// an ASTMutationListener here.
@@ -118,9 +130,6 @@ public:
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
-
- // Support isa/cast/dyn_cast
- static bool classof(const ASTConsumer *) { return true; }
};
} // end namespace clang.
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index cad3ad2b5f9c..f0934b77961b 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the ASTContext interface.
-//
+///
+/// \file
+/// \brief Defines the clang::ASTContext interface.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
@@ -28,6 +29,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/RawCommentList.h"
+#include "clang/AST/CommentCommandTraits.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -84,8 +86,8 @@ namespace clang {
class FullComment;
}
-/// ASTContext - This class holds long-lived AST nodes (such as types and
-/// decls) that can be referred to throughout the semantic analysis of a file.
+/// \brief Holds long-lived AST nodes (such as types and decls) that can be
+/// referred to throughout the semantic analysis of a file.
class ASTContext : public RefCountedBase<ASTContext> {
ASTContext &this_() { return *this; }
@@ -144,19 +146,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable NestedNameSpecifier *GlobalNestedNameSpecifier;
friend class NestedNameSpecifier;
- /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
- /// This is lazily created. This is intentionally not serialized.
+ /// \brief A cache mapping from RecordDecls to ASTRecordLayouts.
+ ///
+ /// This is lazily created. This is intentionally not serialized.
mutable llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>
ASTRecordLayouts;
mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>
ObjCLayouts;
- /// TypeInfoMap - A cache from types to size and alignment information.
+ /// \brief A cache from types to size and alignment information.
typedef llvm::DenseMap<const Type*,
std::pair<uint64_t, unsigned> > TypeInfoMap;
mutable TypeInfoMap MemoizedTypeInfo;
- /// KeyFunctions - A cache mapping from CXXRecordDecls to key functions.
+ /// \brief A cache mapping from CXXRecordDecls to key functions.
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
@@ -170,7 +173,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
/// \brief Mapping from class scope functions specialization to their
- /// template patterns.
+ /// template patterns.
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
ClassScopeSpecializationPattern;
@@ -206,17 +209,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// __builtin_va_list type.
mutable TypedefDecl *BuiltinVaListDecl;
- /// \brief The typedef for the predefined 'id' type.
+ /// \brief The typedef for the predefined \c id type.
mutable TypedefDecl *ObjCIdDecl;
- /// \brief The typedef for the predefined 'SEL' type.
+ /// \brief The typedef for the predefined \c SEL type.
mutable TypedefDecl *ObjCSelDecl;
- /// \brief The typedef for the predefined 'Class' type.
+ /// \brief The typedef for the predefined \c Class type.
mutable TypedefDecl *ObjCClassDecl;
- /// \brief The typedef for the predefined 'Protocol' class in Objective-C.
+ /// \brief The typedef for the predefined \c Protocol class in Objective-C.
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
+
+ /// \brief The typedef for the predefined 'BOOL' type.
+ mutable TypedefDecl *BOOLDecl;
// Typedefs which may be provided defining the structure of Objective-C
// pseudo-builtins
@@ -296,9 +302,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
InstantiatedFromStaticDataMember;
/// \brief Keeps track of the declaration from which a UsingDecl was
- /// created during instantiation. The source declaration is always
- /// a UsingDecl, an UnresolvedUsingValueDecl, or an
- /// UnresolvedUsingTypenameDecl.
+ /// created during instantiation.
+ ///
+ /// The source declaration is always a UsingDecl, an UnresolvedUsingValueDecl,
+ /// or an UnresolvedUsingTypenameDecl.
///
/// For example:
/// \code
@@ -337,9 +344,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// mangling context.
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
- /// \brief Mapping that stores parameterIndex values for ParmVarDecls
- /// when that value exceeds the bitfield size of
- /// ParmVarDeclBits.ParameterIndex.
+ /// \brief Mapping that stores parameterIndex values for ParmVarDecls when
+ /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
ParameterIndexTable ParamIndices;
@@ -348,10 +354,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
TranslationUnitDecl *TUDecl;
- /// SourceMgr - The associated SourceManager object.
+ /// \brief The associated SourceManager object.a
SourceManager &SourceMgr;
- /// LangOpts - The language options used to create the AST associated with
+ /// \brief The language options used to create the AST associated with
/// this ASTContext object.
LangOptions &LangOpts;
@@ -387,9 +393,11 @@ public:
OwningPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener;
- clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; }
+ const clang::PrintingPolicy &getPrintingPolicy() const {
+ return PrintingPolicy;
+ }
- void setPrintingPolicy(clang::PrintingPolicy Policy) {
+ void setPrintingPolicy(const clang::PrintingPolicy &Policy) {
PrintingPolicy = Policy;
}
@@ -508,6 +516,8 @@ public:
}
void addComment(const RawComment &RC) {
+ assert(LangOpts.RetainCommentsFromSystemHeaders ||
+ !SourceMgr.isInSystemHeader(RC.getSourceRange().getBegin()));
Comments.addComment(RC, BumpAlloc);
}
@@ -522,7 +532,22 @@ public:
/// Return parsed documentation comment attached to a given declaration.
/// Returns NULL if no comment is attached.
- comments::FullComment *getCommentForDecl(const Decl *D) const;
+ ///
+ /// \param PP the Preprocessor used with this TU. Could be NULL if
+ /// preprocessor is not available.
+ comments::FullComment *getCommentForDecl(const Decl *D,
+ const Preprocessor *PP) const;
+
+ comments::FullComment *cloneFullComment(comments::FullComment *FC,
+ const Decl *D) const;
+
+private:
+ mutable comments::CommandTraits CommentCommandTraits;
+
+public:
+ comments::CommandTraits &getCommentCommandTraits() const {
+ return CommentCommandTraits;
+ }
/// \brief Retrieve the attributes for the given declaration.
AttrVec& getDeclAttrs(const Decl *D);
@@ -547,7 +572,7 @@ public:
TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation());
- /// \brief If the given using decl is an instantiation of a
+ /// \brief If the given using decl \p Inst is an instantiation of a
/// (possibly unresolved) using decl from a template instantiation,
/// return it.
NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst);
@@ -564,28 +589,28 @@ public:
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
- /// ZeroBitfieldFollowsNonBitfield - return 'true" if 'FD' is a zero-length
- /// bitfield which follows the non-bitfield 'LastFD'.
+ /// \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;
- /// ZeroBitfieldFollowsBitfield - return 'true" if 'FD' is a zero-length
- /// bitfield which follows the bitfield 'LastFD'.
+ /// \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;
- /// BitfieldFollowsBitfield - return 'true" if 'FD' is a
- /// bitfield which follows the bitfield 'LastFD'.
+ /// \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;
- /// NonBitfieldFollowsBitfield - return 'true" if 'FD' is not a
- /// bitfield which follows the bitfield 'LastFD'.
+ /// \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;
- /// BitfieldFollowsNonBitfield - return 'true" if 'FD' is a
- /// bitfield which follows the none bitfield 'LastFD'.
+ /// \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;
@@ -603,6 +628,17 @@ public:
/// Overridden method.
void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
+
+ /// \brief Return C++ or ObjC overridden methods for the given \p Method.
+ ///
+ /// An ObjC method is considered to override any method in the class's
+ /// base classes, its protocols, or its categories' protocols, that has
+ /// the same selector and is of the same kind (class or instance).
+ /// A method in an implementation is not considered as overriding the same
+ /// method in the interface or its categories.
+ void getOverriddenMethods(
+ const NamedDecl *Method,
+ SmallVectorImpl<const NamedDecl *> &Overridden) const;
/// \brief Notify the AST context that a new import declaration has been
/// parsed or implicitly created within this translation unit.
@@ -673,6 +709,7 @@ public:
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+ CanQualType BuiltinFnTy;
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
CanQualType ObjCBuiltinBoolTy;
@@ -731,77 +768,85 @@ public:
//===--------------------------------------------------------------------===//
private:
- /// getExtQualType - Return a type with extended qualifiers.
+ /// \brief Return a type with extended qualifiers.
QualType getExtQualType(const Type *Base, Qualifiers Quals) const;
QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const;
public:
- /// getAddSpaceQualType - Return the uniqued reference to the type for an
- /// address space qualified type with the specified type and address space.
+ /// \brief Return the uniqued reference to the type for an address space
+ /// qualified type with the specified type and address space.
+ ///
/// The resulting type has a union of the qualifiers from T and the address
/// space. If T already has an address space specifier, it is silently
/// replaced.
QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
- /// getObjCGCQualType - Returns the uniqued reference to the type for an
- /// objc gc qualified type. The retulting type has a union of the qualifiers
- /// from T and the gc attribute.
+ /// \brief Return the uniqued reference to the type for an Objective-C
+ /// gc-qualified type.
+ ///
+ /// The retulting type has a union of the qualifiers from T and the gc
+ /// attribute.
QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr) const;
- /// getRestrictType - Returns the uniqued reference to the type for a
- /// 'restrict' qualified type. The resulting type has a union of the
- /// qualifiers from T and 'restrict'.
+ /// \brief Return the uniqued reference to the type for a \c restrict
+ /// qualified type.
+ ///
+ /// The resulting type has a union of the qualifiers from \p T and
+ /// \c restrict.
QualType getRestrictType(QualType T) const {
return T.withFastQualifiers(Qualifiers::Restrict);
}
- /// getVolatileType - Returns the uniqued reference to the type for a
- /// 'volatile' qualified type. The resulting type has a union of the
- /// qualifiers from T and 'volatile'.
+ /// \brief Return the uniqued reference to the type for a \c volatile
+ /// qualified type.
+ ///
+ /// The resulting type has a union of the qualifiers from \p T and
+ /// \c volatile.
QualType getVolatileType(QualType T) const {
return T.withFastQualifiers(Qualifiers::Volatile);
}
- /// getConstType - Returns the uniqued reference to the type for a
- /// 'const' qualified type. The resulting type has a union of the
- /// qualifiers from T and 'const'.
+ /// \brief Return the uniqued reference to the type for a \c const
+ /// qualified type.
///
- /// It can be reasonably expected that this will always be
- /// equivalent to calling T.withConst().
+ /// The resulting type has a union of the qualifiers from \p T and \c const.
+ ///
+ /// It can be reasonably expected that this will always be equivalent to
+ /// calling T.withConst().
QualType getConstType(QualType T) const { return T.withConst(); }
- /// adjustFunctionType - Change the ExtInfo on a function type.
+ /// \brief Change the ExtInfo on a function type.
const FunctionType *adjustFunctionType(const FunctionType *Fn,
FunctionType::ExtInfo EInfo);
- /// getComplexType - Return the uniqued reference to the type for a complex
+ /// \brief Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType getComplexType(QualType T) const;
CanQualType getComplexType(CanQualType T) const {
return CanQualType::CreateUnsafe(getComplexType((QualType) T));
}
- /// getPointerType - Return the uniqued reference to the type for a pointer to
+ /// \brief Return the uniqued reference to the type for a pointer to
/// the specified type.
QualType getPointerType(QualType T) const;
CanQualType getPointerType(CanQualType T) const {
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
}
- /// getAtomicType - Return the uniqued reference to the atomic type for
- /// the specified type.
+ /// \brief Return the uniqued reference to the atomic type for the specified
+ /// type.
QualType getAtomicType(QualType T) const;
- /// getBlockPointerType - Return the uniqued reference to the type for a block
- /// of the specified type.
+ /// \brief Return the uniqued reference to the type for a block of the
+ /// specified type.
QualType getBlockPointerType(QualType T) const;
- /// This gets the struct used to keep track of the descriptor for pointer to
+ /// Gets the struct used to keep track of the descriptor for pointer to
/// blocks.
QualType getBlockDescriptorType() const;
- /// This gets the struct used to keep track of the extended descriptor for
+ /// Gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
@@ -812,78 +857,82 @@ public:
return cudaConfigureCallDecl;
}
- /// This builds the struct used for __block variables.
+ /// Builds the struct used for __block variables.
QualType BuildByRefType(StringRef DeclName, QualType Ty) const;
/// Returns true iff we need copy/dispose helpers for the given type.
bool BlockRequiresCopying(QualType Ty) const;
- /// getLValueReferenceType - Return the uniqued reference to the type for an
- /// lvalue reference to the specified type.
+ /// \brief Return the uniqued reference to the type for an lvalue reference
+ /// to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true)
const;
- /// getRValueReferenceType - Return the uniqued reference to the type for an
- /// rvalue reference to the specified type.
+ /// \brief Return the uniqued reference to the type for an rvalue reference
+ /// to the specified type.
QualType getRValueReferenceType(QualType T) const;
- /// getMemberPointerType - Return the uniqued reference to the type for a
- /// member pointer to the specified type in the specified class. The class
- /// is a Type because it could be a dependent name.
+ /// \brief Return the uniqued reference to the type for a member pointer to
+ /// the specified type in the specified class.
+ ///
+ /// The class \p Cls is a \c Type because it could be a dependent name.
QualType getMemberPointerType(QualType T, const Type *Cls) const;
- /// getVariableArrayType - Returns a non-unique reference to the type for a
- /// variable array of the specified element type.
+ /// \brief Return a non-unique reference to the type for a variable array of
+ /// the specified element type.
QualType getVariableArrayType(QualType EltTy, Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals,
SourceRange Brackets) const;
- /// getDependentSizedArrayType - Returns a non-unique reference to
- /// the type for a dependently-sized array of the specified element
- /// type. FIXME: We will need these to be uniqued, or at least
- /// comparable, at some point.
+ /// \brief Return a non-unique reference to the type for a dependently-sized
+ /// array of the specified element type.
+ ///
+ /// FIXME: We will need these to be uniqued, or at least comparable, at some
+ /// point.
QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals,
SourceRange Brackets) const;
- /// getIncompleteArrayType - Returns a unique reference to the type for a
- /// incomplete array of the specified element type.
+ /// \brief Return a unique reference to the type for an incomplete array of
+ /// the specified element type.
QualType getIncompleteArrayType(QualType EltTy,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;
- /// getConstantArrayType - Return the unique reference to the type for a
- /// constant array of the specified element type.
+ /// \brief Return the unique reference to the type for a constant array of
+ /// the specified element type.
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;
- /// getVariableArrayDecayedType - Returns a vla type where known sizes
- /// are replaced with [*].
+ /// \brief Returns a vla type where known sizes are replaced with [*].
QualType getVariableArrayDecayedType(QualType Ty) const;
- /// getVectorType - Return the unique reference to a vector type of
- /// the specified element type and size. VectorType must be a built-in type.
+ /// \brief Return the unique reference to a vector type of the specified
+ /// element type and size.
+ ///
+ /// \pre \p VectorType must be a built-in type.
QualType getVectorType(QualType VectorType, unsigned NumElts,
VectorType::VectorKind VecKind) const;
- /// getExtVectorType - Return the unique reference to an extended vector type
- /// of the specified element type and size. VectorType must be a built-in
- /// type.
+ /// \brief Return the unique reference to an extended vector type
+ /// of the specified element type and size.
+ ///
+ /// \pre \p VectorType must be a built-in type.
QualType getExtVectorType(QualType VectorType, unsigned NumElts) const;
- /// getDependentSizedExtVectorType - Returns a non-unique reference to
- /// the type for a dependently-sized vector of the specified element
- /// type. FIXME: We will need these to be uniqued, or at least
- /// comparable, at some point.
+ /// \pre Return a non-unique reference to the type for a dependently-sized
+ /// vector of the specified element type.
+ ///
+ /// FIXME: We will need these to be uniqued, or at least comparable, at some
+ /// point.
QualType getDependentSizedExtVectorType(QualType VectorType,
Expr *SizeExpr,
SourceLocation AttrLoc) const;
- /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
- ///
+ /// \brief Return a K&R style C function type like 'int()'.
QualType getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const;
@@ -891,14 +940,13 @@ public:
return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo());
}
- /// getFunctionType - Return a normal function type with a typed
- /// argument list.
+ /// \brief Return a normal function type with a typed argument list.
QualType getFunctionType(QualType ResultTy,
const QualType *Args, unsigned NumArgs,
const FunctionProtoType::ExtProtoInfo &EPI) const;
- /// getTypeDeclType - Return the unique reference to the type for
- /// the specified type declaration.
+ /// \brief Return the unique reference to the type for the specified type
+ /// declaration.
QualType getTypeDeclType(const TypeDecl *Decl,
const TypeDecl *PrevDecl = 0) const {
assert(Decl && "Passed null for Decl param");
@@ -913,8 +961,8 @@ public:
return getTypeDeclTypeSlow(Decl);
}
- /// getTypedefType - Return the unique reference to the type for the
- /// specified typedef-name decl.
+ /// \brief Return the unique reference to the type for the specified
+ /// typedef-name decl.
QualType getTypedefType(const TypedefNameDecl *Decl,
QualType Canon = QualType()) const;
@@ -986,69 +1034,75 @@ public:
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const;
- /// getObjCObjectPointerType - Return a ObjCObjectPointerType type
- /// for the given ObjCObjectType.
+ /// \brief Return a ObjCObjectPointerType type for the given ObjCObjectType.
QualType getObjCObjectPointerType(QualType OIT) const;
- /// getTypeOfType - GCC extension.
+ /// \brief GCC extension.
QualType getTypeOfExprType(Expr *e) const;
QualType getTypeOfType(QualType t) const;
- /// getDecltypeType - C++0x decltype.
+ /// \brief C++11 decltype.
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
- /// getUnaryTransformType - unary type transforms
+ /// \brief Unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind UKind) const;
- /// getAutoType - C++0x deduced auto type.
+ /// \brief C++11 deduced auto type.
QualType getAutoType(QualType DeducedType) const;
- /// getAutoDeductType - C++0x deduction pattern for 'auto' type.
+ /// \brief C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
- /// getAutoRRefDeductType - C++0x deduction pattern for 'auto &&' type.
+ /// \brief C++11 deduction pattern for 'auto &&' type.
QualType getAutoRRefDeductType() const;
- /// getTagDeclType - Return the unique reference to the type for the
- /// specified TagDecl (struct/union/class/enum) decl.
+ /// \brief Return the unique reference to the type for the specified TagDecl
+ /// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
- /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined
- /// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
+ /// \brief Return the unique type for "size_t" (C99 7.17), defined in
+ /// <stddef.h>.
+ ///
+ /// The sizeof operator requires this (C99 6.5.3.4p4).
CanQualType getSizeType() const;
- /// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5),
- /// defined in <stdint.h>.
+ /// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in
+ /// <stdint.h>.
CanQualType getIntMaxType() const;
- /// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5),
- /// defined in <stdint.h>.
+ /// \brief Return the unique type for "uintmax_t" (C99 7.18.1.5), defined in
+ /// <stdint.h>.
CanQualType getUIntMaxType() const;
- /// getWCharType - In C++, this returns the unique wchar_t type. In C99, this
+ /// \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.
QualType getWCharType() const { return WCharTy; }
- /// getSignedWCharType - Return the type of "signed wchar_t".
+ /// \brief Return the type of "signed wchar_t".
+ ///
/// Used when in C++, as a GCC extension.
QualType getSignedWCharType() const;
- /// getUnsignedWCharType - Return the type of "unsigned wchar_t".
+ /// \brief Return the type of "unsigned wchar_t".
+ ///
/// Used when in C++, as a GCC extension.
QualType getUnsignedWCharType() const;
- /// getWIntType - In C99, this returns a type compatible with the type
+ /// \brief In C99, this returns a type compatible with the type
/// defined in <stddef.h> as defined by the target.
QualType getWIntType() const { return WIntTy; }
- /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
- /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
+ /// \brief Return the unique type for "ptrdiff_t" (C99 7.17) defined in
+ /// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
- // getCFConstantStringType - Return the C structure type used to represent
- // constant CFStrings.
+ /// \brief Return the unique type for "pid_t" defined in
+ /// <sys/types.h>. We need this to compute the correct type for vfork().
+ QualType getProcessIDType() const;
+
+ /// \brief Return the C structure type used to represent constant CFStrings.
QualType getCFConstantStringType() const;
/// Get the structure type used to representation CFStrings, or NULL
@@ -1074,21 +1128,21 @@ public:
ObjCNSStringType = T;
}
- /// \brief Retrieve the type that 'id' has been defined to, which may be
- /// different from the built-in 'id' if 'id' has been typedef'd.
+ /// \brief Retrieve the type that \c id has been defined to, which may be
+ /// different from the built-in \c id if \c id has been typedef'd.
QualType getObjCIdRedefinitionType() const {
if (ObjCIdRedefinitionType.isNull())
return getObjCIdType();
return ObjCIdRedefinitionType;
}
- /// \brief Set the user-written type that redefines 'id'.
+ /// \brief Set the user-written type that redefines \c id.
void setObjCIdRedefinitionType(QualType RedefType) {
ObjCIdRedefinitionType = RedefType;
}
- /// \brief Retrieve the type that 'Class' has been defined to, which may be
- /// different from the built-in 'Class' if 'Class' has been typedef'd.
+ /// \brief Retrieve the type that \c Class has been defined to, which may be
+ /// different from the built-in \c Class if \c Class has been typedef'd.
QualType getObjCClassRedefinitionType() const {
if (ObjCClassRedefinitionType.isNull())
return getObjCClassType();
@@ -1175,27 +1229,29 @@ public:
return getLangOpts().CPlusPlus ? BoolTy : IntTy;
}
- /// getObjCEncodingForType - Emit the ObjC type encoding for the
- /// given type into \arg S. If \arg NameFields is specified then
- /// record field names are also encoded.
- void getObjCEncodingForType(QualType t, std::string &S,
+ /// \brief Emit the Objective-CC type encoding for the given type \p T into
+ /// \p S.
+ ///
+ /// If \p Field is specified then record field names are also encoded.
+ void getObjCEncodingForType(QualType T, std::string &S,
const FieldDecl *Field=0) const;
void getLegacyIntegralTypeEncoding(QualType &t) const;
- // Put the string version of type qualifiers into S.
+ /// \brief Put the string version of the type qualifiers \p QT into \p S.
void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
std::string &S) const;
- /// getObjCEncodingForFunctionDecl - Returns the encoded type for this
- /// function. This is in the same format as Objective-C method encodings.
+ /// \brief Emit the encoded type for the function \p Decl into \p S.
+ ///
+ /// This is in the same format as Objective-C method encodings.
///
/// \returns true if an error occurred (e.g., because one of the parameter
/// types is incomplete), false otherwise.
bool getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S);
- /// getObjCEncodingForMethodDecl - Return the encoded type for this method
- /// declaration.
+ /// \brief Emit the encoded type for the method declaration \p Decl into
+ /// \p S.
///
/// \returns true if an error occurred (e.g., because one of the parameter
/// types is incomplete), false otherwise.
@@ -1203,8 +1259,7 @@ public:
bool Extended = false)
const;
- /// getObjCEncodingForBlock - Return the encoded type for this block
- /// declaration.
+ /// \brief Return the encoded type for this block declaration.
std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
/// getObjCEncodingForPropertyDecl - Return the encoded type for
@@ -1218,16 +1273,18 @@ public:
bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const;
- /// getObjCEncodingTypeSize returns size of type for objective-c encoding
- /// purpose in characters.
- CharUnits getObjCEncodingTypeSize(QualType t) const;
+ /// \brief Return the size of type \p T for Objective-C encoding purpose,
+ /// in characters.
+ CharUnits getObjCEncodingTypeSize(QualType T) const;
- /// \brief Retrieve the typedef corresponding to the predefined 'id' type
+ /// \brief Retrieve the typedef corresponding to the predefined \c id type
/// in Objective-C.
TypedefDecl *getObjCIdDecl() const;
- /// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
- /// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
+ /// \brief Represents the Objective-CC \c id type.
+ ///
+ /// This is set up lazily, by Sema. \c id is always a (typedef for a)
+ /// pointer type, a pointer to a struct.
QualType getObjCIdType() const {
return getTypeDeclType(getObjCIdDecl());
}
@@ -1246,48 +1303,64 @@ public:
/// Objective-C 'Class' type.
TypedefDecl *getObjCClassDecl() const;
- /// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by
- /// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a
- /// struct.
+ /// \brief Represents the Objective-C \c Class type.
+ ///
+ /// This is set up lazily, by Sema. \c Class is always a (typedef for a)
+ /// pointer type, a pointer to a struct.
QualType getObjCClassType() const {
return getTypeDeclType(getObjCClassDecl());
}
/// \brief Retrieve the Objective-C class declaration corresponding to
- /// the predefined 'Protocol' class.
+ /// the predefined \c Protocol class.
ObjCInterfaceDecl *getObjCProtocolDecl() const;
+
+ /// \brief Retrieve declaration of 'BOOL' typedef
+ TypedefDecl *getBOOLDecl() const {
+ return BOOLDecl;
+ }
+
+ /// \brief Save declaration of 'BOOL' typedef
+ void setBOOLDecl(TypedefDecl *TD) {
+ BOOLDecl = TD;
+ }
+
+ /// \brief type of 'BOOL' type.
+ QualType getBOOLType() const {
+ return getTypeDeclType(getBOOLDecl());
+ }
- /// \brief Retrieve the type of the Objective-C "Protocol" class.
+ /// \brief Retrieve the type of the Objective-C \c Protocol class.
QualType getObjCProtoType() const {
return getObjCInterfaceType(getObjCProtocolDecl());
}
/// \brief Retrieve the C type declaration corresponding to the predefined
- /// __builtin_va_list type.
+ /// \c __builtin_va_list type.
TypedefDecl *getBuiltinVaListDecl() const;
- /// \brief Retrieve the type of the __builtin_va_list type.
+ /// \brief Retrieve the type of the \c __builtin_va_list type.
QualType getBuiltinVaListType() const {
return getTypeDeclType(getBuiltinVaListDecl());
}
/// \brief Retrieve the C type declaration corresponding to the predefined
- /// __va_list_tag type used to help define the __builtin_va_list type for
- /// some targets.
+ /// \c __va_list_tag type used to help define the \c __builtin_va_list type
+ /// for some targets.
QualType getVaListTagType() const;
- /// getCVRQualifiedType - Returns a type with additional const,
- /// volatile, or restrict qualifiers.
+ /// \brief Return a type with additional \c const, \c volatile, or
+ /// \c restrict qualifiers.
QualType getCVRQualifiedType(QualType T, unsigned CVR) const {
return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
}
- /// getQualifiedType - Un-split a SplitQualType.
+ /// \brief Un-split a SplitQualType.
QualType getQualifiedType(SplitQualType split) const {
return getQualifiedType(split.Ty, split.Quals);
}
- /// getQualifiedType - Returns a type with additional qualifiers.
+ /// \brief Return a type with additional qualifiers.
QualType getQualifiedType(QualType T, Qualifiers Qs) const {
if (!Qs.hasNonFastQualifiers())
return T.withFastQualifiers(Qs.getFastQualifiers());
@@ -1296,15 +1369,16 @@ public:
return getExtQualType(Ptr, Qc);
}
- /// getQualifiedType - Returns a type with additional qualifiers.
+ /// \brief Return a type with additional qualifiers.
QualType getQualifiedType(const Type *T, Qualifiers Qs) const {
if (!Qs.hasNonFastQualifiers())
return QualType(T, Qs.getFastQualifiers());
return getExtQualType(T, Qs);
}
- /// getLifetimeQualifiedType - Returns a type with the given
- /// lifetime qualifier.
+ /// \brief Return a type with the given lifetime qualifier.
+ ///
+ /// \pre Neither type.ObjCLifetime() nor \p lifetime may be \c OCL_None.
QualType getLifetimeQualifiedType(QualType type,
Qualifiers::ObjCLifetime lifetime) {
assert(type.getObjCLifetime() == Qualifiers::OCL_None);
@@ -1341,8 +1415,9 @@ public:
GE_Missing_ucontext ///< Missing a type from <ucontext.h>
};
- /// GetBuiltinType - Return the type for the specified builtin. If
- /// IntegerConstantArgs is non-null, it is filled in with a bitmask of
+ /// \brief Return the type for the specified builtin.
+ ///
+ /// If \p IntegerConstantArgs is non-null, it is filled in with a bitmask of
/// arguments to the builtin that are required to be integer constant
/// expressions.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error,
@@ -1357,19 +1432,19 @@ private:
//===--------------------------------------------------------------------===//
public:
- /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
- /// garbage collection attribute.
- ///
+ /// \brief Return one of the GCNone, Weak or Strong Objective-C garbage
+ /// collection attributes.
Qualifiers::GC getObjCGCAttrKind(QualType Ty) const;
- /// areCompatibleVectorTypes - Return true if the given vector types
- /// are of the same unqualified type or if they are equivalent to the same
- /// GCC vector type, ignoring whether they are target-specific (AltiVec or
- /// Neon) types.
+ /// \brief Return true if the given vector types are of the same unqualified
+ /// type or if they are equivalent to the same GCC vector type.
+ ///
+ /// \note This ignores whether they are target-specific (AltiVec or Neon)
+ /// types.
bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);
- /// isObjCNSObjectType - Return true if this is an NSObject object with
- /// its NSObject attribute set.
+ /// \brief Return true if this is an \c NSObject object with its \c NSObject
+ /// attribute set.
static bool isObjCNSObjectType(QualType Ty) {
return Ty->isObjCNSObjectType();
}
@@ -1378,19 +1453,17 @@ public:
// Type Sizing and Analysis
//===--------------------------------------------------------------------===//
- /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
- /// scalar floating point type.
+ /// \brief Return the APFloat 'semantics' for the specified scalar floating
+ /// point type.
const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
- /// getTypeInfo - Get the size and alignment of the specified complete type in
- /// bits.
+ /// \brief Get the size and alignment of the specified complete type in bits.
std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const;
std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const {
return getTypeInfo(T.getTypePtr());
}
- /// getTypeSize - Return the size of the specified type, in bits. This method
- /// does not work on incomplete types.
+ /// \brief Return the size of the specified (complete) type \p T, in bits.
uint64_t getTypeSize(QualType T) const {
return getTypeInfo(T).first;
}
@@ -1398,24 +1471,24 @@ public:
return getTypeInfo(T).first;
}
- /// getCharWidth - Return the size of the character type, in bits
+ /// \brief Return the size of the character type, in bits.
uint64_t getCharWidth() const {
return getTypeSize(CharTy);
}
- /// toCharUnitsFromBits - Convert a size in bits to a size in characters.
+ /// \brief Convert a size in bits to a size in characters.
CharUnits toCharUnitsFromBits(int64_t BitSize) const;
- /// toBits - Convert a size in characters to a size in bits.
+ /// \brief Convert a size in characters to a size in bits.
int64_t toBits(CharUnits CharSize) const;
- /// getTypeSizeInChars - Return the size of the specified type, in characters.
- /// This method does not work on incomplete types.
+ /// \brief Return the size of the specified (complete) type \p T, in
+ /// characters.
CharUnits getTypeSizeInChars(QualType T) const;
CharUnits getTypeSizeInChars(const Type *T) const;
- /// getTypeAlign - Return the ABI-specified alignment of a type, in bits.
- /// This method does not work on incomplete types.
+ /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
+ /// bits.
unsigned getTypeAlign(QualType T) const {
return getTypeInfo(T).second;
}
@@ -1423,49 +1496,59 @@ public:
return getTypeInfo(T).second;
}
- /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
- /// characters. This method does not work on incomplete types.
+ /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
+ /// characters.
CharUnits getTypeAlignInChars(QualType T) const;
CharUnits getTypeAlignInChars(const Type *T) const;
+
+ // getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the
+ // type is a record, its data size is returned.
+ std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const;
std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const;
std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const;
- /// getPreferredTypeAlign - Return the "preferred" alignment of the specified
- /// type for the current target in bits. This can be different than the ABI
- /// alignment in cases where it is beneficial for performance to overalign
- /// a data type.
+ /// \brief Return the "preferred" alignment of the specified type \p T for
+ /// the current target, in bits.
+ ///
+ /// This can be different than the ABI alignment in cases where it is
+ /// beneficial for performance to overalign a data type.
unsigned getPreferredTypeAlign(const Type *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
+ /// \brief Return a conservative estimate of the alignment of the specified
+ /// decl \p D.
+ ///
+ /// \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;
- /// getASTRecordLayout - Get or compute information about the layout of the
- /// specified record (struct/union/class), which indicates its size and field
+ /// \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;
- /// getASTObjCInterfaceLayout - Get or compute information about the
- /// layout of the specified Objective-C interface.
+ /// \brief Get or compute information about the layout of the specified
+ /// Objective-C interface.
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
const;
void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
bool Simple = false) const;
- /// getASTObjCImplementationLayout - Get or compute information about
- /// the layout of the specified Objective-C implementation. This may
- /// differ from the interface if synthesized ivars are present.
+ /// \brief Get or compute information about the layout of the specified
+ /// Objective-C implementation.
+ ///
+ /// This may differ from the interface if synthesized ivars are present.
const ASTRecordLayout &
getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const;
- /// getKeyFunction - Get the key function for the given record decl, or NULL
- /// if there isn't one. The key function is, according to the Itanium C++ ABI
- /// section 5.2.3:
+ /// \brief Get the key function for the given record decl, or NULL if there
+ /// isn't one.
+ ///
+ /// The key function is, according to the Itanium C++ ABI section 5.2.3:
///
/// ...the first non-pure virtual function that is not inline at the point
/// of class definition.
@@ -1489,12 +1572,14 @@ public:
// Type Operators
//===--------------------------------------------------------------------===//
- /// getCanonicalType - Return the canonical (structural) type corresponding to
- /// the specified potentially non-canonical type. The non-canonical version
- /// of a type may have many "decorated" versions of types. Decorators can
- /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
- /// to be free of any of these, allowing two canonical types to be compared
- /// for exact equality with a simple pointer comparison.
+ /// \brief Return the canonical (structural) type corresponding to the
+ /// specified potentially non-canonical type \p T.
+ ///
+ /// The non-canonical version of a type may have many "decorated" versions of
+ /// types. Decorators can include typedefs, 'typeof' operators, etc. The
+ /// returned type is guaranteed to be free of any of these, allowing two
+ /// canonical types to be compared for exact equality with a simple pointer
+ /// comparison.
CanQualType getCanonicalType(QualType T) const {
return CanQualType::CreateUnsafe(T.getCanonicalType());
}
@@ -1503,21 +1588,23 @@ public:
return T->getCanonicalTypeInternal().getTypePtr();
}
- /// getCanonicalParamType - Return the canonical parameter type
- /// corresponding to the specific potentially non-canonical one.
+ /// \brief Return the canonical parameter type corresponding to the specific
+ /// potentially non-canonical one.
+ ///
/// Qualifiers are stripped off, functions are turned into function
/// pointers, and arrays decay one level into pointers.
CanQualType getCanonicalParamType(QualType T) const;
- /// \brief Determine whether the given types are equivalent.
+ /// \brief Determine whether the given types \p T1 and \p T2 are equivalent.
bool hasSameType(QualType T1, QualType T2) const {
return getCanonicalType(T1) == getCanonicalType(T2);
}
- /// \brief Returns this type as a completely-unqualified array type,
- /// capturing the qualifiers in Quals. This will remove the minimal amount of
- /// sugaring from the types, similar to the behavior of
- /// QualType::getUnqualifiedType().
+ /// \brief Return this type as a completely-unqualified array type,
+ /// capturing the qualifiers in \p Quals.
+ ///
+ /// This will remove the minimal amount of sugaring from the types, similar
+ /// to the behavior of QualType::getUnqualifiedType().
///
/// \param T is the qualified type, which may be an ArrayType
///
@@ -1628,15 +1715,16 @@ public:
return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
}
- /// getBaseElementType - Returns the innermost element type of an array type.
+ /// \brief Return the innermost element type of an array type.
+ ///
/// For example, will return "int" for int[m][n]
QualType getBaseElementType(const ArrayType *VAT) const;
- /// getBaseElementType - Returns the innermost element type of a type
- /// (which needn't actually be an array type).
+ /// \brief Return the innermost element type of a type (which needn't
+ /// actually be an array type).
QualType getBaseElementType(QualType QT) const;
- /// getConstantArrayElementCount - Returns number of constant array elements.
+ /// \brief Return number of constant array elements.
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const;
/// \brief Perform adjustment on the parameter type of a function.
@@ -1651,21 +1739,22 @@ public:
/// cv-qualifiers.
QualType getSignatureParameterType(QualType T) const;
- /// getArrayDecayedType - Return the properly qualified result of decaying the
- /// specified array type to a pointer. This operation is non-trivial when
- /// handling typedefs etc. The canonical type of "T" must be an array type,
- /// this returns a pointer to a properly qualified element of the array.
+ /// \brief Return the properly qualified result of decaying the specified
+ /// array type to a pointer.
+ ///
+ /// This operation is non-trivial when handling typedefs etc. The canonical
+ /// type of \p T must be an array type, this returns a pointer to a properly
+ /// qualified element of the array.
///
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
QualType getArrayDecayedType(QualType T) const;
- /// getPromotedIntegerType - Returns the type that Promotable will
- /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
- /// integer type.
+ /// \brief Return the type that \p PromotableType will promote to: C99
+ /// 6.3.1.1p2, assuming that \p PromotableType is a promotable integer type.
QualType getPromotedIntegerType(QualType PromotableType) const;
- /// \brief Recurses in pointer/array types until it finds an objc retainable
- /// type and returns its ownership.
+ /// \brief Recurses in pointer/array types until it finds an Objective-C
+ /// retainable type and returns its ownership.
Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const;
/// \brief Whether this is a promotable bitfield reference according
@@ -1675,21 +1764,24 @@ public:
/// promotion occurs.
QualType isPromotableBitField(Expr *E) const;
- /// 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.
+ /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
+ ///
+ /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
+ /// \p LHS < \p RHS, return -1.
int getIntegerTypeOrder(QualType LHS, QualType RHS) const;
- /// getFloatingTypeOrder - Compare the rank of the two specified floating
- /// point types, ignoring the domain of the type (i.e. 'double' ==
- /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
- /// LHS < RHS, return -1.
+ /// \brief Compare the rank of the two specified floating point types,
+ /// ignoring the domain of the type (i.e. 'double' == '_Complex double').
+ ///
+ /// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
+ /// \p LHS < \p RHS, return -1.
int getFloatingTypeOrder(QualType LHS, QualType RHS) const;
- /// getFloatingTypeOfSizeWithinDomain - Returns a real floating
- /// point or a complex type (based on typeDomain/typeSize).
- /// 'typeDomain' is a real floating point or complex type.
- /// 'typeSize' is a real floating point or complex type.
+ /// \brief Return a real floating point or a complex type (based on
+ /// \p typeDomain/\p typeSize).
+ ///
+ /// \param typeDomain a real floating point or complex type.
+ /// \param typeSize a real floating point or complex type.
QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
QualType typeDomain) const;
@@ -1787,7 +1879,7 @@ public:
// Per C99 6.2.5p6, for every signed integer type, there is a corresponding
// unsigned integer type. This method takes a signed type, and returns the
// corresponding unsigned integer type.
- QualType getCorrespondingUnsignedType(QualType T);
+ QualType getCorrespondingUnsignedType(QualType T) const;
//===--------------------------------------------------------------------===//
// Type Iterators.
@@ -1805,8 +1897,8 @@ public:
// Integer Values
//===--------------------------------------------------------------------===//
- /// MakeIntValue - Make an APSInt of the appropriate width and
- /// signedness for the given \arg Value and integer \arg Type.
+ /// \brief Make an APSInt of the appropriate width and signedness for the
+ /// given \p Value and integer \p Type.
llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const {
llvm::APSInt Res(getIntWidth(Type),
!Type->isSignedIntegerOrEnumerationType());
@@ -1816,12 +1908,14 @@ public:
bool isSentinelNullExpr(const Expr *E);
- /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
+ /// \brief Get the implementation of the ObjCInterfaceDecl \p D, or NULL if
+ /// none exists.
ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D);
- /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
+ /// \brief Get the implementation of the ObjCCategoryDecl \p D, or NULL if
+ /// none exists.
ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D);
- /// \brief returns true if there is at least one \@implementation in TU.
+ /// \brief Return true if there is at least one \@implementation in the TU.
bool AnyObjCImplementation() {
return !ObjCImpls.empty();
}
@@ -1834,7 +1928,7 @@ public:
ObjCCategoryImplDecl *ImplD);
/// \brief Get the duplicate declaration of a ObjCMethod in the same
- /// interface, or null if non exists.
+ /// interface, or null if none exists.
const ObjCMethodDecl *getObjCMethodRedeclaration(
const ObjCMethodDecl *MD) const {
return ObjCMethodRedecls.lookup(MD);
@@ -1846,16 +1940,16 @@ public:
ObjCMethodRedecls[MD] = Redecl;
}
- /// \brief Returns the objc interface that \arg ND belongs to if it is a
- /// objc method/property/ivar etc. that is part of an interface,
+ /// \brief Returns the Objective-C interface that \p ND belongs to if it is
+ /// an Objective-C method/property/ivar etc. that is part of an interface,
/// otherwise returns null.
ObjCInterfaceDecl *getObjContainingInterface(NamedDecl *ND) const;
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
- /// \brief Get the copy initialization expression of VarDecl,or NULL if
- /// none exists.
- Expr *getBlockVarCopyInits(const VarDecl*VD);
+ /// \brief Get the copy initialization expression of the VarDecl \p VD, or
+ /// NULL if none exists.
+ Expr *getBlockVarCopyInits(const VarDecl* VD);
/// \brief Allocate an uninitialized TypeSourceInfo.
///
@@ -1882,9 +1976,9 @@ public:
/// \brief Add a deallocation callback that will be invoked when the
/// ASTContext is destroyed.
///
- /// \brief Callback A callback function that will be invoked on destruction.
+ /// \param Callback A callback function that will be invoked on destruction.
///
- /// \brief Data Pointer data that will be provided to the callback function
+ /// \param Data Pointer data that will be provided to the callback function
/// when it is called.
void AddDeallocation(void (*Callback)(void*), void *Data);
@@ -1957,8 +2051,8 @@ public:
static unsigned NumImplicitDestructorsDeclared;
private:
- ASTContext(const ASTContext&); // DO NOT IMPLEMENT
- void operator=(const ASTContext&); // DO NOT IMPLEMENT
+ ASTContext(const ASTContext &) LLVM_DELETED_FUNCTION;
+ void operator=(const ASTContext &) LLVM_DELETED_FUNCTION;
public:
/// \brief Initialize built-in types.
@@ -1974,7 +2068,7 @@ public:
private:
void InitBuiltinType(CanQualType &R, BuiltinType::Kind K);
- // Return the ObjC type encoding for a given type.
+ // Return the Objective-C type encoding for a given type.
void getObjCEncodingForTypeImpl(QualType t, std::string &S,
bool ExpandPointedToStructures,
bool ExpandStructures,
@@ -2017,13 +2111,13 @@ private:
void ReleaseDeclContextMaps();
};
-/// @brief Utility function for constructing a nullary selector.
+/// \brief Utility function for constructing a nullary selector.
static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
-/// @brief Utility function for constructing an unary selector.
+/// \brief Utility function for constructing an unary selector.
static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index cb038a0a5826..56d15260a581 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -13,6 +13,8 @@
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
+#include "clang/Basic/SourceLocation.h"
+
namespace clang {
class Decl;
class DeclContext;
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index b17bd48b7d03..12a9855617c0 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -107,9 +107,6 @@ public:
// Pretty print this attribute.
virtual void printPretty(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const = 0;
-
- // Implement isa/cast/dyncast/etc.
- static bool classof(const Attr *) { return true; }
};
class InheritableAttr : public Attr {
@@ -125,7 +122,6 @@ public:
static bool classof(const Attr *A) {
return A->getKind() <= attr::LAST_INHERITABLE;
}
- static bool classof(const InheritableAttr *) { return true; }
};
class InheritableParamAttr : public InheritableAttr {
@@ -139,7 +135,6 @@ public:
static bool classof(const Attr *A) {
return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
}
- static bool classof(const InheritableParamAttr *) { return true; }
};
#include "clang/AST/Attrs.inc"
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index 34e6fc5cd826..ba322fb32655 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -206,6 +206,8 @@ PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
// unknown type, most notably explicit casts.
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
+PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
+
// The type of a cast which, in ARC, would normally require a
// __bridge, but which might be okay depending on the immediate
// context.
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt
index d7458aa7900e..4c4c0fb0a08b 100644
--- a/include/clang/AST/CMakeLists.txt
+++ b/include/clang/AST/CMakeLists.txt
@@ -20,3 +20,15 @@ clang_tablegen(CommentNodes.inc -gen-clang-comment-nodes
SOURCE ../Basic/CommentNodes.td
TARGET ClangCommentNodes)
+clang_tablegen(CommentHTMLTags.inc -gen-clang-comment-html-tags
+ SOURCE CommentHTMLTags.td
+ TARGET ClangCommentHTMLTags)
+
+clang_tablegen(CommentHTMLTagsProperties.inc -gen-clang-comment-html-tags-properties
+ SOURCE CommentHTMLTags.td
+ TARGET ClangCommentHTMLTagsProperties)
+
+clang_tablegen(CommentCommandInfo.inc -gen-clang-comment-command-info
+ SOURCE CommentCommands.td
+ TARGET ClangCommentCommandInfo)
+
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index ee6eba78e415..87bdbe04f3df 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -19,7 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include <list>
@@ -271,15 +271,14 @@ struct UniqueVirtualMethod {
/// pair is the virtual method that overrides it (including the
/// subobject in which that virtual function occurs).
class OverridingMethods {
- llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
- Overrides;
+ typedef SmallVector<UniqueVirtualMethod, 4> ValuesT;
+ typedef llvm::MapVector<unsigned, ValuesT> MapType;
+ MapType Overrides;
public:
// Iterate over the set of subobjects that have overriding methods.
- typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
- ::iterator iterator;
- typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
- ::const_iterator const_iterator;
+ typedef MapType::iterator iterator;
+ typedef MapType::const_iterator const_iterator;
iterator begin() { return Overrides.begin(); }
const_iterator begin() const { return Overrides.begin(); }
iterator end() { return Overrides.end(); }
@@ -357,8 +356,8 @@ public:
/// 0 represents the virtua base class subobject of that type, while
/// subobject numbers greater than 0 refer to non-virtual base class
/// subobjects of that type.
-class CXXFinalOverriderMap
- : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
+class CXXFinalOverriderMap
+ : public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { };
/// \brief A set of all the primary bases for a class.
class CXXIndirectPrimaryBaseSet
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 6cce88868db8..ea307bf307cb 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -276,6 +276,7 @@ public:
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isInterfaceType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 5be35826a964..12e74b32be8a 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -164,8 +164,8 @@ namespace clang {
QuantityType getQuantity() const { return Quantity; }
/// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
- /// greater than or equal to this quantity and is a multiple of \arg
- /// Align. Align must be non-zero.
+ /// greater than or equal to this quantity and is a multiple of \p Align.
+ /// Align must be non-zero.
CharUnits RoundUpToAlignment(const CharUnits &Align) {
return CharUnits(llvm::RoundUpToAlignment(Quantity,
Align.Quantity));
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index 01aaac3f77ad..316a1801bd46 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -16,6 +16,8 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/Type.h"
+#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
@@ -25,7 +27,7 @@ class ParmVarDecl;
class TemplateParameterList;
namespace comments {
-
+class FullComment;
/// Any part of the comment.
/// Abstract class.
class Comment {
@@ -74,8 +76,9 @@ protected:
unsigned : NumInlineContentCommentBits;
unsigned RenderKind : 2;
+ unsigned CommandID : 8;
};
- enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 1 };
+ enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
class HTMLStartTagCommentBitfields {
friend class HTMLStartTagComment;
@@ -101,10 +104,19 @@ protected:
};
enum { NumParagraphCommentBits = NumCommentBits + 2 };
+ class BlockCommandCommentBitfields {
+ friend class BlockCommandComment;
+
+ unsigned : NumCommentBits;
+
+ unsigned CommandID : 8;
+ };
+ enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
+
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
- unsigned : NumCommentBits;
+ unsigned : NumBlockCommandCommentBits;
/// Parameter passing direction, see ParamCommandComment::PassDirection.
unsigned Direction : 2;
@@ -112,7 +124,7 @@ protected:
/// True if direction was specified explicitly in the comment.
unsigned IsDirectionExplicit : 1;
};
- enum { NumParamCommandCommentBits = 11 };
+ enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 };
union {
CommentBitfields CommentBits;
@@ -121,6 +133,7 @@ protected:
InlineCommandCommentBitfields InlineCommandCommentBits;
HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
ParagraphCommentBitfields ParagraphCommentBits;
+ BlockCommandCommentBitfields BlockCommandCommentBits;
ParamCommandCommentBitfields ParamCommandCommentBits;
};
@@ -158,10 +171,9 @@ public:
const char *getCommentKindName() const;
LLVM_ATTRIBUTE_USED void dump() const;
- LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
- void dump(llvm::raw_ostream &OS, SourceManager *SM) const;
-
- static bool classof(const Comment *) { return true; }
+ LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) const;
+ void dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM) const;
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
@@ -204,8 +216,6 @@ public:
C->getCommentKind() <= LastInlineContentCommentConstant;
}
- static bool classof(const InlineContentComment *) { return true; }
-
void addTrailingNewline() {
InlineContentCommentBits.HasTrailingNewline = 1;
}
@@ -232,8 +242,6 @@ public:
return C->getCommentKind() == TextCommentKind;
}
- static bool classof(const TextComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@@ -273,35 +281,35 @@ public:
};
protected:
- /// Command name.
- StringRef Name;
-
/// Command arguments.
llvm::ArrayRef<Argument> Args;
public:
InlineCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name,
+ unsigned CommandID,
RenderKind RK,
llvm::ArrayRef<Argument> Args) :
InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
- Name(Name), Args(Args) {
+ Args(Args) {
InlineCommandCommentBits.RenderKind = RK;
+ InlineCommandCommentBits.CommandID = CommandID;
}
static bool classof(const Comment *C) {
return C->getCommentKind() == InlineCommandCommentKind;
}
- static bool classof(const InlineCommandComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
- StringRef getCommandName() const {
- return Name;
+ unsigned getCommandID() const {
+ return InlineCommandCommentBits.CommandID;
+ }
+
+ StringRef getCommandName(const CommandTraits &Traits) const {
+ return Traits.getCommandInfo(getCommandID())->Name;
}
SourceRange getCommandNameRange() const {
@@ -352,8 +360,6 @@ public:
C->getCommentKind() <= LastHTMLTagCommentConstant;
}
- static bool classof(const HTMLTagComment *) { return true; }
-
StringRef getTagName() const LLVM_READONLY { return TagName; }
SourceRange getTagNameSourceRange() const LLVM_READONLY {
@@ -419,8 +425,6 @@ public:
return C->getCommentKind() == HTMLStartTagCommentKind;
}
- static bool classof(const HTMLStartTagComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@@ -476,8 +480,6 @@ public:
return C->getCommentKind() == HTMLEndTagCommentKind;
}
- static bool classof(const HTMLEndTagComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@@ -498,8 +500,6 @@ public:
return C->getCommentKind() >= FirstBlockContentCommentConstant &&
C->getCommentKind() <= LastBlockContentCommentConstant;
}
-
- static bool classof(const BlockContentComment *) { return true; }
};
/// A single paragraph that contains inline content.
@@ -529,8 +529,6 @@ public:
return C->getCommentKind() == ParagraphCommentKind;
}
- static bool classof(const ParagraphComment *) { return true; }
-
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Content.begin());
}
@@ -566,9 +564,6 @@ public:
};
protected:
- /// Command name.
- StringRef Name;
-
/// Word-like arguments.
llvm::ArrayRef<Argument> Args;
@@ -578,21 +573,21 @@ protected:
BlockCommandComment(CommentKind K,
SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) :
+ unsigned CommandID) :
BlockContentComment(K, LocBegin, LocEnd),
- Name(Name),
Paragraph(NULL) {
- setLocation(getCommandNameRange().getBegin());
+ setLocation(getCommandNameBeginLoc());
+ BlockCommandCommentBits.CommandID = CommandID;
}
public:
BlockCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) :
+ unsigned CommandID) :
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
- Name(Name),
Paragraph(NULL) {
- setLocation(getCommandNameRange().getBegin());
+ setLocation(getCommandNameBeginLoc());
+ BlockCommandCommentBits.CommandID = CommandID;
}
static bool classof(const Comment *C) {
@@ -600,8 +595,6 @@ public:
C->getCommentKind() <= LastBlockCommandCommentConstant;
}
- static bool classof(const BlockCommandComment *) { return true; }
-
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(&Paragraph);
}
@@ -610,12 +603,21 @@ public:
return reinterpret_cast<child_iterator>(&Paragraph + 1);
}
- StringRef getCommandName() const {
- return Name;
+ unsigned getCommandID() const {
+ return BlockCommandCommentBits.CommandID;
}
- SourceRange getCommandNameRange() const {
- return SourceRange(getLocStart().getLocWithOffset(1),
+ StringRef getCommandName(const CommandTraits &Traits) const {
+ return Traits.getCommandInfo(getCommandID())->Name;
+ }
+
+ SourceLocation getCommandNameBeginLoc() const {
+ return getLocStart().getLocWithOffset(1);
+ }
+
+ SourceRange getCommandNameRange(const CommandTraits &Traits) const {
+ StringRef Name = getCommandName(Traits);
+ return SourceRange(getCommandNameBeginLoc(),
getLocStart().getLocWithOffset(1 + Name.size()));
}
@@ -667,8 +669,9 @@ public:
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) :
- BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
+ unsigned CommandID) :
+ BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
+ CommandID),
ParamIndex(InvalidParamIndex) {
ParamCommandCommentBits.Direction = In;
ParamCommandCommentBits.IsDirectionExplicit = false;
@@ -678,8 +681,6 @@ public:
return C->getCommentKind() == ParamCommandCommentKind;
}
- static bool classof(const ParamCommandComment *) { return true; }
-
enum PassDirection {
In,
Out,
@@ -705,7 +706,9 @@ public:
return getNumArgs() > 0;
}
- StringRef getParamName() const {
+ StringRef getParamName(const FullComment *FC) const;
+
+ StringRef getParamNameAsWritten() const {
return Args[0].Text;
}
@@ -748,21 +751,21 @@ private:
public:
TParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) :
- BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, Name)
+ unsigned CommandID) :
+ BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
{ }
static bool classof(const Comment *C) {
return C->getCommentKind() == TParamCommandCommentKind;
}
- static bool classof(const TParamCommandComment *) { return true; }
-
bool hasParamName() const {
return getNumArgs() > 0;
}
- StringRef getParamName() const {
+ StringRef getParamName(const FullComment *FC) const;
+
+ StringRef getParamNameAsWritten() const {
return Args[0].Text;
}
@@ -807,8 +810,6 @@ public:
return C->getCommentKind() == VerbatimBlockLineCommentKind;
}
- static bool classof(const VerbatimBlockLineComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@@ -830,17 +831,15 @@ protected:
public:
VerbatimBlockComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) :
+ unsigned CommandID) :
BlockCommandComment(VerbatimBlockCommentKind,
- LocBegin, LocEnd, Name)
+ LocBegin, LocEnd, CommandID)
{ }
static bool classof(const Comment *C) {
return C->getCommentKind() == VerbatimBlockCommentKind;
}
- static bool classof(const VerbatimBlockComment *) { return true; }
-
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Lines.begin());
}
@@ -882,12 +881,12 @@ protected:
public:
VerbatimLineComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name,
+ unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) :
BlockCommandComment(VerbatimLineCommentKind,
LocBegin, LocEnd,
- Name),
+ CommandID),
Text(Text),
TextBegin(TextBegin)
{ }
@@ -896,8 +895,6 @@ public:
return C->getCommentKind() == VerbatimLineCommentKind;
}
- static bool classof(const VerbatimLineComment *) { return true; }
-
child_iterator child_begin() const { return NULL; }
child_iterator child_end() const { return NULL; }
@@ -913,23 +910,34 @@ public:
/// Information about the declaration, useful to clients of FullComment.
struct DeclInfo {
- /// Declaration the comment is attached to. Should not be NULL.
- const Decl *ThisDecl;
-
- /// Parameters that can be referenced by \\param if \c ThisDecl is something
+ /// Declaration the comment is actually attached to (in the source).
+ /// Should not be NULL.
+ const Decl *CommentDecl;
+
+ /// CurrentDecl is the declaration with which the FullComment is associated.
+ ///
+ /// It can be different from \c CommentDecl. It happens when we we decide
+ /// that the comment originally attached to \c CommentDecl is fine for
+ /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
+ /// \c CommentDecl).
+ ///
+ /// The information in the DeclInfo corresponds to CurrentDecl.
+ const Decl *CurrentDecl;
+
+ /// Parameters that can be referenced by \\param if \c CommentDecl is something
/// that we consider a "function".
ArrayRef<const ParmVarDecl *> ParamVars;
- /// Function result type if \c ThisDecl is something that we consider
+ /// Function result type if \c CommentDecl is something that we consider
/// a "function".
QualType ResultType;
- /// Template parameters that can be referenced by \\tparam if \c ThisDecl is
+ /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
/// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
/// true).
const TemplateParameterList *TemplateParameters;
- /// A simplified description of \c ThisDecl kind that should be good enough
+ /// A simplified description of \c CommentDecl kind that should be good enough
/// for documentation rendering purposes.
enum DeclKind {
/// Everything else not explicitly mentioned below.
@@ -942,7 +950,9 @@ struct DeclInfo {
/// \li member function,
/// \li member function template,
/// \li member function template specialization,
- /// \li ObjC method.
+ /// \li ObjC method,
+ /// \li a typedef for a function pointer, member function pointer,
+ /// ObjC block.
FunctionKind,
/// Something that we consider a "class":
@@ -968,7 +978,7 @@ struct DeclInfo {
EnumKind
};
- /// What kind of template specialization \c ThisDecl is.
+ /// What kind of template specialization \c CommentDecl is.
enum TemplateDeclKind {
NotTemplate,
Template,
@@ -976,24 +986,24 @@ struct DeclInfo {
TemplatePartialSpecialization
};
- /// If false, only \c ThisDecl is valid.
+ /// If false, only \c CommentDecl is valid.
unsigned IsFilled : 1;
- /// Simplified kind of \c ThisDecl, see\c DeclKind enum.
+ /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
unsigned Kind : 3;
- /// Is \c ThisDecl a template declaration.
+ /// Is \c CommentDecl a template declaration.
unsigned TemplateKind : 2;
- /// Is \c ThisDecl an ObjCMethodDecl.
+ /// Is \c CommentDecl an ObjCMethodDecl.
unsigned IsObjCMethod : 1;
- /// Is \c ThisDecl a non-static member function of C++ class or
+ /// Is \c CommentDecl a non-static member function of C++ class or
/// instance method of ObjC class.
/// Can be true only if \c IsFunctionDecl is true.
unsigned IsInstanceMethod : 1;
- /// Is \c ThisDecl a static member function of C++ class or
+ /// Is \c CommentDecl a static member function of C++ class or
/// class method of ObjC class.
/// Can be true only if \c IsFunctionDecl is true.
unsigned IsClassMethod : 1;
@@ -1012,7 +1022,6 @@ struct DeclInfo {
/// A full comment attached to a declaration, contains block content.
class FullComment : public Comment {
llvm::ArrayRef<BlockContentComment *> Blocks;
-
DeclInfo *ThisDeclInfo;
public:
@@ -1031,27 +1040,31 @@ public:
return C->getCommentKind() == FullCommentKind;
}
- static bool classof(const FullComment *) { return true; }
-
child_iterator child_begin() const {
return reinterpret_cast<child_iterator>(Blocks.begin());
}
child_iterator child_end() const {
- return reinterpret_cast<child_iterator>(Blocks.end());
+ return reinterpret_cast<child_iterator>(Blocks.end());
}
const Decl *getDecl() const LLVM_READONLY {
- return ThisDeclInfo->ThisDecl;
+ return ThisDeclInfo->CommentDecl;
}
-
+
const DeclInfo *getDeclInfo() const LLVM_READONLY {
if (!ThisDeclInfo->IsFilled)
ThisDeclInfo->fill();
return ThisDeclInfo;
}
+
+ DeclInfo *getThisDeclInfo() const LLVM_READONLY {
+ return ThisDeclInfo;
+ }
+
+ llvm::ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
+
};
-
} // end namespace comments
} // end namespace clang
diff --git a/include/clang/AST/CommentBriefParser.h b/include/clang/AST/CommentBriefParser.h
index 003c33727e35..5d508860635d 100644
--- a/include/clang/AST/CommentBriefParser.h
+++ b/include/clang/AST/CommentBriefParser.h
@@ -44,8 +44,7 @@ class BriefParser {
public:
BriefParser(Lexer &L, const CommandTraits &Traits);
- /// Return \\brief paragraph, if it exists; otherwise return the first
- /// paragraph.
+ /// Return the best "brief description" we can find.
std::string Parse();
};
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index 5f0269a4650b..6d44c706c3dc 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -19,136 +19,132 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace comments {
-/// This class provides informaiton about commands that can be used
-/// in comments.
-class CommandTraits {
-public:
- CommandTraits() { }
+/// \brief Information about a single command.
+///
+/// When reordering, adding or removing members please update the corresponding
+/// TableGen backend.
+struct CommandInfo {
+ unsigned getID() const {
+ return ID;
+ }
+
+ const char *Name;
+
+ /// Name of the command that ends the verbatim block.
+ const char *EndCommandName;
+
+ unsigned ID : 8;
+
+ /// Number of word-like arguments for a given block command, except for
+ /// \\param and \\tparam commands -- these have special argument parsers.
+ unsigned NumArgs : 4;
- /// \brief Check if a given command is a verbatim-like block command.
+ /// True if this command is a inline command (of any kind).
+ unsigned IsInlineCommand : 1;
+
+ /// True if this command is a block command (of any kind).
+ unsigned IsBlockCommand : 1;
+
+ /// True if this command is introducing a brief documentation
+ /// paragraph (\\brief or an alias).
+ unsigned IsBriefCommand : 1;
+
+ /// True if this command is \\returns or an alias.
+ unsigned IsReturnsCommand : 1;
+
+ /// True if this command is introducing documentation for a function
+ /// parameter (\\param or an alias).
+ unsigned IsParamCommand : 1;
+
+ /// True if this command is introducing documentation for
+ /// a template parameter (\\tparam or an alias).
+ unsigned IsTParamCommand : 1;
+
+ /// True if this command is \\deprecated or an alias.
+ unsigned IsDeprecatedCommand : 1;
+
+ /// True if we don't want to warn about this command being passed an empty
+ /// paragraph. Meaningful only for block commands.
+ unsigned IsEmptyParagraphAllowed : 1;
+
+ /// \brief True if this command is a verbatim-like block command.
///
/// A verbatim-like block command eats every character (except line starting
/// decorations) until matching end command is seen or comment end is hit.
- ///
- /// \param StartName name of the command that starts the verbatim block.
- /// \param [out] EndName name of the command that ends the verbatim block.
- ///
- /// \returns true if a given command is a verbatim block command.
- bool isVerbatimBlockCommand(StringRef StartName, StringRef &EndName) const;
+ unsigned IsVerbatimBlockCommand : 1;
- /// \brief Register a new verbatim block command.
- void addVerbatimBlockCommand(StringRef StartName, StringRef EndName);
+ /// \brief True if this command is an end command for a verbatim-like block.
+ unsigned IsVerbatimBlockEndCommand : 1;
- /// \brief Check if a given command is a verbatim line command.
+ /// \brief True if this command is a verbatim line command.
///
/// A verbatim-like line command eats everything until a newline is seen or
/// comment end is hit.
- bool isVerbatimLineCommand(StringRef Name) const;
+ unsigned IsVerbatimLineCommand : 1;
- /// \brief Check if a given command is a command that contains a declaration
- /// for the entity being documented.
+ /// \brief True if this command contains a declaration for the entity being
+ /// documented.
///
/// For example:
/// \code
/// \fn void f(int a);
/// \endcode
- bool isDeclarationCommand(StringRef Name) const;
+ unsigned IsDeclarationCommand : 1;
- /// \brief Register a new verbatim line command.
- void addVerbatimLineCommand(StringRef Name);
+ /// \brief True if this command is unknown. This \c CommandInfo object was
+ /// created during parsing.
+ unsigned IsUnknownCommand : 1;
+};
- /// \brief Check if a given command is a block command (of any kind).
- bool isBlockCommand(StringRef Name) const;
+/// This class provides information about commands that can be used
+/// in comments.
+class CommandTraits {
+public:
+ CommandTraits(llvm::BumpPtrAllocator &Allocator);
- /// \brief Check if a given command is introducing documentation for
- /// a function parameter (\\param or an alias).
- bool isParamCommand(StringRef Name) const;
+ /// \returns a CommandInfo object for a given command name or
+ /// NULL if no CommandInfo object exists for this command.
+ const CommandInfo *getCommandInfoOrNULL(StringRef Name) const;
- /// \brief Check if a given command is introducing documentation for
- /// a template parameter (\\tparam or an alias).
- bool isTParamCommand(StringRef Name) const;
+ const CommandInfo *getCommandInfo(StringRef Name) const {
+ if (const CommandInfo *Info = getCommandInfoOrNULL(Name))
+ return Info;
+ llvm_unreachable("the command should be known");
+ }
- /// \brief Check if a given command is introducing a brief documentation
- /// paragraph (\\brief or an alias).
- bool isBriefCommand(StringRef Name) const;
+ const CommandInfo *getCommandInfo(unsigned CommandID) const;
- /// \brief Check if a given command is \\brief or an alias.
- bool isReturnsCommand(StringRef Name) const;
+ const CommandInfo *registerUnknownCommand(StringRef CommandName);
- /// \returns the number of word-like arguments for a given block command,
- /// except for \\param and \\tparam commands -- these have special argument
- /// parsers.
- unsigned getBlockCommandNumArgs(StringRef Name) const;
+ /// \returns a CommandInfo object for a given command name or
+ /// NULL if \c Name is not a builtin command.
+ static const CommandInfo *getBuiltinCommandInfo(StringRef Name);
- /// \brief Check if a given command is a inline command (of any kind).
- bool isInlineCommand(StringRef Name) const;
+ /// \returns a CommandInfo object for a given command ID or
+ /// NULL if \c CommandID is not a builtin command.
+ static const CommandInfo *getBuiltinCommandInfo(unsigned CommandID);
private:
- struct VerbatimBlockCommand {
- StringRef StartName;
- StringRef EndName;
- };
-
- typedef SmallVector<VerbatimBlockCommand, 4> VerbatimBlockCommandVector;
+ CommandTraits(const CommandTraits &) LLVM_DELETED_FUNCTION;
+ void operator=(const CommandTraits &) LLVM_DELETED_FUNCTION;
- /// Registered additional verbatim-like block commands.
- VerbatimBlockCommandVector VerbatimBlockCommands;
+ const CommandInfo *getRegisteredCommandInfo(StringRef Name) const;
+ const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const;
- struct VerbatimLineCommand {
- StringRef Name;
- };
+ unsigned NextID;
- typedef SmallVector<VerbatimLineCommand, 4> VerbatimLineCommandVector;
+ /// Allocator for CommandInfo objects.
+ llvm::BumpPtrAllocator &Allocator;
- /// Registered verbatim-like line commands.
- VerbatimLineCommandVector VerbatimLineCommands;
+ SmallVector<CommandInfo *, 4> RegisteredCommands;
};
-inline bool CommandTraits::isBlockCommand(StringRef Name) const {
- return isBriefCommand(Name) || isReturnsCommand(Name) ||
- isParamCommand(Name) || isTParamCommand(Name) ||
- llvm::StringSwitch<bool>(Name)
- .Case("author", true)
- .Case("authors", true)
- .Case("pre", true)
- .Case("post", true)
- .Default(false);
-}
-
-inline bool CommandTraits::isParamCommand(StringRef Name) const {
- return Name == "param";
-}
-
-inline bool CommandTraits::isTParamCommand(StringRef Name) const {
- return Name == "tparam" || // Doxygen
- Name == "templatefield"; // HeaderDoc
-}
-
-inline bool CommandTraits::isBriefCommand(StringRef Name) const {
- return Name == "brief" || Name == "short";
-}
-
-inline bool CommandTraits::isReturnsCommand(StringRef Name) const {
- return Name == "returns" || Name == "return" || Name == "result";
-}
-
-inline unsigned CommandTraits::getBlockCommandNumArgs(StringRef Name) const {
- return 0;
-}
-
-inline bool CommandTraits::isInlineCommand(StringRef Name) const {
- return llvm::StringSwitch<bool>(Name)
- .Case("b", true)
- .Cases("c", "p", true)
- .Cases("a", "e", "em", true)
- .Default(false);
-}
-
} // end namespace comments
} // end namespace clang
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
new file mode 100644
index 000000000000..3d8bad89c26b
--- /dev/null
+++ b/include/clang/AST/CommentCommands.td
@@ -0,0 +1,156 @@
+class Command<string name> {
+ string Name = name;
+ string EndCommandName = "";
+
+ int NumArgs = 0;
+
+ bit IsInlineCommand = 0;
+
+ bit IsBlockCommand = 0;
+ bit IsBriefCommand = 0;
+ bit IsReturnsCommand = 0;
+ bit IsParamCommand = 0;
+ bit IsTParamCommand = 0;
+ bit IsDeprecatedCommand = 0;
+
+ bit IsEmptyParagraphAllowed = 0;
+
+ bit IsVerbatimBlockCommand = 0;
+ bit IsVerbatimBlockEndCommand = 0;
+ bit IsVerbatimLineCommand = 0;
+ bit IsDeclarationCommand = 0;
+}
+
+class InlineCommand<string name> : Command<name> {
+ let IsInlineCommand = 1;
+}
+
+class BlockCommand<string name> : Command<name> {
+ let IsBlockCommand = 1;
+}
+
+class VerbatimBlockCommand<string name> : Command<name> {
+ let EndCommandName = name;
+ let IsVerbatimBlockCommand = 1;
+}
+
+multiclass VerbatimBlockCommand<string name, string endCommandName> {
+ def Begin : Command<name> {
+ let EndCommandName = endCommandName;
+ let IsVerbatimBlockCommand = 1;
+ }
+
+ def End : Command<endCommandName> {
+ let IsVerbatimBlockEndCommand = 1;
+ }
+}
+
+class VerbatimLineCommand<string name> : Command<name> {
+ let IsVerbatimLineCommand = 1;
+}
+
+class DeclarationVerbatimLineCommand<string name> :
+ VerbatimLineCommand<name> {
+ let IsDeclarationCommand = 1;
+}
+
+def B : InlineCommand<"b">;
+def C : InlineCommand<"c">;
+def P : InlineCommand<"p">;
+def A : InlineCommand<"a">;
+def E : InlineCommand<"e">;
+def Em : InlineCommand<"em">;
+
+def Brief : BlockCommand<"brief"> { let IsBriefCommand = 1; }
+def Short : BlockCommand<"short"> { let IsBriefCommand = 1; }
+
+def Returns : BlockCommand<"returns"> { let IsReturnsCommand = 1; }
+def Return : BlockCommand<"return"> { let IsReturnsCommand = 1; }
+def Result : BlockCommand<"result"> { let IsReturnsCommand = 1; }
+
+def Param : BlockCommand<"param"> { let IsParamCommand = 1; }
+
+// Doxygen
+def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
+
+// HeaderDoc
+def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
+
+def Deprecated : BlockCommand<"deprecated"> {
+ let IsEmptyParagraphAllowed = 1;
+ let IsDeprecatedCommand = 1;
+}
+
+def Author : BlockCommand<"author">;
+def Authors : BlockCommand<"authors">;
+def Bug : BlockCommand<"bug">;
+def Copyright : BlockCommand<"copyright">;
+def Date : BlockCommand<"date">;
+def Details : BlockCommand<"details">;
+def Invariant : BlockCommand<"invariant">;
+def Note : BlockCommand<"note">;
+def Post : BlockCommand<"post">;
+def Pre : BlockCommand<"pre">;
+def Remark : BlockCommand<"remark">;
+def Remarks : BlockCommand<"remarks">;
+def Sa : BlockCommand<"sa">;
+def See : BlockCommand<"see">;
+def Since : BlockCommand<"since">;
+def Todo : BlockCommand<"todo">;
+def Version : BlockCommand<"version">;
+def Warning : BlockCommand<"warning">;
+
+defm Code : VerbatimBlockCommand<"code", "endcode">;
+defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">;
+defm Htmlonly : VerbatimBlockCommand<"htmlonly", "endhtmlonly">;
+defm Latexonly : VerbatimBlockCommand<"latexonly", "endlatexonly">;
+defm Xmlonly : VerbatimBlockCommand<"xmlonly", "endxmlonly">;
+defm Manonly : VerbatimBlockCommand<"manonly", "endmanonly">;
+defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">;
+
+defm Dot : VerbatimBlockCommand<"dot", "enddot">;
+defm Msc : VerbatimBlockCommand<"msc", "endmsc">;
+
+// These commands have special support in lexer.
+def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula
+defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula
+defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment
+
+def Defgroup : VerbatimLineCommand<"defgroup">;
+def Ingroup : VerbatimLineCommand<"ingroup">;
+def Addtogroup : VerbatimLineCommand<"addtogroup">;
+def Weakgroup : VerbatimLineCommand<"weakgroup">;
+def Name : VerbatimLineCommand<"name">;
+
+def Section : VerbatimLineCommand<"section">;
+def Subsection : VerbatimLineCommand<"subsection">;
+def Subsubsection : VerbatimLineCommand<"subsubsection">;
+def Paragraph : VerbatimLineCommand<"paragraph">;
+
+def Mainpage : VerbatimLineCommand<"mainpage">;
+def Subpage : VerbatimLineCommand<"subpage">;
+def Ref : VerbatimLineCommand<"ref">;
+
+// Doxygen commands.
+def Fn : DeclarationVerbatimLineCommand<"fn">;
+def Namespace : DeclarationVerbatimLineCommand<"namespace">;
+def Overload : DeclarationVerbatimLineCommand<"overload">;
+def Property : DeclarationVerbatimLineCommand<"property">;
+def Typedef : DeclarationVerbatimLineCommand<"typedef">;
+def Var : DeclarationVerbatimLineCommand<"var">;
+
+// HeaderDoc commands.
+def Class : DeclarationVerbatimLineCommand<"class">;
+def Interface : DeclarationVerbatimLineCommand<"interface">;
+def Protocol : DeclarationVerbatimLineCommand<"protocol">;
+def Category : DeclarationVerbatimLineCommand<"category">;
+def Template : DeclarationVerbatimLineCommand<"template">;
+def Function : DeclarationVerbatimLineCommand<"function">;
+def Method : DeclarationVerbatimLineCommand<"method">;
+def Callback : DeclarationVerbatimLineCommand<"callback">;
+def Const : DeclarationVerbatimLineCommand<"const">;
+def Constant : DeclarationVerbatimLineCommand<"constant">;
+def Struct : DeclarationVerbatimLineCommand<"struct">;
+def Union : DeclarationVerbatimLineCommand<"union">;
+def Enum : DeclarationVerbatimLineCommand<"enum">;
+
diff --git a/include/clang/AST/CommentHTMLTags.td b/include/clang/AST/CommentHTMLTags.td
new file mode 100644
index 000000000000..f98e32ddca4f
--- /dev/null
+++ b/include/clang/AST/CommentHTMLTags.td
@@ -0,0 +1,54 @@
+class Tag<string spelling> {
+ string Spelling = spelling;
+ bit EndTagOptional = 0;
+ bit EndTagForbidden = 0;
+}
+
+def Em : Tag<"em">;
+def Strong : Tag<"strong">;
+def Tt : Tag<"tt">;
+def I : Tag<"i">;
+def B : Tag<"b">;
+def Big : Tag<"big">;
+def Small : Tag<"small">;
+def Strike : Tag<"strike">;
+def S : Tag<"s">;
+def U : Tag<"u">;
+def Font : Tag<"font">;
+def A : Tag<"a">;
+def Hr : Tag<"hr"> { let EndTagForbidden = 1; }
+def Div : Tag<"div">;
+def Span : Tag<"span">;
+def H1 : Tag<"h1">;
+def H2 : Tag<"h2">;
+def H3 : Tag<"h3">;
+def H4 : Tag<"h4">;
+def H5 : Tag<"h5">;
+def H6 : Tag<"h6">;
+def Code : Tag<"code">;
+def Blockquote : Tag<"blockquote">;
+def Sub : Tag<"sub">;
+def Sup : Tag<"sup">;
+def Img : Tag<"img"> { let EndTagForbidden = 1; }
+def P : Tag<"p"> { let EndTagOptional = 1; }
+def Br : Tag<"br"> { let EndTagForbidden = 1; }
+def Pre : Tag<"pre">;
+def Ins : Tag<"ins">;
+def Del : Tag<"del">;
+def Ul : Tag<"ul">;
+def Ol : Tag<"ol">;
+def Li : Tag<"li"> { let EndTagOptional = 1; }
+def Dl : Tag<"dl">;
+def Dt : Tag<"dt"> { let EndTagOptional = 1; }
+def Dd : Tag<"dd"> { let EndTagOptional = 1; }
+def Table : Tag<"table">;
+def Caption : Tag<"caption">;
+def Thead : Tag<"thead"> { let EndTagOptional = 1; }
+def Tfoot : Tag<"tfoot"> { let EndTagOptional = 1; }
+def Tbody : Tag<"tbody"> { let EndTagOptional = 1; }
+def Colgroup : Tag<"colgroup"> { let EndTagOptional = 1; }
+def Col : Tag<"col"> { let EndTagForbidden = 1; }
+def Tr : Tag<"tr"> { let EndTagOptional = 1; }
+def Th : Tag<"th"> { let EndTagOptional = 1; }
+def Td : Tag<"td"> { let EndTagOptional = 1; }
+
diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h
index 7a24b1163178..f2636973ff27 100644
--- a/include/clang/AST/CommentLexer.h
+++ b/include/clang/AST/CommentLexer.h
@@ -26,6 +26,7 @@ namespace comments {
class Lexer;
class TextTokenRetokenizer;
+struct CommandInfo;
class CommandTraits;
namespace tok {
@@ -33,7 +34,8 @@ enum TokenKind {
eof,
newline,
text,
- command,
+ unknown_command, // Command that does not have an ID.
+ command, // Command with an ID.
verbatim_block_begin,
verbatim_block_line,
verbatim_block_end,
@@ -49,11 +51,6 @@ enum TokenKind {
};
} // end namespace tok
-class CommentOptions {
-public:
- bool Markdown;
-};
-
/// \brief Comment token.
class Token {
friend class Lexer;
@@ -70,8 +67,14 @@ class Token {
unsigned Length;
/// Contains text value associated with a token.
- const char *TextPtr1;
- unsigned TextLen1;
+ const char *TextPtr;
+
+ /// Integer value associated with a token.
+ ///
+ /// If the token is a konwn command, contains command ID and TextPtr is
+ /// unused (command spelling can be found with CommandTraits). Otherwise,
+ /// contains the length of the string that starts at TextPtr.
+ unsigned IntVal;
public:
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
@@ -94,113 +97,120 @@ public:
StringRef getText() const LLVM_READONLY {
assert(is(tok::text));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setText(StringRef Text) {
assert(is(tok::text));
- TextPtr1 = Text.data();
- TextLen1 = Text.size();
+ TextPtr = Text.data();
+ IntVal = Text.size();
+ }
+
+ StringRef getUnknownCommandName() const LLVM_READONLY {
+ assert(is(tok::unknown_command));
+ return StringRef(TextPtr, IntVal);
+ }
+
+ void setUnknownCommandName(StringRef Name) {
+ assert(is(tok::unknown_command));
+ TextPtr = Name.data();
+ IntVal = Name.size();
}
- StringRef getCommandName() const LLVM_READONLY {
+ unsigned getCommandID() const LLVM_READONLY {
assert(is(tok::command));
- return StringRef(TextPtr1, TextLen1);
+ return IntVal;
}
- void setCommandName(StringRef Name) {
+ void setCommandID(unsigned ID) {
assert(is(tok::command));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ IntVal = ID;
}
- StringRef getVerbatimBlockName() const LLVM_READONLY {
+ unsigned getVerbatimBlockID() const LLVM_READONLY {
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
- return StringRef(TextPtr1, TextLen1);
+ return IntVal;
}
- void setVerbatimBlockName(StringRef Name) {
+ void setVerbatimBlockID(unsigned ID) {
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ IntVal = ID;
}
StringRef getVerbatimBlockText() const LLVM_READONLY {
assert(is(tok::verbatim_block_line));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setVerbatimBlockText(StringRef Text) {
assert(is(tok::verbatim_block_line));
- TextPtr1 = Text.data();
- TextLen1 = Text.size();
+ TextPtr = Text.data();
+ IntVal = Text.size();
}
- /// Returns the name of verbatim line command.
- StringRef getVerbatimLineName() const LLVM_READONLY {
+ unsigned getVerbatimLineID() const LLVM_READONLY {
assert(is(tok::verbatim_line_name));
- return StringRef(TextPtr1, TextLen1);
+ return IntVal;
}
- void setVerbatimLineName(StringRef Name) {
+ void setVerbatimLineID(unsigned ID) {
assert(is(tok::verbatim_line_name));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ IntVal = ID;
}
StringRef getVerbatimLineText() const LLVM_READONLY {
assert(is(tok::verbatim_line_text));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setVerbatimLineText(StringRef Text) {
assert(is(tok::verbatim_line_text));
- TextPtr1 = Text.data();
- TextLen1 = Text.size();
+ TextPtr = Text.data();
+ IntVal = Text.size();
}
StringRef getHTMLTagStartName() const LLVM_READONLY {
assert(is(tok::html_start_tag));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setHTMLTagStartName(StringRef Name) {
assert(is(tok::html_start_tag));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ TextPtr = Name.data();
+ IntVal = Name.size();
}
StringRef getHTMLIdent() const LLVM_READONLY {
assert(is(tok::html_ident));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setHTMLIdent(StringRef Name) {
assert(is(tok::html_ident));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ TextPtr = Name.data();
+ IntVal = Name.size();
}
StringRef getHTMLQuotedString() const LLVM_READONLY {
assert(is(tok::html_quoted_string));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setHTMLQuotedString(StringRef Str) {
assert(is(tok::html_quoted_string));
- TextPtr1 = Str.data();
- TextLen1 = Str.size();
+ TextPtr = Str.data();
+ IntVal = Str.size();
}
StringRef getHTMLTagEndName() const LLVM_READONLY {
assert(is(tok::html_end_tag));
- return StringRef(TextPtr1, TextLen1);
+ return StringRef(TextPtr, IntVal);
}
void setHTMLTagEndName(StringRef Name) {
assert(is(tok::html_end_tag));
- TextPtr1 = Name.data();
- TextLen1 = Name.size();
+ TextPtr = Name.data();
+ IntVal = Name.size();
}
void dump(const Lexer &L, const SourceManager &SM) const;
@@ -209,8 +219,8 @@ public:
/// \brief Comment lexer.
class Lexer {
private:
- Lexer(const Lexer&); // DO NOT IMPLEMENT
- void operator=(const Lexer&); // DO NOT IMPLEMENT
+ Lexer(const Lexer &) LLVM_DELETED_FUNCTION;
+ void operator=(const Lexer &) LLVM_DELETED_FUNCTION;
/// Allocator for strings that are semantic values of tokens and have to be
/// computed (for example, resolved decimal character references).
@@ -221,7 +231,6 @@ private:
const char *const BufferStart;
const char *const BufferEnd;
SourceLocation FileLoc;
- CommentOptions CommOpts;
const char *BufferPtr;
@@ -286,8 +295,8 @@ private:
Result.setKind(Kind);
Result.setLength(TokLen);
#ifndef NDEBUG
- Result.TextPtr1 = "<UNSET>";
- Result.TextLen1 = 7;
+ Result.TextPtr = "<UNSET>";
+ Result.IntVal = 7;
#endif
BufferPtr = TokEnd;
}
@@ -314,13 +323,14 @@ private:
void setupAndLexVerbatimBlock(Token &T,
const char *TextBegin,
- char Marker, StringRef EndName);
+ char Marker, const CommandInfo *Info);
void lexVerbatimBlockFirstLine(Token &T);
void lexVerbatimBlockBody(Token &T);
- void setupAndLexVerbatimLine(Token &T, const char *TextBegin);
+ void setupAndLexVerbatimLine(Token &T, const char *TextBegin,
+ const CommandInfo *Info);
void lexVerbatimLineText(Token &T);
@@ -336,7 +346,7 @@ private:
public:
Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
- SourceLocation FileLoc, const CommentOptions &CommOpts,
+ SourceLocation FileLoc,
const char *BufferStart, const char *BufferEnd);
void lex(Token &T);
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index 039079931c58..19e1d57fc3f5 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -28,8 +28,8 @@ class CommandTraits;
/// Doxygen comment parser.
class Parser {
- Parser(const Parser&); // DO NOT IMPLEMENT
- void operator=(const Parser&); // DO NOT IMPLEMENT
+ Parser(const Parser &) LLVM_DELETED_FUNCTION;
+ void operator=(const Parser &) LLVM_DELETED_FUNCTION;
friend class TextTokenRetokenizer;
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index e1756ca3e2f1..0340b3cfd52d 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -25,13 +25,14 @@
namespace clang {
class Decl;
class SourceMgr;
+class Preprocessor;
namespace comments {
class CommandTraits;
class Sema {
- Sema(const Sema&); // DO NOT IMPLEMENT
- void operator=(const Sema&); // DO NOT IMPLEMENT
+ Sema(const Sema &) LLVM_DELETED_FUNCTION;
+ void operator=(const Sema &) LLVM_DELETED_FUNCTION;
/// Allocator for AST nodes.
llvm::BumpPtrAllocator &Allocator;
@@ -41,18 +42,13 @@ class Sema {
DiagnosticsEngine &Diags;
- const CommandTraits &Traits;
+ CommandTraits &Traits;
+
+ const Preprocessor *PP;
/// Information about the declaration this comment is attached to.
DeclInfo *ThisDeclInfo;
- /// Comment AST nodes that correspond to \c ParamVars for which we have
- /// found a \\param command or NULL if no documentation was found so far.
- ///
- /// Has correct size and contains valid values if \c DeclInfo->IsFilled is
- /// true.
- llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
-
/// Comment AST nodes that correspond to parameter names in
/// \c TemplateParameters.
///
@@ -75,7 +71,8 @@ class Sema {
public:
Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
- DiagnosticsEngine &Diags, const CommandTraits &Traits);
+ DiagnosticsEngine &Diags, CommandTraits &Traits,
+ const Preprocessor *PP);
void setDecl(const Decl *D);
@@ -96,7 +93,7 @@ public:
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name);
+ unsigned CommandID);
void actOnBlockCommandArgs(BlockCommandComment *Command,
ArrayRef<BlockCommandComment::Argument> Args);
@@ -106,7 +103,7 @@ public:
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name);
+ unsigned CommandID);
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -123,7 +120,7 @@ public:
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name);
+ unsigned CommandID);
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -135,25 +132,29 @@ public:
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName);
+ unsigned CommandID);
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName,
+ unsigned CommandID,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg);
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name);
+ StringRef CommandName);
+
+ InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID);
TextComment *actOnText(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Text);
VerbatimBlockComment *actOnVerbatimBlockStart(SourceLocation Loc,
- StringRef Name);
+ unsigned CommandID);
VerbatimBlockLineComment *actOnVerbatimBlockLine(SourceLocation Loc,
StringRef Text);
@@ -164,7 +165,7 @@ public:
ArrayRef<VerbatimBlockLineComment *> Lines);
VerbatimLineComment *actOnVerbatimLine(SourceLocation LocBegin,
- StringRef Name,
+ unsigned CommandID,
SourceLocation TextBegin,
StringRef Text);
@@ -190,6 +191,12 @@ public:
/// used only once per comment, e.g., \\brief and \\returns.
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
+ void checkDeprecatedCommand(const BlockCommandComment *Comment);
+
+ /// Resolve parameter names to parameter indexes in function declaration.
+ /// Emit diagnostics about unknown parametrs.
+ void resolveParamCommandIndexes(const FullComment *FC);
+
bool isFunctionDecl();
bool isTemplateOrSpecialization();
@@ -218,9 +225,6 @@ public:
InlineCommandComment::RenderKind
getInlineCommandRenderKind(StringRef Name) const;
-
- bool isHTMLEndTagOptional(StringRef Name);
- bool isHTMLEndTagForbidden(StringRef Name);
};
} // end namespace comments
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index e9f25b368aad..087a58587471 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -88,7 +88,6 @@ public:
static TranslationUnitDecl *Create(ASTContext &C);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TranslationUnitDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TranslationUnit; }
static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
@@ -214,16 +213,19 @@ public:
bool isCXXInstanceMember() const;
class LinkageInfo {
- Linkage linkage_;
- Visibility visibility_;
- bool explicit_;
+ uint8_t linkage_ : 2;
+ uint8_t visibility_ : 2;
+ uint8_t explicit_ : 1;
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
public:
LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
explicit_(false) {}
LinkageInfo(Linkage L, Visibility V, bool E)
- : linkage_(L), visibility_(V), explicit_(E) {}
+ : linkage_(L), visibility_(V), explicit_(E) {
+ assert(linkage() == L && visibility() == V && visibilityExplicit() == E &&
+ "Enum truncated!");
+ }
static LinkageInfo external() {
return LinkageInfo();
@@ -238,8 +240,8 @@ public:
return LinkageInfo(NoLinkage, DefaultVisibility, false);
}
- Linkage linkage() const { return linkage_; }
- Visibility visibility() const { return visibility_; }
+ Linkage linkage() const { return (Linkage)linkage_; }
+ Visibility visibility() const { return (Visibility)visibility_; }
bool visibilityExplicit() const { return explicit_; }
void setLinkage(Linkage L) { linkage_ = L; }
@@ -337,7 +339,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const NamedDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
@@ -383,7 +384,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const LabelDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Label; }
};
@@ -509,7 +509,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const NamespaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Namespace; }
static DeclContext *castToDeclContext(const NamespaceDecl *D) {
return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
@@ -545,7 +544,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ValueDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
};
@@ -578,8 +576,8 @@ struct QualifierInfo {
private:
// Copy constructor and copy assignment are disabled.
- QualifierInfo(const QualifierInfo&);
- QualifierInfo& operator=(const QualifierInfo&);
+ QualifierInfo(const QualifierInfo&) LLVM_DELETED_FUNCTION;
+ QualifierInfo& operator=(const QualifierInfo&) LLVM_DELETED_FUNCTION;
};
/// \brief Represents a ValueDecl that came out of a declarator.
@@ -666,7 +664,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const DeclaratorDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstDeclarator && K <= lastDeclarator;
}
@@ -712,7 +709,7 @@ public:
typedef clang::StorageClass StorageClass;
/// getStorageClassSpecifierString - Return the string used to
- /// specify the storage class \arg SC.
+ /// specify the storage class \p SC.
///
/// It is illegal to call this function with SC == None.
static const char *getStorageClassSpecifierString(StorageClass SC);
@@ -1208,7 +1205,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const VarDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
};
@@ -1229,7 +1225,6 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const ImplicitParamDecl *D) { return true; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ImplicitParam; }
};
@@ -1399,7 +1394,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ParmVarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ParmVar; }
private:
@@ -2070,7 +2064,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FunctionDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstFunction && K <= lastFunction;
}
@@ -2204,7 +2197,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
friend class ASTDeclReader;
@@ -2243,7 +2235,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const EnumConstantDecl *D) { return true; }
static bool classofKind(Kind K) { return K == EnumConstant; }
friend class StmtIteratorBase;
@@ -2287,7 +2278,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const IndirectFieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K == IndirectField; }
friend class ASTDeclReader;
};
@@ -2334,7 +2324,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TypeDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstType && K <= lastType; }
};
@@ -2390,7 +2379,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TypedefNameDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTypedefName && K <= lastTypedefName;
}
@@ -2413,7 +2401,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TypedefDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Typedef; }
};
@@ -2434,7 +2421,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TypeAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TypeAlias; }
};
@@ -2448,7 +2434,7 @@ public:
private:
// FIXME: This can be packed into the bitfields in Decl.
/// TagDeclKind - The TagKind enum.
- unsigned TagDeclKind : 2;
+ unsigned TagDeclKind : 3;
/// IsCompleteDefinition - True if this is a definition ("struct foo
/// {};"), false if it is a declaration ("struct foo;"). It is not
@@ -2625,6 +2611,7 @@ public:
void setTagKind(TagKind TK) { TagDeclKind = TK; }
bool isStruct() const { return getTagKind() == TTK_Struct; }
+ bool isInterface() const { return getTagKind() == TTK_Interface; }
bool isClass() const { return getTagKind() == TTK_Class; }
bool isUnion() const { return getTagKind() == TTK_Union; }
bool isEnum() const { return getTagKind() == TTK_Enum; }
@@ -2665,7 +2652,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TagDecl *D) { return true; }
static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; }
static DeclContext *castToDeclContext(const TagDecl *D) {
@@ -2895,7 +2881,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const EnumDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Enum; }
friend class ASTDeclReader;
@@ -3026,11 +3011,15 @@ public:
virtual void completeDefinition();
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const RecordDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRecord && K <= lastRecord;
}
+ /// isMsStrust - Get whether or not this is an ms_struct which can
+ /// be turned on with an attribute, pragma, or -mms-bitfields
+ /// commandline option.
+ bool isMsStruct(const ASTContext &C) const;
+
private:
/// \brief Deserialize just the fields.
void LoadFieldsFromExternalStorage() const;
@@ -3062,7 +3051,6 @@ public:
void setAsmString(StringLiteral *Asm) { AsmString = Asm; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FileScopeAsmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == FileScopeAsm; }
};
@@ -3208,7 +3196,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const BlockDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Block; }
static DeclContext *castToDeclContext(const BlockDecl *D) {
return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
@@ -3282,7 +3269,6 @@ public:
virtual SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ImportDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Import; }
};
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 0f596095f74a..50e202738dd4 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -430,16 +430,10 @@ public:
void dropAttr() {
if (!HasAttrs) return;
- AttrVec &Attrs = getAttrs();
- for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
- if (isa<T>(Attrs[i])) {
- Attrs.erase(Attrs.begin() + i);
- --e;
- }
- else
- ++i;
- }
- if (Attrs.empty())
+ AttrVec &Vec = getAttrs();
+ Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa<T, Attr*>), Vec.end());
+
+ if (Vec.empty())
HasAttrs = false;
}
@@ -844,8 +838,6 @@ public:
IdentifierNamespace |= IDNS_NonMemberOperator;
}
- // Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *) { return true; }
static bool classofKind(Kind K) { return true; }
static DeclContext *castToDeclContext(const Decl *);
static Decl *castFromDeclContext(const DeclContext *);
@@ -1479,6 +1471,13 @@ public:
inline ddiag_iterator ddiag_end() const;
// Low-level accessors
+
+ /// \brief Mark the lookup table as needing to be built. This should be
+ /// used only if setHasExternalLexicalStorage() has been called.
+ void setMustBuildLookupTable() {
+ assert(ExternalLexicalStorage && "Requires external lexical storage");
+ LookupPtr.setInt(true);
+ }
/// \brief Retrieve the internal representation of the lookup structure.
/// This may omit some names if we are lazily building the structure.
@@ -1516,10 +1515,6 @@ public:
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
-#define DECL(NAME, BASE)
-#define DECL_CONTEXT(NAME) \
- static bool classof(const NAME##Decl *D) { return true; }
-#include "clang/AST/DeclNodes.inc"
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 2d95f038dfd4..9cb56e2b3ccc 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -145,7 +145,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const AccessSpecDecl *D) { return true; }
static bool classofKind(Kind K) { return K == AccessSpec; }
};
@@ -563,9 +562,10 @@ class CXXRecordDecl : public RecordDecl {
struct LambdaDefinitionData : public DefinitionData {
typedef LambdaExpr::Capture Capture;
- LambdaDefinitionData(CXXRecordDecl *D, bool Dependent)
+ LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
: DefinitionData(D), Dependent(Dependent), NumCaptures(0),
- NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0)
+ NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
+ MethodTyInfo(Info)
{
IsLambda = true;
}
@@ -598,7 +598,10 @@ class CXXRecordDecl : public RecordDecl {
/// \brief The list of captures, both explicit and implicit, for this
/// lambda.
- Capture *Captures;
+ Capture *Captures;
+
+ /// \brief The type of the call method.
+ TypeSourceInfo *MethodTyInfo;
};
struct DefinitionData &data() {
@@ -705,7 +708,8 @@ public:
IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
bool DelayTypeCreation = false);
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
- SourceLocation Loc, bool DependentLambda);
+ TypeSourceInfo *Info, SourceLocation Loc,
+ bool DependentLambda);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
bool isDynamicClass() const {
@@ -1303,7 +1307,7 @@ public:
/// \brief Function type used by forallBases() as a callback.
///
- /// \param Base the definition of the base class
+ /// \param BaseDefinition the definition of the base class
///
/// \returns true if this base matched the search criteria
typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition,
@@ -1500,15 +1504,15 @@ public:
bool isDependentLambda() const {
return isLambda() && getLambdaData().Dependent;
}
-
+
+ TypeSourceInfo *getLambdaTypeInfo() const {
+ return getLambdaData().MethodTyInfo;
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstCXXRecord && K <= lastCXXRecord;
}
- static bool classof(const CXXRecordDecl *D) { return true; }
- static bool classof(const ClassTemplateSpecializationDecl *D) {
- return true;
- }
friend class ASTDeclReader;
friend class ASTDeclWriter;
@@ -1549,14 +1553,16 @@ public:
bool isStatic() const { return getStorageClass() == SC_Static; }
bool isInstance() const { return !isStatic(); }
- bool isConst() { return getType()->castAs<FunctionType>()->isConst(); }
- bool isVolatile() { return getType()->castAs<FunctionType>()->isVolatile(); }
+ bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
+ bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); }
bool isVirtual() const {
CXXMethodDecl *CD =
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
- if (CD->isVirtualAsWritten())
+ // Methods declared in interfaces are automatically (pure) virtual.
+ if (CD->isVirtualAsWritten() ||
+ (CD->getParent()->isInterface() && CD->isUserProvided()))
return true;
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
@@ -1661,7 +1667,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const CXXMethodDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstCXXMethod && K <= lastCXXMethod;
}
@@ -2141,7 +2146,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const CXXConstructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConstructor; }
friend class ASTDeclReader;
@@ -2213,7 +2217,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const CXXDestructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXDestructor; }
friend class ASTDeclReader;
@@ -2280,7 +2283,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const CXXConversionDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConversion; }
friend class ASTDeclReader;
@@ -2350,7 +2352,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const LinkageSpecDecl *D) { return true; }
static bool classofKind(Kind K) { return K == LinkageSpec; }
static DeclContext *castToDeclContext(const LinkageSpecDecl *D) {
return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D));
@@ -2454,7 +2455,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const UsingDirectiveDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UsingDirective; }
// Friend for getUsingDirectiveName.
@@ -2548,7 +2548,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const NamespaceAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == NamespaceAlias; }
};
@@ -2619,7 +2618,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const UsingShadowDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
friend class ASTDeclReader;
@@ -2751,7 +2749,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const UsingDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Using; }
friend class ASTDeclReader;
@@ -2825,7 +2822,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const UnresolvedUsingValueDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
friend class ASTDeclReader;
@@ -2891,7 +2887,6 @@ public:
CreateDeserialized(ASTContext &C, unsigned ID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
};
@@ -2931,7 +2926,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(StaticAssertDecl *D) { return true; }
static bool classofKind(Kind K) { return K == StaticAssert; }
friend class ASTDeclReader;
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 9a64f08dee50..37e45868b57c 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "llvm/Support/Compiler.h"
namespace clang {
@@ -104,9 +105,15 @@ public:
/// Retrieves the source range for the friend declaration.
SourceRange getSourceRange() const LLVM_READONLY {
- /* FIXME: consider the case of templates wrt start of range. */
- if (NamedDecl *ND = getFriendDecl())
+ if (NamedDecl *ND = getFriendDecl()) {
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ return FTD->getSourceRange();
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(ND)) {
+ if (DD->getOuterLocStart() != DD->getInnerLocStart())
+ return DD->getSourceRange();
+ }
return SourceRange(getFriendLoc(), ND->getLocEnd());
+ }
else if (TypeSourceInfo *TInfo = getFriendType())
return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
else
@@ -123,7 +130,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FriendDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Decl::Friend; }
friend class ASTDeclReader;
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 6c39f2c3abe1..8b27dd8e9e16 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -33,8 +33,8 @@ class ObjCPropertyImplDecl;
class CXXCtorInitializer;
class ObjCListBase {
- void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
- ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT
+ ObjCListBase(const ObjCListBase &) LLVM_DELETED_FUNCTION;
+ void operator=(const ObjCListBase &) LLVM_DELETED_FUNCTION;
protected:
/// List is an array of pointers to objects that are not owned by this object.
void **List;
@@ -123,8 +123,8 @@ private:
unsigned IsInstance : 1;
unsigned IsVariadic : 1;
- // Synthesized declaration method for a property setter/getter
- unsigned IsSynthesized : 1;
+ /// True if this method is the getter or setter for an explicit property.
+ unsigned IsPropertyAccessor : 1;
// Method has a definition.
unsigned IsDefined : 1;
@@ -174,8 +174,7 @@ private:
SourceLocation DeclEndLoc; // the location of the ';' or '{'.
// The following are only used for method definitions, null otherwise.
- // FIXME: space savings opportunity, consider a sub-class.
- Stmt *Body;
+ LazyDeclStmtPtr Body;
/// SelfDecl - Decl for the implicit self parameter. This is lazily
/// constructed by createImplicitParams.
@@ -227,7 +226,7 @@ private:
DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
- bool isSynthesized = false,
+ bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
@@ -235,14 +234,14 @@ private:
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
IsInstance(isInstance), IsVariadic(isVariadic),
- IsSynthesized(isSynthesized),
+ IsPropertyAccessor(isPropertyAccessor),
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
RelatedResultType(HasRelatedResultType),
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
MethodDeclType(T), ResultTInfo(ResultTInfo),
ParamsAndSelLocs(0), NumParams(0),
- DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
+ DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -261,7 +260,7 @@ public:
DeclContext *contextDecl,
bool isInstance = true,
bool isVariadic = false,
- bool isSynthesized = false,
+ bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false,
bool isDefined = false,
ImplementationControl impControl = None,
@@ -363,7 +362,7 @@ public:
}
/// \brief Sets the method's parameters and selector source locations.
- /// If the method is implicit (not coming from source) \arg SelLocs is
+ /// If the method is implicit (not coming from source) \p SelLocs is
/// ignored.
void setMethodParams(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
@@ -403,8 +402,8 @@ public:
bool isClassMethod() const { return !IsInstance; }
- bool isSynthesized() const { return IsSynthesized; }
- void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
+ bool isPropertyAccessor() const { return IsPropertyAccessor; }
+ void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; }
bool isDefined() const { return IsDefined; }
void setDefined(bool isDefined) { IsDefined = isDefined; }
@@ -418,7 +417,25 @@ public:
/// method in the interface or its categories.
bool isOverriding() const { return IsOverriding; }
void setOverriding(bool isOverriding) { IsOverriding = isOverriding; }
-
+
+ /// \brief Return overridden methods for the given \p Method.
+ ///
+ /// An ObjC method is considered to override any method in the class's
+ /// base classes (and base's categories), its protocols, or its categories'
+ /// protocols, that has
+ /// the same selector and is of the same kind (class or instance).
+ /// A method in an implementation is not considered as overriding the same
+ /// method in the interface or its categories.
+ void getOverriddenMethods(
+ SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const;
+
+ /// \brief Returns the property associated with this method's selector.
+ ///
+ /// Note that even if this particular method is not marked as a property
+ /// accessor, it is still possible for it to match a property declared in a
+ /// superclass. Pass \c false if you only want to check the current class.
+ const ObjCPropertyDecl *findPropertyDecl(bool CheckOverrides = true) const;
+
// Related to protocols declared in \@protocol
void setDeclImplementation(ImplementationControl ic) {
DeclImplementation = ic;
@@ -427,10 +444,15 @@ public:
return ImplementationControl(DeclImplementation);
}
- virtual Stmt *getBody() const {
- return (Stmt*) Body;
- }
- CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; }
+ /// \brief Determine whether this method has a body.
+ virtual bool hasBody() const { return Body; }
+
+ /// \brief Retrieve the body of this method, if it has one.
+ virtual Stmt *getBody() const;
+
+ void setLazyBody(uint64_t Offset) { Body = Offset; }
+
+ CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); }
void setBody(Stmt *B) { Body = B; }
/// \brief Returns whether this specific method is a definition.
@@ -438,7 +460,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCMethodDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCMethod; }
static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
@@ -520,6 +541,13 @@ public:
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
+ typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
+
+ /// This routine collects list of properties to be implemented in the class.
+ /// This includes, class's and its conforming protocols' properties.
+ /// Note, the superclass's properties are not included in the list.
+ virtual void collectPropertiesToImplement(PropertyMap &PM) const {}
+
SourceLocation getAtStartLoc() const { return AtStart; }
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
@@ -537,7 +565,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCContainerDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstObjCContainer &&
K <= lastObjCContainer;
@@ -880,6 +907,8 @@ public:
ObjCPropertyDecl
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
+ virtual void collectPropertiesToImplement(PropertyMap &PM) const;
+
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
@@ -992,7 +1021,6 @@ public:
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCInterfaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCInterface; }
friend class ASTReader;
@@ -1065,7 +1093,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCIvarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCIvar; }
private:
/// NextIvar - Next Ivar in the list of ivars declared in class; class's
@@ -1098,7 +1125,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
};
@@ -1277,8 +1303,9 @@ public:
return getFirstDeclaration();
}
+ virtual void collectPropertiesToImplement(PropertyMap &PM) const;
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCProtocolDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
friend class ASTReader;
@@ -1402,7 +1429,6 @@ public:
SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCCategoryDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategory; }
friend class ASTDeclReader;
@@ -1455,7 +1481,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCImplDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstObjCImpl && K <= lastObjCImpl;
}
@@ -1532,7 +1557,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCCategoryImplDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
friend class ASTDeclReader;
@@ -1568,8 +1592,12 @@ class ObjCImplementationDecl : public ObjCImplDecl {
CXXCtorInitializer **IvarInitializers;
unsigned NumIvarInitializers;
- /// true if class has a .cxx_[construct,destruct] method.
- bool HasCXXStructors : 1;
+ /// Do the ivars of this class require initialization other than
+ /// zero-initialization?
+ bool HasNonZeroConstructors : 1;
+
+ /// Do the ivars of this class require non-trivial destruction?
+ bool HasDestructors : 1;
ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface,
@@ -1581,7 +1609,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
IvarRBraceLoc(IvarRBraceLoc),
IvarInitializers(0), NumIvarInitializers(0),
- HasCXXStructors(false) {}
+ HasNonZeroConstructors(false), HasDestructors(false) {}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
@@ -1625,8 +1653,15 @@ public:
CXXCtorInitializer ** initializers,
unsigned numInitializers);
- bool hasCXXStructors() const { return HasCXXStructors; }
- void setHasCXXStructors(bool val) { HasCXXStructors = val; }
+ /// Do any of the ivars of this class (not counting its base classes)
+ /// require construction other than zero-initialization?
+ bool hasNonZeroConstructors() const { return HasNonZeroConstructors; }
+ void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; }
+
+ /// Do any of the ivars of this class (not counting its base classes)
+ /// require non-trivial destruction?
+ bool hasDestructors() const { return HasDestructors; }
+ void setHasDestructors(bool val) { HasDestructors = val; }
/// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation.
@@ -1676,7 +1711,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCImplementationDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCImplementation; }
friend class ASTDeclReader;
@@ -1708,7 +1742,6 @@ public:
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCCompatibleAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; }
};
@@ -1882,13 +1915,15 @@ public:
virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, getLocation());
}
+
+ /// Get the default name of the synthesized ivar.
+ IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
/// Lookup a property by name in the specified DeclContext.
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
IdentifierInfo *propertyID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCPropertyDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCProperty; }
};
@@ -1999,7 +2034,6 @@ public:
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCPropertyImplDecl *D) { return true; }
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
friend class ASTDeclReader;
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 7affc7e15f27..862011666205 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -50,7 +50,11 @@ class TemplateParameterList {
/// The number of template parameters in this template
/// parameter list.
- unsigned NumParams;
+ unsigned NumParams : 31;
+
+ /// Whether this template parameter list contains an unexpanded parameter
+ /// pack.
+ unsigned ContainsUnexpandedParameterPack : 1;
protected:
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
@@ -104,6 +108,12 @@ public:
/// the second template parameter list will have depth 1, etc.
unsigned getDepth() const;
+ /// \brief Determine whether this template parameter list contains an
+ /// unexpanded parameter pack.
+ bool containsUnexpandedParameterPack() const {
+ return ContainsUnexpandedParameterPack;
+ }
+
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -139,8 +149,8 @@ class TemplateArgumentList {
/// argument list.
unsigned NumArguments;
- TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL
- void operator=(const TemplateArgumentList &Other); // DO NOT IMPL
+ TemplateArgumentList(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
+ void operator=(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
bool Owned)
@@ -233,12 +243,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TemplateDecl *D) { return true; }
- static bool classof(const RedeclarableTemplateDecl *D) { return true; }
- static bool classof(const FunctionTemplateDecl *D) { return true; }
- static bool classof(const ClassTemplateDecl *D) { return true; }
- static bool classof(const TemplateTemplateParmDecl *D) { return true; }
- static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTemplate && K <= lastTemplate;
}
@@ -678,10 +682,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const RedeclarableTemplateDecl *D) { return true; }
- static bool classof(const FunctionTemplateDecl *D) { return true; }
- static bool classof(const ClassTemplateDecl *D) { return true; }
- static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
}
@@ -827,7 +827,6 @@ public:
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == FunctionTemplate; }
friend class ASTDeclReader;
@@ -969,7 +968,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TemplateTypeParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TemplateTypeParm; }
};
@@ -1090,8 +1088,17 @@ public:
/// \endcode
bool isParameterPack() const { return ParameterPack; }
+ /// \brief Whether this parameter pack is a pack expansion.
+ ///
+ /// A non-type template parameter pack is a pack expansion if its type
+ /// contains an unexpanded parameter pack. In this case, we will have
+ /// built a PackExpansionType wrapping the type.
+ bool isPackExpansion() const {
+ return ParameterPack && getType()->getAs<PackExpansionType>();
+ }
+
/// \brief Whether this parameter is a non-type template parameter pack
- /// that has different types at different positions.
+ /// that has a known list of different types at different positions.
///
/// A parameter pack is an expanded parameter pack when the original
/// parameter pack's type was itself a pack expansion, and that expansion
@@ -1141,7 +1148,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
};
@@ -1165,23 +1171,47 @@ class TemplateTemplateParmDecl : public TemplateDecl,
/// \brief Whether this parameter is a parameter pack.
bool ParameterPack;
+ /// \brief Whether this template template parameter is an "expanded"
+ /// parameter pack, meaning that it is a pack expansion and we
+ /// already know the set of template parameters that expansion expands to.
+ bool ExpandedParameterPack;
+
+ /// \brief The number of parameters in an expanded parameter pack.
+ unsigned NumExpandedParams;
+
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), DefaultArgument(),
- DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
+ DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
+ ExpandedParameterPack(false), NumExpandedParams(0)
{ }
+ TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
+ unsigned D, unsigned P,
+ IdentifierInfo *Id, TemplateParameterList *Params,
+ unsigned NumExpansions,
+ TemplateParameterList * const *Expansions);
+
public:
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, bool ParameterPack,
IdentifierInfo *Id,
TemplateParameterList *Params);
+ static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D,
+ unsigned P,
+ IdentifierInfo *Id,
+ TemplateParameterList *Params,
+ llvm::ArrayRef<TemplateParameterList*> Expansions);
- static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
+ static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
+ static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned NumExpansions);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
@@ -1195,6 +1225,49 @@ public:
/// \endcode
bool isParameterPack() const { return ParameterPack; }
+ /// \brief Whether this parameter pack is a pack expansion.
+ ///
+ /// A template template parameter pack is a pack expansion if its template
+ /// parameter list contains an unexpanded parameter pack.
+ bool isPackExpansion() const {
+ return ParameterPack &&
+ getTemplateParameters()->containsUnexpandedParameterPack();
+ }
+
+ /// \brief Whether this parameter is a template template parameter pack that
+ /// has a known list of different template parameter lists at different
+ /// positions.
+ ///
+ /// A parameter pack is an expanded parameter pack when the original parameter
+ /// pack's template parameter list was itself a pack expansion, and that
+ /// expansion has already been expanded. For exampe, given:
+ ///
+ /// \code
+ /// template<typename...Types> struct Outer {
+ /// template<template<Types> class...Templates> struct Inner;
+ /// };
+ /// \endcode
+ ///
+ /// The parameter pack \c Templates is a pack expansion, which expands the
+ /// pack \c Types. When \c Types is supplied with template arguments by
+ /// instantiating \c Outer, the instantiation of \c Templates is an expanded
+ /// parameter pack.
+ bool isExpandedParameterPack() const { return ExpandedParameterPack; }
+
+ /// \brief Retrieves the number of expansion template parameters in
+ /// an expanded parameter pack.
+ unsigned getNumExpansionTemplateParameters() const {
+ assert(ExpandedParameterPack && "Not an expansion parameter pack");
+ return NumExpandedParams;
+ }
+
+ /// \brief Retrieve a particular expansion type within an expanded parameter
+ /// pack.
+ TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
+ assert(I < NumExpandedParams && "Out-of-range expansion type index");
+ return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
+ }
+
/// \brief Determine whether this template parameter has a default
/// argument.
bool hasDefaultArgument() const {
@@ -1238,7 +1311,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TemplateTemplateParmDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
friend class ASTDeclReader;
@@ -1505,14 +1577,6 @@ public:
K <= lastClassTemplateSpecialization;
}
- static bool classof(const ClassTemplateSpecializationDecl *) {
- return true;
- }
-
- static bool classof(const ClassTemplatePartialSpecializationDecl *) {
- return true;
- }
-
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -1681,10 +1745,6 @@ public:
return K == ClassTemplatePartialSpecialization;
}
- static bool classof(const ClassTemplatePartialSpecializationDecl *) {
- return true;
- }
-
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -1886,7 +1946,6 @@ public:
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ClassTemplate; }
friend class ASTDeclReader;
@@ -1984,7 +2043,6 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::FriendTemplate; }
- static bool classof(const FriendTemplateDecl *D) { return true; }
friend class ASTDeclReader;
};
@@ -2059,7 +2117,6 @@ public:
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
friend class ASTDeclReader;
@@ -2123,9 +2180,6 @@ public:
static bool classofKind(Kind K) {
return K == Decl::ClassScopeFunctionSpecialization;
}
- static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
- return true;
- }
friend class ASTDeclReader;
friend class ASTDeclWriter;
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 614652540679..d991c73612c2 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -334,8 +334,8 @@ class DeclarationNameTable {
CXXOperatorIdName *CXXOperatorNames; // Operator names
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
- DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
- DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
+ DeclarationNameTable(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
+ void operator=(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
public:
DeclarationNameTable(const ASTContext &C);
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 89c003c8f664..dc83654bd948 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -34,6 +34,7 @@
namespace clang {
class ASTContext;
class APValue;
+ class CastExpr;
class Decl;
class IdentifierInfo;
class ParmVarDecl;
@@ -42,6 +43,7 @@ namespace clang {
class BlockDecl;
class CXXBaseSpecifier;
class CXXOperatorCallExpr;
+ class MaterializeTemporaryExpr;
class CXXMemberCallExpr;
class ObjCPropertyRefExpr;
class OpaqueValueExpr;
@@ -49,6 +51,48 @@ namespace clang {
/// \brief A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
+/// \brief An adjustment to be made to the temporary created when emitting a
+/// reference binding, which accesses a particular subobject of that temporary.
+struct SubobjectAdjustment {
+ enum {
+ DerivedToBaseAdjustment,
+ FieldAdjustment,
+ MemberPointerAdjustment
+ } Kind;
+
+ union {
+ struct {
+ const CastExpr *BasePath;
+ const CXXRecordDecl *DerivedClass;
+ } DerivedToBase;
+
+ FieldDecl *Field;
+
+ struct {
+ const MemberPointerType *MPT;
+ Expr *RHS;
+ } Ptr;
+ };
+
+ SubobjectAdjustment(const CastExpr *BasePath,
+ const CXXRecordDecl *DerivedClass)
+ : Kind(DerivedToBaseAdjustment) {
+ DerivedToBase.BasePath = BasePath;
+ DerivedToBase.DerivedClass = DerivedClass;
+ }
+
+ SubobjectAdjustment(FieldDecl *Field)
+ : Kind(FieldAdjustment) {
+ this->Field = Field;
+ }
+
+ SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS)
+ : Kind(MemberPointerAdjustment) {
+ this->Ptr.MPT = MPT;
+ this->Ptr.RHS = RHS;
+ }
+};
+
/// Expr - This represents one expression. Note that Expr's are subclasses of
/// Stmt. This allows an expression to be transparently used any place a Stmt
/// is required.
@@ -220,15 +264,6 @@ public:
/// Reasons why an expression might not be an l-value.
LValueClassification ClassifyLValue(ASTContext &Ctx) const;
- /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
- /// does not have an incomplete type, does not have a const-qualified type,
- /// and if it is a structure or union, does not have any member (including,
- /// recursively, any member or element of all contained aggregates or unions)
- /// with a const-qualified type.
- ///
- /// \param Loc [in,out] - A source location which *may* be filled
- /// in with the location of the expression making this a
- /// non-modifiable lvalue, if specified.
enum isModifiableLvalueResult {
MLV_Valid,
MLV_NotObjectType,
@@ -247,6 +282,15 @@ public:
MLV_ClassTemporary,
MLV_ArrayTemporary
};
+ /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
+ /// does not have an incomplete type, does not have a const-qualified type,
+ /// and if it is a structure or union, does not have any member (including,
+ /// recursively, any member or element of all contained aggregates or unions)
+ /// with a const-qualified type.
+ ///
+ /// \param Loc [in,out] - A source location which *may* be filled
+ /// in with the location of the expression making this a
+ /// non-modifiable lvalue, if specified.
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;
@@ -392,6 +436,9 @@ public:
/// property, find the underlying property reference expression.
const ObjCPropertyRefExpr *getObjCProperty() const;
+ /// \brief Check if this expression is the ObjC 'self' implicit parameter.
+ bool isObjCSelfExpr() const;
+
/// \brief Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
@@ -692,11 +739,22 @@ public:
/// behavior if the object isn't dynamically of the derived type.
const CXXRecordDecl *getBestDynamicClassType() const;
+ /// 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;
+
+ /// Skip irrelevant expressions to find what should be materialize for
+ /// binding with a reference.
+ const Expr *
+ findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const;
+
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
T->getStmtClass() <= lastExprConstant;
}
- static bool classof(const Expr *) { return true; }
};
@@ -762,7 +820,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpaqueValueExprClass;
}
- static bool classof(const OpaqueValueExpr *) { return true; }
};
/// \brief A reference to a declared variable, function, enum, etc.
@@ -1059,7 +1116,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
}
- static bool classof(const DeclRefExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1109,7 +1165,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == PredefinedExprClass;
}
- static bool classof(const PredefinedExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1132,8 +1187,8 @@ class APNumericStorage {
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
- APNumericStorage(const APNumericStorage&); // do not implement
- APNumericStorage& operator=(const APNumericStorage&); // do not implement
+ APNumericStorage(const APNumericStorage &) LLVM_DELETED_FUNCTION;
+ void operator=(const APNumericStorage &) LLVM_DELETED_FUNCTION;
protected:
APNumericStorage() : VAL(0), BitWidth(0) { }
@@ -1196,7 +1251,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == IntegerLiteralClass;
}
- static bool classof(const IntegerLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1243,7 +1297,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CharacterLiteralClass;
}
- static bool classof(const CharacterLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1286,7 +1339,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
}
- static bool classof(const FloatingLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1317,7 +1369,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImaginaryLiteralClass;
}
- static bool classof(const ImaginaryLiteral *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@@ -1479,7 +1530,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == StringLiteralClass;
}
- static bool classof(const StringLiteral *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1520,7 +1570,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenExprClass;
}
- static bool classof(const ParenExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@@ -1610,7 +1659,7 @@ public:
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++"
- static const char *getOpcodeStr(Opcode Op);
+ static StringRef getOpcodeStr(Opcode Op);
/// \brief Retrieve the unary opcode that corresponds to the given
/// overloaded operator.
@@ -1631,7 +1680,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryOperatorClass;
}
- static bool classof(const UnaryOperator *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@@ -1757,8 +1805,7 @@ private:
OffsetOfExpr(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
+ ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc);
explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
@@ -1769,9 +1816,8 @@ public:
static OffsetOfExpr *Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
- SourceLocation RParenLoc);
+ ArrayRef<OffsetOfNode> comps,
+ ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
static OffsetOfExpr *CreateEmpty(ASTContext &C,
unsigned NumComps, unsigned NumExprs);
@@ -1832,8 +1878,6 @@ public:
return T->getStmtClass() == OffsetOfExprClass;
}
- static bool classof(const OffsetOfExpr *) { return true; }
-
// Iterators
child_range children() {
Stmt **begin =
@@ -1937,7 +1981,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
}
- static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; }
// Iterators
child_range children();
@@ -2017,7 +2060,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArraySubscriptExprClass;
}
- static bool classof(const ArraySubscriptExpr *) { return true; }
// Iterators
child_range children() {
@@ -2041,7 +2083,7 @@ class CallExpr : public Expr {
protected:
// These versions of the constructor are for derived classes.
CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
+ ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc);
CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty);
@@ -2061,7 +2103,7 @@ protected:
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
public:
- CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t,
+ CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc);
/// \brief Build an empty call expression.
@@ -2153,7 +2195,6 @@ public:
return T->getStmtClass() >= firstCallExprConstant &&
T->getStmtClass() <= lastCallExprConstant;
}
- static bool classof(const CallExpr *) { return true; }
// Iterators
child_range children() {
@@ -2440,7 +2481,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == MemberExprClass;
}
- static bool classof(const MemberExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@@ -2506,7 +2546,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundLiteralExprClass;
}
- static bool classof(const CompoundLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Init, &Init+1); }
@@ -2597,7 +2636,6 @@ public:
return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant;
}
- static bool classof(const CastExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Op, &Op+1); }
@@ -2661,7 +2699,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitCastExprClass;
}
- static bool classof(const ImplicitCastExpr *) { return true; }
};
inline Expr *Expr::IgnoreImpCasts() {
@@ -2716,7 +2753,6 @@ public:
return T->getStmtClass() >= firstExplicitCastExprConstant &&
T->getStmtClass() <= lastExplicitCastExprConstant;
}
- static bool classof(const ExplicitCastExpr *) { return true; }
};
/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style
@@ -2757,7 +2793,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CStyleCastExprClass;
}
- static bool classof(const CStyleCastExpr *) { return true; }
};
/// \brief A builtin binary operation expression such as "x + y" or "x <= y".
@@ -2784,6 +2819,12 @@ public:
private:
unsigned Opc : 6;
+
+ // Records the FP_CONTRACT pragma status at the point that this binary
+ // operator was parsed. This bit is only meaningful for operations on
+ // floating point types. For all other types it should default to
+ // false.
+ unsigned FPContractable : 1;
SourceLocation OpLoc;
enum { LHS, RHS, END_EXPR };
@@ -2792,7 +2833,7 @@ public:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc)
+ SourceLocation opLoc, bool fpContractable)
: Expr(BinaryOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2800,7 +2841,7 @@ public:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), OpLoc(opLoc) {
+ Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
@@ -2829,9 +2870,9 @@ public:
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
- static const char *getOpcodeStr(Opcode Op);
+ static StringRef getOpcodeStr(Opcode Op);
- const char *getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
+ StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
/// \brief Retrieve the binary opcode that corresponds to the given
/// overloaded operator.
@@ -2894,17 +2935,24 @@ public:
return S->getStmtClass() >= firstBinaryOperatorConstant &&
S->getStmtClass() <= lastBinaryOperatorConstant;
}
- static bool classof(const BinaryOperator *) { return true; }
// Iterators
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ // Set the FP contractability status of this operator. Only meaningful for
+ // operations on floating point types.
+ void setFPContractable(bool FPC) { FPContractable = FPC; }
+
+ // Get the FP contractability status of this operator. Only meaningful for
+ // operations on floating point types.
+ bool isFPContractable() const { return FPContractable; }
+
protected:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc, bool dead)
+ SourceLocation opLoc, bool fpContractable, bool dead2)
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2912,7 +2960,7 @@ protected:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), OpLoc(opLoc) {
+ Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
@@ -2934,8 +2982,9 @@ public:
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
ExprValueKind VK, ExprObjectKind OK,
QualType CompLHSType, QualType CompResultType,
- SourceLocation OpLoc)
- : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true),
+ SourceLocation OpLoc, bool fpContractable)
+ : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
+ true),
ComputationLHSType(CompLHSType),
ComputationResultType(CompResultType) {
assert(isCompoundAssignmentOp() &&
@@ -2955,7 +3004,6 @@ public:
QualType getComputationResultType() const { return ComputationResultType; }
void setComputationResultType(QualType T) { ComputationResultType = T; }
- static bool classof(const CompoundAssignOperator *) { return true; }
static bool classof(const Stmt *S) {
return S->getStmtClass() == CompoundAssignOperatorClass;
}
@@ -3001,7 +3049,6 @@ public:
return T->getStmtClass() == ConditionalOperatorClass ||
T->getStmtClass() == BinaryConditionalOperatorClass;
}
- static bool classof(const AbstractConditionalOperator *) { return true; }
};
/// ConditionalOperator - The ?: ternary operator. The GNU "missing
@@ -3060,7 +3107,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ConditionalOperatorClass;
}
- static bool classof(const ConditionalOperator *) { return true; }
// Iterators
child_range children() {
@@ -3142,7 +3188,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == BinaryConditionalOperatorClass;
}
- static bool classof(const BinaryConditionalOperator *) { return true; }
// Iterators
child_range children() {
@@ -3198,7 +3243,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == AddrLabelExprClass;
}
- static bool classof(const AddrLabelExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -3242,7 +3286,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == StmtExprClass;
}
- static bool classof(const StmtExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
@@ -3266,9 +3309,8 @@ class ShuffleVectorExpr : public Expr {
unsigned NumExprs;
public:
- ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
- QualType Type, SourceLocation BLoc,
- SourceLocation RP);
+ ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
+ SourceLocation BLoc, SourceLocation RP);
/// \brief Build an empty vector-shuffle expression.
explicit ShuffleVectorExpr(EmptyShell Empty)
@@ -3286,7 +3328,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ShuffleVectorExprClass;
}
- static bool classof(const ShuffleVectorExpr *) { return true; }
/// getNumSubExprs - Return the size of the SubExprs array. This includes the
/// constant expression, the actual arguments passed in, and the function
@@ -3308,7 +3349,7 @@ public:
void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs);
- unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
+ unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const {
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
}
@@ -3381,7 +3422,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ChooseExprClass;
}
- static bool classof(const ChooseExpr *) { return true; }
// Iterators
child_range children() {
@@ -3418,7 +3458,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == GNUNullExprClass;
}
- static bool classof(const GNUNullExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -3464,7 +3503,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == VAArgExprClass;
}
- static bool classof(const VAArgExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
@@ -3501,21 +3539,32 @@ public:
/// initializer lists may still have fewer initializers than there are
/// elements to initialize within the object.
///
+/// After semantic analysis has completed, given an initializer list,
+/// method isSemanticForm() returns true if and only if this is the
+/// semantic form of the initializer list (note: the same AST node
+/// may at the same time be the syntactic form).
/// Given the semantic form of the initializer list, one can retrieve
-/// the original syntactic form of that initializer list (if it
-/// exists) using getSyntacticForm(). Since many initializer lists
-/// have the same syntactic and semantic forms, getSyntacticForm() may
-/// return NULL, indicating that the current initializer list also
-/// serves as its syntactic form.
+/// the syntactic form of that initializer list (when different)
+/// using method getSyntacticForm(); the method returns null if applied
+/// to a initializer list which is already in syntactic form.
+/// Similarly, given the syntactic form (i.e., an initializer list such
+/// that isSemanticForm() returns false), one can retrieve the semantic
+/// form using method getSemanticForm().
+/// Since many initializer lists have the same syntactic and semantic forms,
+/// getSyntacticForm() may return NULL, indicating that the current
+/// semantic initializer list also serves as its syntactic form.
class InitListExpr : public Expr {
// FIXME: Eliminate this vector in favor of ASTContext allocation
typedef ASTVector<Stmt *> InitExprsTy;
InitExprsTy InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
- /// Contains the initializer list that describes the syntactic form
- /// written in the source code.
- InitListExpr *SyntacticForm;
+ /// The alternative form of the initializer list (if it exists).
+ /// The int part of the pair stores whether this initalizer 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.
+ llvm::PointerIntPair<InitListExpr *, 1, bool> AltForm;
/// \brief Either:
/// If this initializer list initializes an array with more elements than
@@ -3528,8 +3577,7 @@ class InitListExpr : public Expr {
public:
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
- Expr **initexprs, unsigned numinits,
- SourceLocation rbraceloc);
+ ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
/// \brief Build an empty initializer list.
explicit InitListExpr(ASTContext &C, EmptyShell Empty)
@@ -3621,12 +3669,20 @@ public:
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
- /// @brief Retrieve the initializer list that describes the
- /// syntactic form of the initializer.
- ///
- ///
- InitListExpr *getSyntacticForm() const { return SyntacticForm; }
- void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
+ bool isSemanticForm() const { return AltForm.getInt(); }
+ InitListExpr *getSemanticForm() const {
+ return isSemanticForm() ? 0 : AltForm.getPointer();
+ }
+ InitListExpr *getSyntacticForm() const {
+ return isSemanticForm() ? AltForm.getPointer() : 0;
+ }
+
+ void setSyntacticForm(InitListExpr *Init) {
+ AltForm.setPointer(Init);
+ AltForm.setInt(true);
+ Init->AltForm.setPointer(this);
+ Init->AltForm.setInt(false);
+ }
bool hadArrayRangeDesignator() const {
return InitListExprBits.HadArrayRangeDesignator != 0;
@@ -3647,7 +3703,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == InitListExprClass;
}
- static bool classof(const InitListExpr *) { return true; }
// Iterators
child_range children() {
@@ -3723,8 +3778,7 @@ private:
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
- Expr **IndexExprs, unsigned NumIndexExprs,
- Expr *Init);
+ ArrayRef<Expr*> IndexExprs, Expr *Init);
explicit DesignatedInitExpr(unsigned NumSubExprs)
: Expr(DesignatedInitExprClass, EmptyShell()),
@@ -3885,7 +3939,7 @@ public:
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
- Expr **IndexExprs, unsigned NumIndexExprs,
+ ArrayRef<Expr*> IndexExprs,
SourceLocation EqualOrColonLoc,
bool GNUSyntax, Expr *Init);
@@ -3985,7 +4039,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
}
- static bool classof(const DesignatedInitExpr *) { return true; }
// Iterators
child_range children() {
@@ -4015,7 +4068,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitValueInitExprClass;
}
- static bool classof(const ImplicitValueInitExpr *) { return true; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange();
@@ -4032,8 +4084,8 @@ class ParenListExpr : public Expr {
SourceLocation LParenLoc, RParenLoc;
public:
- ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs,
- unsigned numexprs, SourceLocation rparenloc);
+ ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
+ SourceLocation rparenloc);
/// \brief Build an empty paren list.
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
@@ -4061,7 +4113,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenListExprClass;
}
- static bool classof(const ParenListExpr *) { return true; }
// Iterators
child_range children() {
@@ -4109,18 +4160,18 @@ class GenericSelectionExpr : public Expr {
public:
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
- SourceLocation RParenLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex);
/// This constructor is used in the result-dependent case.
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
- SourceLocation RParenLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc, SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack);
explicit GenericSelectionExpr(EmptyShell Empty)
@@ -4176,7 +4227,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == GenericSelectionExprClass;
}
- static bool classof(const GenericSelectionExpr *) { return true; }
child_range children() {
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
@@ -4247,7 +4297,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExtVectorElementExprClass;
}
- static bool classof(const ExtVectorElementExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@@ -4289,7 +4338,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockExprClass;
}
- static bool classof(const BlockExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -4336,7 +4384,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == AsTypeExprClass;
}
- static bool classof(const AsTypeExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
@@ -4473,7 +4520,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == PseudoObjectExprClass;
}
- static bool classof(const PseudoObjectExpr *) { return true; }
};
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
@@ -4501,7 +4547,7 @@ private:
friend class ASTStmtReader;
public:
- AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
+ AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t,
AtomicOp op, SourceLocation RP);
/// \brief Determine the number of arguments the specified atomic builtin
@@ -4563,7 +4609,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == AtomicExprClass;
}
- static bool classof(const AtomicExpr *) { return true; }
// Iterators
child_range children() {
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index ecfa9e213637..9c759db1f97a 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -53,14 +53,19 @@ class CXXOperatorCallExpr : public CallExpr {
OverloadedOperatorKind Operator;
SourceRange Range;
+ // Record the FP_CONTRACT state that applies to this operator call. Only
+ // meaningful for floating point types. For other types this value can be
+ // set to false.
+ unsigned FPContractable : 1;
+
SourceRange getSourceRangeImpl() const LLVM_READONLY;
public:
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
- Expr **args, unsigned numargs, QualType t,
- ExprValueKind VK, SourceLocation operatorloc)
- : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, numargs, t, VK,
+ ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
+ SourceLocation operatorloc, bool fpContractable)
+ : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
operatorloc),
- Operator(Op) {
+ Operator(Op), FPContractable(fpContractable) {
Range = getSourceRangeImpl();
}
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@@ -83,7 +88,14 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXOperatorCallExprClass;
}
- static bool classof(const CXXOperatorCallExpr *) { return true; }
+
+ // Set the FP contractability status of this operator. Only meaningful for
+ // operations on floating point types.
+ void setFPContractable(bool FPC) { FPContractable = FPC; }
+
+ // Get the FP contractability status of this operator. Only meaningful for
+ // operations on floating point types.
+ bool isFPContractable() const { return FPContractable; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -99,9 +111,9 @@ public:
/// the object argument).
class CXXMemberCallExpr : public CallExpr {
public:
- CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs,
+ CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation RP)
- : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, numargs, t, VK, RP) {}
+ : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {}
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
@@ -124,7 +136,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXMemberCallExprClass;
}
- static bool classof(const CXXMemberCallExpr *) { return true; }
};
/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function.
@@ -134,10 +145,9 @@ private:
public:
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
- Expr **args, unsigned numargs, QualType t,
- ExprValueKind VK, SourceLocation RP)
- : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, numargs, t, VK,
- RP) {
+ ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
+ SourceLocation RP)
+ : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) {
setConfig(Config);
}
@@ -153,7 +163,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CUDAKernelCallExprClass;
}
- static bool classof(const CUDAKernelCallExpr *) { return true; }
};
/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
@@ -205,7 +214,6 @@ public:
return false;
}
}
- static bool classof(const CXXNamedCastExpr *) { return true; }
};
/// CXXStaticCastExpr - A C++ @c static_cast expression
@@ -235,7 +243,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXStaticCastExprClass;
}
- static bool classof(const CXXStaticCastExpr *) { return true; }
};
/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
@@ -269,7 +276,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDynamicCastExprClass;
}
- static bool classof(const CXXDynamicCastExpr *) { return true; }
};
/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
@@ -301,7 +307,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXReinterpretCastExprClass;
}
- static bool classof(const CXXReinterpretCastExpr *) { return true; }
};
/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
@@ -329,7 +334,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXConstCastExprClass;
}
- static bool classof(const CXXConstCastExpr *) { return true; }
};
/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
@@ -346,11 +350,11 @@ class UserDefinedLiteral : public CallExpr {
SourceLocation UDSuffixLoc;
public:
- UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs,
+ UserDefinedLiteral(ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
- : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK,
- LitEndLoc), UDSuffixLoc(SuffixLoc) {}
+ : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
+ UDSuffixLoc(SuffixLoc) {}
explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
: CallExpr(C, UserDefinedLiteralClass, Empty) {}
@@ -398,7 +402,6 @@ public:
static bool classof(const Stmt *S) {
return S->getStmtClass() == UserDefinedLiteralClass;
}
- static bool classof(const UserDefinedLiteral *) { return true; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -429,7 +432,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBoolLiteralExprClass;
}
- static bool classof(const CXXBoolLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -455,7 +457,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNullPtrLiteralExprClass;
}
- static bool classof(const CXXNullPtrLiteralExpr *) { return true; }
child_range children() { return child_range(); }
};
@@ -536,7 +537,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTypeidExprClass;
}
- static bool classof(const CXXTypeidExpr *) { return true; }
// Iterators
child_range children() {
@@ -611,7 +611,9 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUuidofExprClass;
}
- static bool classof(const CXXUuidofExpr *) { return true; }
+
+ /// Grabs __declspec(uuid()) off a type, or returns 0 if there is none.
+ static UuidAttr *GetUuidAttrOfType(QualType QT);
// Iterators
child_range children() {
@@ -659,7 +661,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
- static bool classof(const CXXThisExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -710,7 +711,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThrowExprClass;
}
- static bool classof(const CXXThrowExpr *) { return true; }
// Iterators
child_range children() {
@@ -798,7 +798,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDefaultArgExprClass;
}
- static bool classof(const CXXDefaultArgExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -875,7 +874,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBindTemporaryExprClass;
}
- static bool classof(const CXXBindTemporaryExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
@@ -908,7 +906,7 @@ protected:
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
- Expr **args, unsigned numargs,
+ ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@@ -934,7 +932,7 @@ public:
static CXXConstructExpr *Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@@ -1011,7 +1009,6 @@ public:
return T->getStmtClass() == CXXConstructExprClass ||
T->getStmtClass() == CXXTemporaryObjectExprClass;
}
- static bool classof(const CXXConstructExpr *) { return true; }
// Iterators
child_range children() {
@@ -1066,7 +1063,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXFunctionalCastExprClass;
}
- static bool classof(const CXXFunctionalCastExpr *) { return true; }
};
/// @brief Represents a C++ functional cast expression that builds a
@@ -1090,7 +1086,7 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
public:
CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
- Expr **Args,unsigned NumArgs,
+ ArrayRef<Expr *> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
bool ZeroInitialization = false);
@@ -1104,7 +1100,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTemporaryObjectExprClass;
}
- static bool classof(const CXXTemporaryObjectExpr *) { return true; }
friend class ASTStmtReader;
};
@@ -1281,8 +1276,11 @@ private:
/// \brief Retrieve the complete set of array-index variables.
VarDecl **getArrayIndexVars() const {
+ unsigned ArrayIndexSize =
+ llvm::RoundUpToAlignment(sizeof(unsigned) * (NumCaptures + 1),
+ llvm::alignOf<VarDecl*>());
return reinterpret_cast<VarDecl **>(
- getArrayIndexStarts() + NumCaptures + 1);
+ reinterpret_cast<char*>(getArrayIndexStarts()) + ArrayIndexSize);
}
public:
@@ -1394,7 +1392,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == LambdaExprClass;
}
- static bool classof(const LambdaExpr *) { return true; }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(IntroducerRange.getBegin(), ClosingBrace);
@@ -1442,7 +1439,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXScalarValueInitExprClass;
}
- static bool classof(const CXXScalarValueInitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1467,8 +1463,8 @@ class CXXNewExpr : public Expr {
/// the source range covering the parenthesized type-id.
SourceRange TypeIdParens;
- /// \brief Location of the first token.
- SourceLocation StartLoc;
+ /// \brief Range of the entire new expression.
+ SourceRange Range;
/// \brief Source-range of a paren-delimited initializer.
SourceRange DirectInitRange;
@@ -1498,11 +1494,11 @@ public:
CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
- Expr **placementArgs, unsigned numPlaceArgs,
+ ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle, Expr *initializer,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
- SourceLocation startLoc, SourceRange directInitRange);
+ SourceRange Range, SourceRange directInitRange);
explicit CXXNewExpr(EmptyShell Shell)
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
@@ -1580,7 +1576,7 @@ public:
}
/// \brief Returns the CXXConstructExpr from this new-expression, or NULL.
- const CXXConstructExpr* getConstructExpr() {
+ const CXXConstructExpr* getConstructExpr() const {
return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
}
@@ -1617,19 +1613,18 @@ public:
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
- SourceLocation getStartLoc() const { return StartLoc; }
- SourceLocation getEndLoc() const;
+ SourceLocation getStartLoc() const { return Range.getBegin(); }
+ SourceLocation getEndLoc() const { return Range.getEnd(); }
SourceRange getDirectInitRange() const { return DirectInitRange; }
SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getStartLoc(), getEndLoc());
+ return Range;
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNewExprClass;
}
- static bool classof(const CXXNewExpr *) { return true; }
// Iterators
child_range children() {
@@ -1700,7 +1695,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDeleteExprClass;
}
- static bool classof(const CXXDeleteExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Argument, &Argument+1); }
@@ -1889,7 +1883,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXPseudoDestructorExprClass;
}
- static bool classof(const CXXPseudoDestructorExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base + 1); }
@@ -1945,7 +1938,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryTypeTraitExprClass;
}
- static bool classof(const UnaryTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -2017,7 +2009,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == BinaryTypeTraitExprClass;
}
- static bool classof(const BinaryTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -2111,7 +2102,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == TypeTraitExprClass;
}
- static bool classof(const TypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -2186,7 +2176,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArrayTypeTraitExprClass;
}
- static bool classof(const ArrayTypeTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -2245,7 +2234,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExpressionTraitExprClass;
}
- static bool classof(const ExpressionTraitExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -2432,7 +2420,6 @@ public:
return T->getStmtClass() == UnresolvedLookupExprClass ||
T->getStmtClass() == UnresolvedMemberExprClass;
}
- static bool classof(const OverloadExpr *) { return true; }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -2454,10 +2441,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// call.
bool RequiresADL;
- /// True if namespace ::std should be considered an associated namespace
- /// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
- bool StdIsAssociatedNamespace;
-
/// True if these lookup results are overloaded. This is pretty
/// trivially rederivable if we urgently need to kill this field.
bool Overloaded;
@@ -2476,19 +2459,16 @@ class UnresolvedLookupExpr : public OverloadExpr {
const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs,
- UnresolvedSetIterator Begin, UnresolvedSetIterator End,
- bool StdIsAssociatedNamespace)
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End)
: OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc,
NameInfo, TemplateArgs, Begin, End, false, false, false),
RequiresADL(RequiresADL),
- StdIsAssociatedNamespace(StdIsAssociatedNamespace),
Overloaded(Overloaded), NamingClass(NamingClass)
{}
UnresolvedLookupExpr(EmptyShell Empty)
: OverloadExpr(UnresolvedLookupExprClass, Empty),
- RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
- NamingClass(0)
+ RequiresADL(false), Overloaded(false), NamingClass(0)
{}
friend class ASTStmtReader;
@@ -2500,14 +2480,10 @@ public:
const DeclarationNameInfo &NameInfo,
bool ADL, bool Overloaded,
UnresolvedSetIterator Begin,
- UnresolvedSetIterator End,
- bool StdIsAssociatedNamespace = false) {
- assert((ADL || !StdIsAssociatedNamespace) &&
- "std considered associated namespace when not performing ADL");
+ UnresolvedSetIterator End) {
return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
SourceLocation(), NameInfo,
- ADL, Overloaded, 0, Begin, End,
- StdIsAssociatedNamespace);
+ ADL, Overloaded, 0, Begin, End);
}
static UnresolvedLookupExpr *Create(ASTContext &C,
@@ -2528,10 +2504,6 @@ public:
/// argument-dependent lookup.
bool requiresADL() const { return RequiresADL; }
- /// True if namespace \::std should be artificially added to the set of
- /// associated namespaces for argument-dependent lookup purposes.
- bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
-
/// True if this lookup is overloaded.
bool isOverloaded() const { return Overloaded; }
@@ -2554,7 +2526,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnresolvedLookupExprClass;
}
- static bool classof(const UnresolvedLookupExpr *) { return true; }
};
/// \brief A qualified reference to a name whose declaration cannot
@@ -2705,7 +2676,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DependentScopeDeclRefExprClass;
}
- static bool classof(const DependentScopeDeclRefExpr *) { return true; }
child_range children() { return child_range(); }
@@ -2778,7 +2748,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ExprWithCleanupsClass;
}
- static bool classof(const ExprWithCleanups *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
@@ -2820,8 +2789,7 @@ class CXXUnresolvedConstructExpr : public Expr {
CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc);
CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs)
@@ -2833,8 +2801,7 @@ public:
static CXXUnresolvedConstructExpr *Create(ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc);
static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C,
@@ -2893,7 +2860,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
}
- static bool classof(const CXXUnresolvedConstructExpr *) { return true; }
// Iterators
child_range children() {
@@ -3142,7 +3108,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDependentScopeMemberExprClass;
}
- static bool classof(const CXXDependentScopeMemberExpr *) { return true; }
// Iterators
child_range children() {
@@ -3276,7 +3241,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnresolvedMemberExprClass;
}
- static bool classof(const UnresolvedMemberExpr *) { return true; }
// Iterators
child_range children() {
@@ -3320,7 +3284,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNoexceptExprClass;
}
- static bool classof(const CXXNoexceptExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Operand, &Operand + 1); }
@@ -3397,7 +3360,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == PackExpansionExprClass;
}
- static bool classof(const PackExpansionExpr *) { return true; }
// Iterators
child_range children() {
@@ -3503,7 +3465,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == SizeOfPackExprClass;
}
- static bool classof(const SizeOfPackExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -3548,9 +3509,6 @@ public:
static bool classof(const Stmt *s) {
return s->getStmtClass() == SubstNonTypeTemplateParmExprClass;
}
- static bool classof(const SubstNonTypeTemplateParmExpr *) {
- return true;
- }
// Iterators
child_range children() { return child_range(&Replacement, &Replacement+1); }
@@ -3561,7 +3519,7 @@ public:
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
-/// parameter lists, this node node is used to represent a non-type template
+/// parameter lists, this node is used to represent a non-type template
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
@@ -3608,14 +3566,77 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass;
}
- static bool classof(const SubstNonTypeTemplateParmPackExpr *) {
- return true;
- }
// Iterators
child_range children() { return child_range(); }
};
+/// \brief Represents a reference to a function parameter pack that has been
+/// substituted but not yet expanded.
+///
+/// When a pack expansion contains multiple parameter packs at different levels,
+/// this node is used to represent a function parameter pack at an outer level
+/// which we have already substituted to refer to expanded parameters, but where
+/// the containing pack expansion cannot yet be expanded.
+///
+/// \code
+/// template<typename...Ts> struct S {
+/// template<typename...Us> auto f(Ts ...ts) -> decltype(g(Us(ts)...));
+/// };
+/// template struct S<int, int>;
+/// \endcode
+class FunctionParmPackExpr : public Expr {
+ /// \brief The function parameter pack which was referenced.
+ ParmVarDecl *ParamPack;
+
+ /// \brief The location of the function parameter pack reference.
+ SourceLocation NameLoc;
+
+ /// \brief The number of expansions of this pack.
+ unsigned NumParameters;
+
+ FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
+ SourceLocation NameLoc, unsigned NumParams,
+ Decl * const *Params);
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+
+public:
+ static FunctionParmPackExpr *Create(ASTContext &Context, QualType T,
+ ParmVarDecl *ParamPack,
+ SourceLocation NameLoc,
+ llvm::ArrayRef<Decl*> Params);
+ static FunctionParmPackExpr *CreateEmpty(ASTContext &Context,
+ unsigned NumParams);
+
+ /// \brief Get the parameter pack which this expression refers to.
+ ParmVarDecl *getParameterPack() const { return ParamPack; }
+
+ /// \brief Get the location of the parameter pack.
+ SourceLocation getParameterPackLocation() const { return NameLoc; }
+
+ /// \brief Iterators over the parameters which the parameter pack expanded
+ /// into.
+ typedef ParmVarDecl * const *iterator;
+ iterator begin() const { return reinterpret_cast<iterator>(this+1); }
+ iterator end() const { return begin() + NumParameters; }
+
+ /// \brief Get the number of parameters in this parameter pack.
+ unsigned getNumExpansions() const { return NumParameters; }
+
+ /// \brief Get an expansion of the parameter pack by index.
+ ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == FunctionParmPackExprClass;
+ }
+
+ child_range children() { return child_range(); }
+};
+
/// \brief Represents a prvalue temporary that written into memory so that
/// a reference can bind to it.
///
@@ -3670,9 +3691,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == MaterializeTemporaryExprClass;
}
- static bool classof(const MaterializeTemporaryExpr *) {
- return true;
- }
// Iterators
child_range children() { return child_range(&Temporary, &Temporary + 1); }
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 93a5ada27915..27f5da0ce707 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -51,7 +51,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCStringLiteralClass;
}
- static bool classof(const ObjCStringLiteral *) { return true; }
// Iterators
child_range children() { return child_range(&String, &String+1); }
@@ -81,7 +80,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBoolLiteralExprClass;
}
- static bool classof(const ObjCBoolLiteralExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -121,7 +119,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBoxedExprClass;
}
- static bool classof(const ObjCBoxedExpr *) { return true; }
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
@@ -156,7 +153,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCArrayLiteralClass;
}
- static bool classof(const ObjCArrayLiteral *) { return true; }
/// \brief Retrieve elements of array of literals.
Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
@@ -319,7 +315,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCDictionaryLiteralClass;
}
- static bool classof(const ObjCDictionaryLiteral *) { return true; }
// Iterators
child_range children() {
@@ -372,7 +367,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCEncodeExprClass;
}
- static bool classof(const ObjCEncodeExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -409,7 +403,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSelectorExprClass;
}
- static bool classof(const ObjCSelectorExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -447,7 +440,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCProtocolExprClass;
}
- static bool classof(const ObjCProtocolExpr *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -501,7 +493,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIvarRefExprClass;
}
- static bool classof(const ObjCIvarRefExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@@ -715,7 +706,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCPropertyRefExprClass;
}
- static bool classof(const ObjCPropertyRefExpr *) { return true; }
// Iterators
child_range children() {
@@ -813,7 +803,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSubscriptRefExprClass;
}
- static bool classof(const ObjCSubscriptRefExpr *) { return true; }
Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); }
void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; }
@@ -1156,10 +1145,8 @@ public:
return getReceiverKind() == Class || getReceiverKind() == SuperClass;
}
- /// \brief Returns the receiver of an instance message.
- ///
- /// \brief Returns the object expression for an instance message, or
- /// NULL for a message that is not an instance message.
+ /// \brief Returns the object expression (receiver) for an instance message,
+ /// or null for a message that is not an instance message.
Expr *getInstanceReceiver() {
if (getReceiverKind() == Instance)
return static_cast<Expr *>(getReceiverPointer());
@@ -1208,6 +1195,17 @@ public:
return SourceLocation();
}
+ /// \brief Retrieve the receiver type to which this message is being directed.
+ ///
+ /// This routine cross-cuts all of the different kinds of message
+ /// sends to determine what the underlying (statically known) type
+ /// of the receiver will be; use \c getReceiverKind() to determine
+ /// whether the message is a class or an instance method, whether it
+ /// is a send to super or not, etc.
+ ///
+ /// \returns The type of the receiver.
+ QualType getReceiverType() const;
+
/// \brief Retrieve the Objective-C interface to which this message
/// is being directed, if known.
///
@@ -1344,7 +1342,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCMessageExprClass;
}
- static bool classof(const ObjCMessageExpr *) { return true; }
// Iterators
child_range children();
@@ -1409,7 +1406,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIsaExprClass;
}
- static bool classof(const ObjCIsaExpr *) { return true; }
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
@@ -1483,7 +1479,6 @@ public:
static bool classof(const Stmt *s) {
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
}
- static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; }
};
/// \brief An Objective-C "bridged" cast expression, which casts between
@@ -1532,8 +1527,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBridgedCastExprClass;
}
- static bool classof(const ObjCBridgedCastExpr *) { return true; }
-
};
} // end namespace clang
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 7aedfe2ef600..db2bddb4bfca 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -162,7 +162,7 @@ public:
}
/// \brief Get the decls that are contained in a file in the Offset/Length
- /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// range. \p Length can be 0 to indicate a point at \p Offset instead of
/// a range.
virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
SmallVectorImpl<Decl *> &Decls) {}
diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile
index f6dd4ce6e69a..7fb33f27741a 100644
--- a/include/clang/AST/Makefile
+++ b/include/clang/AST/Makefile
@@ -1,6 +1,8 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc CommentNodes.inc
+BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc \
+ CommentNodes.inc CommentHTMLTags.inc \
+ CommentHTMLTagsProperties.inc CommentCommandInfo.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -33,3 +35,18 @@ $(ObjDir)/CommentNodes.inc.tmp : $(TD_SRC_DIR)/CommentNodes.td $(CLANG_TBLGEN) \
$(Echo) "Building Clang comment node tables with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-nodes -o $(call SYSPATH, $@) $<
+$(ObjDir)/CommentHTMLTags.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td $(CLANG_TBLGEN) \
+ $(ObjDir)/.dir
+ $(Echo) "Building Clang comment HTML tag matchers with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-comment-html-tags -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/CommentHTMLTagsProperties.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang comment HTML tag properties with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-comment-html-tags-properties -o $(call SYSPATH, $@) $<
+
+$(ObjDir)/CommentCommandInfo.inc.tmp : $(PROJ_SRC_DIR)/CommentCommands.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang comment command info with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-comment-command-info -o $(call SYSPATH, $@) $<
+
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 51ae1daf14f3..f9fd1f906b55 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -83,7 +83,7 @@ public:
/// \brief The Objective-C NSArray selectors.
Selector getNSArraySelector(NSArrayMethodKind MK) const;
- /// \brief Return NSArrayMethodKind if \arg Sel is such a selector.
+ /// \brief Return NSArrayMethodKind if \p Sel is such a selector.
llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
/// \brief Enumerates the NSDictionary methods used to generate literals.
@@ -104,7 +104,7 @@ public:
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
- /// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector.
+ /// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.
llvm::Optional<NSDictionaryMethodKind>
getNSDictionaryMethodKind(Selector Sel);
@@ -169,7 +169,7 @@ public:
Sel == getNSNumberLiteralSelector(MK, true);
}
- /// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector.
+ /// \brief Return NSNumberLiteralMethodKind if \p Sel is such a selector.
llvm::Optional<NSNumberLiteralMethodKind>
getNSNumberLiteralMethodKind(Selector Sel) const;
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index a5aec1fdda6b..bf9e1cbc764b 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -97,8 +97,7 @@ private:
Specifier(Other.Specifier) {
}
- NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not
- // implement
+ void operator=(const NestedNameSpecifier &) LLVM_DELETED_FUNCTION;
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 63594141ac66..18169fd60c83 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -288,7 +288,11 @@ enum CastKind {
///
/// This particular cast kind is used for the conversion from a C++11
/// lambda expression to a block pointer.
- CK_CopyAndAutoreleaseBlockObject
+ CK_CopyAndAutoreleaseBlockObject,
+
+ // Convert a builtin function to a function pointer; only allowed in the
+ // callee of a call expression.
+ CK_BuiltinFnToFnPtr
};
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index f2c015fffe94..7babc1b24a13 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -39,6 +39,7 @@ struct PrintingPolicy {
SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool),
+ TerseOutput(false), SuppressAttributes(false),
DumpSourceManager(0) { }
/// \brief What language we're printing.
@@ -134,6 +135,17 @@ struct PrintingPolicy {
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
unsigned Bool : 1;
+ /// \brief Provide a 'terse' output.
+ ///
+ /// For example, in this mode we don't print function bodies, class members,
+ /// declarations inside namespaces etc. Effectively, this should print
+ /// only the requested declaration.
+ unsigned TerseOutput : 1;
+
+ /// \brief When true, do not print attributes attached to the declaration.
+ ///
+ unsigned SuppressAttributes : 1;
+
/// \brief If we are "dumping" rather than "pretty-printing", this points to
/// a SourceManager which will be used to dump SourceLocations. Dumping
/// involves printing the internal details of the AST and pretty-printing
diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h
index 630626b438ee..3a8b2183a557 100644
--- a/include/clang/AST/RawCommentList.h
+++ b/include/clang/AST/RawCommentList.h
@@ -18,6 +18,7 @@ namespace clang {
class ASTContext;
class ASTReader;
class Decl;
+class Preprocessor;
namespace comments {
class FullComment;
@@ -114,7 +115,8 @@ public:
}
/// Parse the comment, assuming it is attached to decl \c D.
- comments::FullComment *parse(const ASTContext &Context, const Decl *D) const;
+ comments::FullComment *parse(const ASTContext &Context,
+ const Preprocessor *PP, const Decl *D) const;
private:
SourceRange Range;
@@ -188,7 +190,7 @@ public:
private:
SourceManager &SourceMgr;
std::vector<RawComment *> Comments;
- RawComment LastComment;
+ SourceLocation PrevCommentEndLoc;
bool OnlyWhitespaceSeen;
void addCommentsToFront(const std::vector<RawComment *> &C) {
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index 3a870d057bad..36556469eaf8 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -136,8 +136,8 @@ private:
void Destroy(ASTContext &Ctx);
- ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
- void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
+ ASTRecordLayout(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
+ void operator=(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
public:
/// getAlignment - Get the record alignment in characters.
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 2e56a486f3d0..f96e06797855 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -721,6 +721,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type:
@@ -753,6 +754,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type: {
@@ -799,7 +801,7 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
- if (Init->isWritten())
+ if (Init->isWritten() || getDerived().shouldVisitImplicitCode())
TRY_TO(TraverseStmt(Init->getInit()));
return true;
}
@@ -1827,7 +1829,7 @@ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
return true; \
}
-DEF_TRAVERSE_STMT(AsmStmt, {
+DEF_TRAVERSE_STMT(GCCAsmStmt, {
TRY_TO(TraverseStmt(S->getAsmString()));
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
@@ -1836,7 +1838,7 @@ DEF_TRAVERSE_STMT(AsmStmt, {
TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- TRY_TO(TraverseStmt(S->getClobber(I)));
+ TRY_TO(TraverseStmt(S->getClobberStringLiteral(I)));
}
// children() iterates over inputExpr and outputExpr.
})
@@ -2141,7 +2143,9 @@ DEF_TRAVERSE_STMT(BlockExpr, {
return true; // no child statements to loop through.
})
DEF_TRAVERSE_STMT(ChooseExpr, { })
-DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
+DEF_TRAVERSE_STMT(CompoundLiteralExpr, {
+ TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
+})
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
@@ -2219,6 +2223,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { })
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
+DEF_TRAVERSE_STMT(FunctionParmPackExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
DEF_TRAVERSE_STMT(AtomicExpr, { })
diff --git a/include/clang/AST/SelectorLocationsKind.h b/include/clang/AST/SelectorLocationsKind.h
index cd43a5c49c55..6d903f820cd4 100644
--- a/include/clang/AST/SelectorLocationsKind.h
+++ b/include/clang/AST/SelectorLocationsKind.h
@@ -42,7 +42,7 @@ enum SelectorLocationsKind {
SelLoc_StandardWithSpace = 2
};
-/// \brief Returns true if all \arg SelLocs are in a "standard" location.
+/// \brief Returns true if all \p SelLocs are in a "standard" location.
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
ArrayRef<SourceLocation> SelLocs,
ArrayRef<Expr *> Args,
@@ -60,7 +60,7 @@ SourceLocation getStandardSelectorLoc(unsigned Index,
ArrayRef<Expr *> Args,
SourceLocation EndLoc);
-/// \brief Returns true if all \arg SelLocs are in a "standard" location.
+/// \brief Returns true if all \p SelLocs are in a "standard" location.
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
ArrayRef<SourceLocation> SelLocs,
ArrayRef<ParmVarDecl *> Args,
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 35fb69312b6e..a9bbb48f0368 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -392,9 +392,6 @@ public:
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
}
- // Implement isa<T> support.
- static bool classof(const Stmt *) { return true; }
-
/// 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
@@ -424,12 +421,12 @@ public:
/// \brief Produce a unique representation of the given statement.
///
- /// \brief ID once the profiling operation is complete, will contain
+ /// \param ID once the profiling operation is complete, will contain
/// the unique representation of the given statement.
///
- /// \brief Context the AST context in which the statement resides
+ /// \param Context the AST context in which the statement resides
///
- /// \brief Canonical whether the profile should be based on the canonical
+ /// \param Canonical whether the profile should be based on the canonical
/// representation of this statement (e.g., where non-type template
/// parameters are identified by index/level rather than their
/// declaration pointers) or the exact representation of the statement as
@@ -480,7 +477,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclStmtClass;
}
- static bool classof(const DeclStmt *) { return true; }
// Iterators over subexpressions.
child_range children() {
@@ -535,7 +531,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == NullStmtClass;
}
- static bool classof(const NullStmt *) { return true; }
child_range children() { return child_range(); }
@@ -615,7 +610,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundStmtClass;
}
- static bool classof(const CompoundStmt *) { return true; }
// Iterators
child_range children() {
@@ -654,7 +648,6 @@ public:
return T->getStmtClass() == CaseStmtClass ||
T->getStmtClass() == DefaultStmtClass;
}
- static bool classof(const SwitchCase *) { return true; }
};
class CaseStmt : public SwitchCase {
@@ -714,7 +707,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass;
}
- static bool classof(const CaseStmt *) { return true; }
// Iterators
child_range children() {
@@ -749,7 +741,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DefaultStmtClass;
}
- static bool classof(const DefaultStmt *) { return true; }
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
@@ -788,7 +779,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == LabelStmtClass;
}
- static bool classof(const LabelStmt *) { return true; }
};
@@ -837,7 +827,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == AttributedStmtClass;
}
- static bool classof(const AttributedStmt *) { return true; }
};
@@ -906,7 +895,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == IfStmtClass;
}
- static bool classof(const IfStmt *) { return true; }
};
/// SwitchStmt - This represents a 'switch' stmt.
@@ -1000,7 +988,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == SwitchStmtClass;
}
- static bool classof(const SwitchStmt *) { return true; }
};
@@ -1050,7 +1037,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == WhileStmtClass;
}
- static bool classof(const WhileStmt *) { return true; }
// Iterators
child_range children() {
@@ -1099,7 +1085,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == DoStmtClass;
}
- static bool classof(const DoStmt *) { return true; }
// Iterators
child_range children() {
@@ -1171,7 +1156,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ForStmtClass;
}
- static bool classof(const ForStmt *) { return true; }
// Iterators
child_range children() {
@@ -1206,7 +1190,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == GotoStmtClass;
}
- static bool classof(const GotoStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1251,7 +1234,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == IndirectGotoStmtClass;
}
- static bool classof(const IndirectGotoStmt *) { return true; }
// Iterators
child_range children() { return child_range(&Target, &Target+1); }
@@ -1278,7 +1260,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ContinueStmtClass;
}
- static bool classof(const ContinueStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1302,7 +1283,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == BreakStmtClass;
}
- static bool classof(const BreakStmt *) { return true; }
// Iterators
child_range children() { return child_range(); }
@@ -1354,7 +1334,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ReturnStmtClass;
}
- static bool classof(const ReturnStmt *) { return true; }
// Iterators
child_range children() {
@@ -1363,48 +1342,184 @@ public:
}
};
-/// AsmStmt - This represents a GNU inline-assembly statement extension.
+/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
///
class AsmStmt : public Stmt {
- SourceLocation AsmLoc, RParenLoc;
- StringLiteral *AsmStr;
-
+protected:
+ SourceLocation AsmLoc;
+ /// \brief True if the assembly statement does not have any input or output
+ /// operands.
bool IsSimple;
+
+ /// \brief If true, treat this inline assembly as having side effects.
+ /// This assembly statement should not be optimized, deleted or moved.
bool IsVolatile;
- bool MSAsm;
unsigned NumOutputs;
unsigned NumInputs;
unsigned NumClobbers;
- // FIXME: If we wanted to, we could allocate all of these in one big array.
IdentifierInfo **Names;
- StringLiteral **Constraints;
Stmt **Exprs;
- StringLiteral **Clobbers;
-public:
- AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
- bool msasm, unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints,
- Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, SourceLocation rparenloc);
+ AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile,
+ unsigned numoutputs, unsigned numinputs, unsigned numclobbers) :
+ Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile),
+ NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { }
+public:
/// \brief Build an empty inline-assembly statement.
- explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
- Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
+ explicit AsmStmt(StmtClass SC, EmptyShell Empty) :
+ Stmt(SC, Empty), Names(0), Exprs(0) { }
SourceLocation getAsmLoc() const { return AsmLoc; }
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
- SourceLocation getRParenLoc() const { return RParenLoc; }
- void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- bool isVolatile() const { return IsVolatile; }
- void setVolatile(bool V) { IsVolatile = V; }
bool isSimple() const { return IsSimple; }
void setSimple(bool V) { IsSimple = V; }
- bool isMSAsm() const { return MSAsm; }
- void setMSAsm(bool V) { MSAsm = V; }
+
+ bool isVolatile() const { return IsVolatile; }
+ void setVolatile(bool V) { IsVolatile = V; }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
+
+ //===--- Asm String Analysis ---===//
+
+ /// Assemble final IR asm string.
+ std::string generateAsmString(ASTContext &C) const;
+
+ //===--- Output operands ---===//
+
+ unsigned getNumOutputs() const { return NumOutputs; }
+
+ IdentifierInfo *getOutputIdentifier(unsigned i) const {
+ return Names[i];
+ }
+
+ StringRef getOutputName(unsigned i) const {
+ if (IdentifierInfo *II = getOutputIdentifier(i))
+ return II->getName();
+
+ return StringRef();
+ }
+
+ /// getOutputConstraint - Return the constraint string for the specified
+ /// output operand. All output constraints are known to be non-empty (either
+ /// '=' or '+').
+ StringRef getOutputConstraint(unsigned i) const;
+
+ /// isOutputPlusConstraint - Return true if the specified output constraint
+ /// is a "+" constraint (which is both an input and an output) or false if it
+ /// is an "=" constraint (just an output).
+ bool isOutputPlusConstraint(unsigned i) const {
+ return getOutputConstraint(i)[0] == '+';
+ }
+
+ const Expr *getOutputExpr(unsigned i) const;
+
+ /// getNumPlusOperands - Return the number of output operands that have a "+"
+ /// constraint.
+ unsigned getNumPlusOperands() const;
+
+ //===--- Input operands ---===//
+
+ unsigned getNumInputs() const { return NumInputs; }
+
+ IdentifierInfo *getInputIdentifier(unsigned i) const {
+ return Names[i + NumOutputs];
+ }
+
+ StringRef getInputName(unsigned i) const {
+ if (IdentifierInfo *II = getInputIdentifier(i))
+ return II->getName();
+
+ return StringRef();
+ }
+
+ /// getInputConstraint - Return the specified input constraint. Unlike output
+ /// constraints, these can be empty.
+ StringRef getInputConstraint(unsigned i) const;
+
+ const Expr *getInputExpr(unsigned i) const;
+
+ //===--- Other ---===//
+
+ unsigned getNumClobbers() const { return NumClobbers; }
+ StringRef getClobber(unsigned i) const;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == GCCAsmStmtClass ||
+ T->getStmtClass() == MSAsmStmtClass;
+ }
+
+ // Input expr iterators.
+
+ typedef ExprIterator inputs_iterator;
+ typedef ConstExprIterator const_inputs_iterator;
+
+ inputs_iterator begin_inputs() {
+ return &Exprs[0] + NumOutputs;
+ }
+
+ inputs_iterator end_inputs() {
+ return &Exprs[0] + NumOutputs + NumInputs;
+ }
+
+ const_inputs_iterator begin_inputs() const {
+ return &Exprs[0] + NumOutputs;
+ }
+
+ const_inputs_iterator end_inputs() const {
+ return &Exprs[0] + NumOutputs + NumInputs;
+ }
+
+ // Output expr iterators.
+
+ typedef ExprIterator outputs_iterator;
+ typedef ConstExprIterator const_outputs_iterator;
+
+ outputs_iterator begin_outputs() {
+ return &Exprs[0];
+ }
+ outputs_iterator end_outputs() {
+ return &Exprs[0] + NumOutputs;
+ }
+
+ const_outputs_iterator begin_outputs() const {
+ return &Exprs[0];
+ }
+ const_outputs_iterator end_outputs() const {
+ return &Exprs[0] + NumOutputs;
+ }
+
+ child_range children() {
+ return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
+ }
+};
+
+/// This represents a GCC inline-assembly statement extension.
+///
+class GCCAsmStmt : public AsmStmt {
+ SourceLocation RParenLoc;
+ StringLiteral *AsmStr;
+
+ // FIXME: If we wanted to, we could allocate all of these in one big array.
+ StringLiteral **Constraints;
+ StringLiteral **Clobbers;
+
+public:
+ 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);
+
+ /// \brief Build an empty inline-assembly statement.
+ explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty),
+ Constraints(0), Clobbers(0) { }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
//===--- Asm String Analysis ---===//
@@ -1461,25 +1576,11 @@ public:
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
ASTContext &C, unsigned &DiagOffs) const;
+ /// Assemble final IR asm string.
+ std::string generateAsmString(ASTContext &C) const;
//===--- Output operands ---===//
- unsigned getNumOutputs() const { return NumOutputs; }
-
- IdentifierInfo *getOutputIdentifier(unsigned i) const {
- return Names[i];
- }
-
- StringRef getOutputName(unsigned i) const {
- if (IdentifierInfo *II = getOutputIdentifier(i))
- return II->getName();
-
- return StringRef();
- }
-
- /// getOutputConstraint - Return the constraint string for the specified
- /// output operand. All output constraints are known to be non-empty (either
- /// '=' or '+').
StringRef getOutputConstraint(unsigned i) const;
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
@@ -1492,37 +1593,11 @@ public:
Expr *getOutputExpr(unsigned i);
const Expr *getOutputExpr(unsigned i) const {
- return const_cast<AsmStmt*>(this)->getOutputExpr(i);
+ return const_cast<GCCAsmStmt*>(this)->getOutputExpr(i);
}
- /// isOutputPlusConstraint - Return true if the specified output constraint
- /// is a "+" constraint (which is both an input and an output) or false if it
- /// is an "=" constraint (just an output).
- bool isOutputPlusConstraint(unsigned i) const {
- return getOutputConstraint(i)[0] == '+';
- }
-
- /// getNumPlusOperands - Return the number of output operands that have a "+"
- /// constraint.
- unsigned getNumPlusOperands() const;
-
//===--- Input operands ---===//
- unsigned getNumInputs() const { return NumInputs; }
-
- IdentifierInfo *getInputIdentifier(unsigned i) const {
- return Names[i + NumOutputs];
- }
-
- StringRef getInputName(unsigned i) const {
- if (IdentifierInfo *II = getInputIdentifier(i))
- return II->getName();
-
- return StringRef();
- }
-
- /// getInputConstraint - Return the specified input constraint. Unlike output
- /// constraints, these can be empty.
StringRef getInputConstraint(unsigned i) const;
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
@@ -1536,7 +1611,7 @@ public:
void setInputExpr(unsigned i, Expr *E);
const Expr *getInputExpr(unsigned i) const {
- return const_cast<AsmStmt*>(this)->getInputExpr(i);
+ return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
}
void setOutputsAndInputsAndClobbers(ASTContext &C,
@@ -1555,90 +1630,45 @@ public:
/// This returns -1 if the operand name is invalid.
int getNamedOperand(StringRef SymbolicName) const;
- unsigned getNumClobbers() const { return NumClobbers; }
- StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
- const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
+ StringRef getClobber(unsigned i) const;
+ StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; }
+ const StringLiteral *getClobberStringLiteral(unsigned i) const {
+ return Clobbers[i];
+ }
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AsmLoc, RParenLoc);
}
- static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;}
- static bool classof(const AsmStmt *) { return true; }
-
- // Input expr iterators.
-
- typedef ExprIterator inputs_iterator;
- typedef ConstExprIterator const_inputs_iterator;
-
- inputs_iterator begin_inputs() {
- return &Exprs[0] + NumOutputs;
- }
-
- inputs_iterator end_inputs() {
- return &Exprs[0] + NumOutputs + NumInputs;
- }
-
- const_inputs_iterator begin_inputs() const {
- return &Exprs[0] + NumOutputs;
- }
-
- const_inputs_iterator end_inputs() const {
- return &Exprs[0] + NumOutputs + NumInputs;
- }
-
- // Output expr iterators.
-
- typedef ExprIterator outputs_iterator;
- typedef ConstExprIterator const_outputs_iterator;
-
- outputs_iterator begin_outputs() {
- return &Exprs[0];
- }
- outputs_iterator end_outputs() {
- return &Exprs[0] + NumOutputs;
- }
-
- const_outputs_iterator begin_outputs() const {
- return &Exprs[0];
- }
- const_outputs_iterator end_outputs() const {
- return &Exprs[0] + NumOutputs;
- }
-
- child_range children() {
- return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == GCCAsmStmtClass;
}
};
-/// MSAsmStmt - This represents a MS inline-assembly statement extension.
+/// This represents a Microsoft inline-assembly statement extension.
///
-class MSAsmStmt : public Stmt {
+class MSAsmStmt : public AsmStmt {
SourceLocation AsmLoc, LBraceLoc, EndLoc;
std::string AsmStr;
- bool IsSimple;
- bool IsVolatile;
-
unsigned NumAsmToks;
- unsigned NumInputs;
- unsigned NumOutputs;
- unsigned NumClobbers;
Token *AsmToks;
- IdentifierInfo **Names;
- Stmt **Exprs;
+ StringRef *Constraints;
StringRef *Clobbers;
public:
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
- ArrayRef<IdentifierInfo*> inputs, ArrayRef<IdentifierInfo*> outputs,
- StringRef asmstr, ArrayRef<StringRef> clobbers,
- SourceLocation endloc);
+ unsigned numoutputs, unsigned numinputs,
+ ArrayRef<IdentifierInfo*> names, ArrayRef<StringRef> constraints,
+ ArrayRef<Expr*> exprs, StringRef asmstr,
+ ArrayRef<StringRef> clobbers, SourceLocation endloc);
+
+ /// \brief Build an empty MS-style inline-assembly statement.
+ explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty),
+ NumAsmToks(0), AsmToks(0), Constraints(0), Clobbers(0) { }
- SourceLocation getAsmLoc() const { return AsmLoc; }
- void setAsmLoc(SourceLocation L) { AsmLoc = L; }
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation L) { LBraceLoc = L; }
SourceLocation getEndLoc() const { return EndLoc; }
@@ -1649,20 +1679,42 @@ public:
unsigned getNumAsmToks() { return NumAsmToks; }
Token *getAsmToks() { return AsmToks; }
- bool isVolatile() const { return IsVolatile; }
- void setVolatile(bool V) { IsVolatile = V; }
- bool isSimple() const { return IsSimple; }
- void setSimple(bool V) { IsSimple = V; }
-
//===--- Asm String Analysis ---===//
const std::string *getAsmString() const { return &AsmStr; }
std::string *getAsmString() { return &AsmStr; }
void setAsmString(StringRef &E) { AsmStr = E.str(); }
+ /// Assemble final IR asm string.
+ std::string generateAsmString(ASTContext &C) const;
+
+ //===--- Output operands ---===//
+
+ StringRef getOutputConstraint(unsigned i) const {
+ return Constraints[i];
+ }
+
+ Expr *getOutputExpr(unsigned i);
+
+ const Expr *getOutputExpr(unsigned i) const {
+ return const_cast<MSAsmStmt*>(this)->getOutputExpr(i);
+ }
+
+ //===--- Input operands ---===//
+
+ StringRef getInputConstraint(unsigned i) const {
+ return Constraints[i + NumOutputs];
+ }
+
+ Expr *getInputExpr(unsigned i);
+ void setInputExpr(unsigned i, Expr *E);
+
+ const Expr *getInputExpr(unsigned i) const {
+ return const_cast<MSAsmStmt*>(this)->getInputExpr(i);
+ }
+
//===--- Other ---===//
- unsigned getNumClobbers() const { return NumClobbers; }
StringRef getClobber(unsigned i) const { return Clobbers[i]; }
SourceRange getSourceRange() const LLVM_READONLY {
@@ -1671,7 +1723,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == MSAsmStmtClass;
}
- static bool classof(const MSAsmStmt *) { return true; }
child_range children() {
return child_range(&Exprs[0], &Exprs[0]);
@@ -1720,8 +1771,6 @@ public:
return T->getStmtClass() == SEHExceptStmtClass;
}
- static bool classof(SEHExceptStmt *) { return true; }
-
};
class SEHFinallyStmt : public Stmt {
@@ -1757,8 +1806,6 @@ public:
return T->getStmtClass() == SEHFinallyStmtClass;
}
- static bool classof(SEHFinallyStmt *) { return true; }
-
};
class SEHTryStmt : public Stmt {
@@ -1810,8 +1857,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == SEHTryStmtClass;
}
-
- static bool classof(SEHTryStmt *) { return true; }
};
} // end namespace clang
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index a948722cc1d5..f4e4dcdd4a5e 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -50,7 +50,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXCatchStmtClass;
}
- static bool classof(const CXXCatchStmt *) { return true; }
child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); }
@@ -111,7 +110,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTryStmtClass;
}
- static bool classof(const CXXTryStmt *) { return true; }
child_range children() {
return child_range(getStmts(), getStmts() + getNumHandlers() + 1);
@@ -196,7 +194,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXForRangeStmtClass;
}
- static bool classof(const CXXForRangeStmt *) { return true; }
// Iterators
child_range children() {
@@ -286,8 +283,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == MSDependentExistsStmtClass;
}
-
- static bool classof(MSDependentExistsStmt *) { return true; }
};
} // end namespace clang
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index e7e1232989e3..d7a73a70bd54 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -61,7 +61,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCForCollectionStmtClass;
}
- static bool classof(const ObjCForCollectionStmt *) { return true; }
// Iterators
child_range children() {
@@ -112,7 +111,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtCatchStmtClass;
}
- static bool classof(const ObjCAtCatchStmt *) { return true; }
child_range children() { return child_range(&Body, &Body + 1); }
};
@@ -143,7 +141,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtFinallyStmtClass;
}
- static bool classof(const ObjCAtFinallyStmt *) { return true; }
child_range children() {
return child_range(&AtFinallyStmt, &AtFinallyStmt+1);
@@ -244,7 +241,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;
}
- static bool classof(const ObjCAtTryStmt *) { return true; }
child_range children() {
return child_range(getStmts(),
@@ -303,7 +299,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
}
- static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
child_range children() {
return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR);
@@ -339,7 +334,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtThrowStmtClass;
}
- static bool classof(const ObjCAtThrowStmt *) { return true; }
child_range children() { return child_range(&Throw, &Throw+1); }
};
@@ -371,7 +365,6 @@ public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
}
- static bool classof(const ObjCAutoreleasePoolStmt *) { return true; }
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
};
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 5047028e5eac..1c0abde5b761 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -28,11 +28,11 @@ namespace llvm {
namespace clang {
-class Decl;
class DiagnosticBuilder;
class Expr;
struct PrintingPolicy;
class TypeSourceInfo;
+class ValueDecl;
/// \brief Represents a template argument within a class template
/// specialization.
@@ -43,12 +43,14 @@ public:
/// \brief Represents an empty template argument, e.g., one that has not
/// been deduced.
Null = 0,
- /// The template argument is a type. Its value is stored in the
- /// TypeOrValue field.
+ /// The template argument is a type.
Type,
- /// The template argument is a declaration that was provided for a pointer
- /// or reference non-type template parameter.
+ /// The template argument is a declaration that was provided for a pointer,
+ /// reference, or pointer to member non-type template parameter.
Declaration,
+ /// The template argument is a null pointer or null pointer to member that
+ /// was provided for a non-type template parameter.
+ NullPtr,
/// The template argument is an integral value stored in an llvm::APSInt
/// that was provided for an integral non-type template parameter.
Integral,
@@ -73,6 +75,10 @@ private:
union {
uintptr_t TypeOrValue;
struct {
+ ValueDecl *D;
+ bool ForRefParam;
+ } DeclArg;
+ struct {
// We store a decomposed APSInt with the data allocated by ASTContext if
// BitWidth > 64. The memory may be shared between multiple
// TemplateArgument instances.
@@ -101,15 +107,18 @@ public:
TemplateArgument() : Kind(Null), TypeOrValue(0) { }
/// \brief Construct a template type argument.
- TemplateArgument(QualType T) : Kind(Type) {
+ TemplateArgument(QualType T, bool isNullPtr = false)
+ : Kind(isNullPtr ? NullPtr : Type) {
TypeOrValue = 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(Decl *D) : Kind(Declaration) {
- TypeOrValue = reinterpret_cast<uintptr_t>(D);
+ TemplateArgument(ValueDecl *D, bool ForRefParam) : Kind(Declaration) {
+ assert(D && "Expected decl");
+ DeclArg.D = D;
+ DeclArg.ForRefParam = ForRefParam;
}
/// \brief Construct an integral constant template argument. The memory to
@@ -177,6 +186,10 @@ public:
this->Args.NumArgs = NumArgs;
}
+ static TemplateArgument getEmptyPack() {
+ return TemplateArgument((TemplateArgument*)0, 0);
+ }
+
/// \brief Create a new template argument pack by copying the given set of
/// template arguments.
static TemplateArgument CreatePackCopy(ASTContext &Context,
@@ -205,34 +218,43 @@ public:
/// \brief Determine whether this template argument is a pack expansion.
bool isPackExpansion() const;
- /// \brief Retrieve the template argument as a type.
+ /// \brief Retrieve the type for a type template argument.
QualType getAsType() const {
- if (Kind != Type)
- return QualType();
-
+ assert(Kind == Type && "Unexpected kind");
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
}
- /// \brief Retrieve the template argument as a declaration.
- Decl *getAsDecl() const {
- if (Kind != Declaration)
- return 0;
- return reinterpret_cast<Decl *>(TypeOrValue);
+ /// \brief Retrieve the declaration for a declaration non-type
+ /// template argument.
+ ValueDecl *getAsDecl() const {
+ assert(Kind == 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");
+ return DeclArg.ForRefParam;
}
- /// \brief Retrieve the template argument as a template name.
+ /// \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));
+ }
+
+ /// \brief Retrieve the template name for a template name argument.
TemplateName getAsTemplate() const {
- if (Kind != Template)
- return TemplateName();
-
+ assert(Kind == 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 {
- if (Kind != Template && Kind != TemplateExpansion)
- return TemplateName();
+ assert((Kind == Template || Kind == TemplateExpansion) &&
+ "Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name);
}
@@ -244,6 +266,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");
using namespace llvm;
if (Integer.BitWidth <= 64)
return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
@@ -255,23 +278,18 @@ public:
/// \brief Retrieve the type of the integral value.
QualType getIntegralType() const {
- if (Kind != Integral)
- return QualType();
-
+ assert(Kind == Integral && "Unexpected kind");
return QualType::getFromOpaquePtr(Integer.Type);
}
void setIntegralType(QualType T) {
- assert(Kind == Integral &&
- "Cannot set the integral type of a non-integral template argument");
+ assert(Kind == Integral && "Unexpected kind");
Integer.Type = T.getAsOpaquePtr();
}
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
- if (Kind != Expression)
- return 0;
-
+ assert(Kind == Expression && "Unexpected kind");
return reinterpret_cast<Expr *>(TypeOrValue);
}
@@ -436,7 +454,17 @@ public:
assert(Argument.getKind() == TemplateArgument::Declaration);
return LocInfo.getAsExpr();
}
-
+
+ Expr *getSourceNullPtrExpression() const {
+ assert(Argument.getKind() == TemplateArgument::NullPtr);
+ return LocInfo.getAsExpr();
+ }
+
+ Expr *getSourceIntegralExpression() const {
+ assert(Argument.getKind() == TemplateArgument::Integral);
+ return LocInfo.getAsExpr();
+ }
+
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
assert(Argument.getKind() == TemplateArgument::Template ||
Argument.getKind() == TemplateArgument::TemplateExpansion);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 6564b66548a4..6900a7d40af9 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -20,6 +20,7 @@
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/Visibility.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/type_traits.h"
@@ -160,6 +161,44 @@ public:
Qualifiers() : Mask(0) {}
+ /// \brief Returns the common set of qualifiers while removing them from
+ /// the given sets.
+ static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
+ // If both are only CVR-qualified, bit operations are sufficient.
+ if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
+ Qualifiers Q;
+ Q.Mask = L.Mask & R.Mask;
+ L.Mask &= ~Q.Mask;
+ R.Mask &= ~Q.Mask;
+ return Q;
+ }
+
+ Qualifiers Q;
+ unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
+ Q.addCVRQualifiers(CommonCRV);
+ L.removeCVRQualifiers(CommonCRV);
+ R.removeCVRQualifiers(CommonCRV);
+
+ if (L.getObjCGCAttr() == R.getObjCGCAttr()) {
+ Q.setObjCGCAttr(L.getObjCGCAttr());
+ L.removeObjCGCAttr();
+ R.removeObjCGCAttr();
+ }
+
+ if (L.getObjCLifetime() == R.getObjCLifetime()) {
+ Q.setObjCLifetime(L.getObjCLifetime());
+ L.removeObjCLifetime();
+ R.removeObjCLifetime();
+ }
+
+ if (L.getAddressSpace() == R.getAddressSpace()) {
+ Q.setAddressSpace(L.getAddressSpace());
+ L.removeAddressSpace();
+ R.removeAddressSpace();
+ }
+ return Q;
+ }
+
static Qualifiers fromFastMask(unsigned Mask) {
Qualifiers Qs;
Qs.addFastQualifiers(Mask);
@@ -333,6 +372,23 @@ public:
}
}
+ /// \brief Remove the qualifiers from the given set from this set.
+ void removeQualifiers(Qualifiers Q) {
+ // If the other set doesn't have any non-boolean qualifiers, just
+ // bit-and the inverse in.
+ if (!(Q.Mask & ~CVRMask))
+ Mask &= ~Q.Mask;
+ else {
+ Mask &= ~(Q.Mask & CVRMask);
+ if (getObjCGCAttr() == Q.getObjCGCAttr())
+ removeObjCGCAttr();
+ if (getObjCLifetime() == Q.getObjCLifetime())
+ removeObjCLifetime();
+ if (getAddressSpace() == Q.getAddressSpace())
+ removeAddressSpace();
+ }
+ }
+
/// \brief Add the qualifiers from the given set to this set, given that
/// they don't conflict.
void addConsistentQualifiers(Qualifiers qs) {
@@ -400,7 +456,7 @@ public:
}
Qualifiers &operator-=(Qualifiers R) {
- Mask = Mask & ~(R.Mask);
+ removeQualifiers(R);
return *this;
}
@@ -435,18 +491,6 @@ private:
static const uint32_t AddressSpaceShift = 8;
};
-/// 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_AAPCS, // __attribute__((pcs("aapcs")))
- CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
-};
-
/// A std::pair-like structure for storing a qualified type split
/// into its local qualifiers and its locally-unqualified type.
struct SplitQualType {
@@ -1126,8 +1170,8 @@ public:
};
private:
- Type(const Type&); // DO NOT IMPLEMENT.
- void operator=(const Type&); // DO NOT IMPLEMENT.
+ Type(const Type &) LLVM_DELETED_FUNCTION;
+ void operator=(const Type &) LLVM_DELETED_FUNCTION;
/// Bitfields required by the Type class.
class TypeBitfields {
@@ -1225,7 +1269,7 @@ protected:
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
- unsigned ExtInfo : 8;
+ unsigned ExtInfo : 9;
/// TypeQuals - Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
@@ -1512,6 +1556,7 @@ public:
bool isRecordType() const;
bool isClassType() const;
bool isStructureType() const;
+ bool isInterfaceType() const;
bool isStructureOrClassType() const;
bool isUnionType() const;
bool isComplexIntegerType() const; // GCC _Complex integer type.
@@ -1630,13 +1675,19 @@ public:
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
- const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
/// \brief Retrieves the CXXRecordDecl that this type refers to, either
/// because the type is a RecordType or because it is the injected-class-name
/// type of a class template or class template partial specialization.
CXXRecordDecl *getAsCXXRecordDecl() const;
+ /// If this is a pointer or reference to a RecordType, return the
+ /// CXXRecordDecl that that type refers to.
+ ///
+ /// If this is not a pointer or reference, or the type being pointed to does
+ /// not refer to a CXXRecordDecl, returns NULL.
+ const CXXRecordDecl *getPointeeCXXRecordDecl() const;
+
/// \brief Get the AutoType whose type will be deduced for a variable with
/// an initializer of this type. This looks through declarators like pointer
/// types, but not through decltype or typedefs.
@@ -1738,8 +1789,6 @@ public:
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
LLVM_ATTRIBUTE_USED void dump() const;
- static bool classof(const Type *) { return true; }
-
friend class ASTReader;
friend class ASTWriter;
};
@@ -1748,6 +1797,11 @@ public:
/// until it reaches a TypedefType or a non-sugared type.
template <> const TypedefType *Type::getAs() const;
+/// \brief This will check for a TemplateSpecializationType by removing any
+/// existing sugar until it reaches a TemplateSpecializationType or a
+/// non-sugared type.
+template <> const TemplateSpecializationType *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)
@@ -1834,7 +1888,6 @@ public:
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
- static bool classof(const BuiltinType *) { return true; }
};
/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex
@@ -1865,7 +1918,6 @@ public:
}
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
- static bool classof(const ComplexType *) { return true; }
};
/// ParenType - Sugar for parentheses used when specifying types.
@@ -1897,7 +1949,6 @@ public:
}
static bool classof(const Type *T) { return T->getTypeClass() == Paren; }
- static bool classof(const ParenType *) { return true; }
};
/// PointerType - C99 6.7.5.1 - Pointer Declarators.
@@ -1929,7 +1980,6 @@ public:
}
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
- static bool classof(const PointerType *) { return true; }
};
/// BlockPointerType - pointer to a block type.
@@ -1965,7 +2015,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == BlockPointer;
}
- static bool classof(const BlockPointerType *) { return true; }
};
/// ReferenceType - Base for LValueReferenceType and RValueReferenceType
@@ -2013,7 +2062,6 @@ public:
return T->getTypeClass() == LValueReference ||
T->getTypeClass() == RValueReference;
}
- static bool classof(const ReferenceType *) { return true; }
};
/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference
@@ -2031,7 +2079,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == LValueReference;
}
- static bool classof(const LValueReferenceType *) { return true; }
};
/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference
@@ -2048,7 +2095,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == RValueReference;
}
- static bool classof(const RValueReferenceType *) { return true; }
};
/// MemberPointerType - C++ 8.3.3 - Pointers to members
@@ -2103,7 +2149,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == MemberPointer;
}
- static bool classof(const MemberPointerType *) { return true; }
};
/// ArrayType - C99 6.7.5.2 - Array Declarators.
@@ -2159,7 +2204,6 @@ public:
T->getTypeClass() == IncompleteArray ||
T->getTypeClass() == DependentSizedArray;
}
- static bool classof(const ArrayType *) { return true; }
};
/// ConstantArrayType - This class represents the canonical version of
@@ -2211,7 +2255,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
}
- static bool classof(const ConstantArrayType *) { return true; }
};
/// IncompleteArrayType - This class represents C arrays with an unspecified
@@ -2231,7 +2274,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == IncompleteArray;
}
- static bool classof(const IncompleteArrayType *) { return true; }
friend class StmtIteratorBase;
@@ -2294,7 +2336,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == VariableArray;
}
- static bool classof(const VariableArrayType *) { return true; }
friend class StmtIteratorBase;
@@ -2351,7 +2392,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == DependentSizedArray;
}
- static bool classof(const DependentSizedArrayType *) { return true; }
friend class StmtIteratorBase;
@@ -2397,7 +2437,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == DependentSizedExtVector;
}
- static bool classof(const DependentSizedExtVectorType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Context, getElementType(), getSizeExpr());
@@ -2463,7 +2502,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
}
- static bool classof(const VectorType *) { return true; }
};
/// ExtVectorType - Extended vector type. This type is created using
@@ -2529,7 +2567,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == ExtVector;
}
- static bool classof(const ExtVectorType *) { return true; }
};
/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
@@ -2561,19 +2598,19 @@ class FunctionType : public Type {
// * AST read and write
// * Codegen
class ExtInfo {
- // Feel free to rearrange or add bits, but if you go over 8,
+ // Feel free to rearrange or add bits, but if you go over 9,
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
// | CC |noreturn|produces|regparm|
- // |0 .. 2| 3 | 4 | 5 .. 7|
+ // |0 .. 3| 4 | 5 | 6 .. 8|
//
// regparm is either 0 (no regparm attribute) or the regparm value+1.
- enum { CallConvMask = 0x7 };
- enum { NoReturnMask = 0x8 };
- enum { ProducesResultMask = 0x10 };
+ enum { CallConvMask = 0xF };
+ enum { NoReturnMask = 0x10 };
+ enum { ProducesResultMask = 0x20 };
enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
- RegParmOffset = 5 }; // Assumed to be the last field
+ RegParmOffset = 6 }; // Assumed to be the last field
uint16_t Bits;
@@ -2692,7 +2729,6 @@ public:
return T->getTypeClass() == FunctionNoProto ||
T->getTypeClass() == FunctionProto;
}
- static bool classof(const FunctionType *) { return true; }
};
/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has
@@ -2724,7 +2760,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto;
}
- static bool classof(const FunctionNoProtoType *) { return true; }
};
/// FunctionProtoType - Represents a prototype with argument type info, e.g.
@@ -2972,14 +3007,13 @@ public:
// FIXME: Remove the string version.
void printExceptionSpecification(std::string &S,
- PrintingPolicy Policy) const;
+ const PrintingPolicy &Policy) const;
void printExceptionSpecification(raw_ostream &OS,
- PrintingPolicy Policy) const;
+ const PrintingPolicy &Policy) const;
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
}
- static bool classof(const FunctionProtoType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
@@ -3010,7 +3044,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == UnresolvedUsing;
}
- static bool classof(const UnresolvedUsingType *) { return true; }
void Profile(llvm::FoldingSetNodeID &ID) {
return Profile(ID, Decl);
@@ -3042,7 +3075,6 @@ public:
QualType desugar() const;
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
- static bool classof(const TypedefType *) { return true; }
};
/// TypeOfExprType (GCC extension).
@@ -3062,7 +3094,6 @@ public:
bool isSugared() const;
static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
- static bool classof(const TypeOfExprType *) { return true; }
};
/// \brief Internal representation of canonical, dependent
@@ -3109,7 +3140,6 @@ public:
bool isSugared() const { return true; }
static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
- static bool classof(const TypeOfType *) { return true; }
};
/// DecltypeType (C++0x)
@@ -3131,7 +3161,6 @@ public:
bool isSugared() const;
static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
- static bool classof(const DecltypeType *) { return true; }
};
/// \brief Internal representation of canonical, dependent
@@ -3184,7 +3213,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == UnaryTransform;
}
- static bool classof(const UnaryTransformType *) { return true; }
};
class TagType : public Type {
@@ -3207,7 +3235,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
- static bool classof(const TagType *) { return true; }
};
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
@@ -3234,7 +3261,6 @@ public:
QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) { return T->getTypeClass() == Record; }
- static bool classof(const RecordType *) { return true; }
};
/// EnumType - This is a helper class that allows the use of isa/cast/dyncast
@@ -3253,7 +3279,6 @@ public:
QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
- static bool classof(const EnumType *) { return true; }
};
/// AttributedType - An attributed type is a type to which a type
@@ -3297,7 +3322,8 @@ public:
attr_fastcall,
attr_stdcall,
attr_thiscall,
- attr_pascal
+ attr_pascal,
+ attr_pnaclcall
};
private:
@@ -3341,7 +3367,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == Attributed;
}
- static bool classof(const AttributedType *T) { return true; }
};
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
@@ -3415,7 +3440,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == TemplateTypeParm;
}
- static bool classof(const TemplateTypeParmType *T) { return true; }
};
/// \brief Represents the result of substituting a type for a template
@@ -3466,7 +3490,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParm;
}
- static bool classof(const SubstTemplateTypeParmType *T) { return true; }
};
/// \brief Represents the result of substituting a set of types for a template
@@ -3519,7 +3542,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParmPack;
}
- static bool classof(const SubstTemplateTypeParmPackType *T) { return true; }
};
/// \brief Represents a C++0x auto type.
@@ -3562,7 +3584,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == Auto;
}
- static bool classof(const AutoType *T) { return true; }
};
/// \brief Represents a type template specialization; the template
@@ -3726,7 +3747,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == TemplateSpecialization;
}
- static bool classof(const TemplateSpecializationType *T) { return true; }
};
/// \brief The injected class name of a C++ class template or class
@@ -3789,13 +3809,14 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == InjectedClassName;
}
- static bool classof(const InjectedClassNameType *T) { return true; }
};
/// \brief The kind of a tag type.
enum TagTypeKind {
/// \brief The "struct" keyword.
TTK_Struct,
+ /// \brief The "__interface" keyword.
+ TTK_Interface,
/// \brief The "union" keyword.
TTK_Union,
/// \brief The "class" keyword.
@@ -3809,6 +3830,8 @@ enum TagTypeKind {
enum ElaboratedTypeKeyword {
/// \brief The "struct" keyword introduces the elaborated-type-specifier.
ETK_Struct,
+ /// \brief The "__interface" keyword introduces the elaborated-type-specifier.
+ ETK_Interface,
/// \brief The "union" keyword introduces the elaborated-type-specifier.
ETK_Union,
/// \brief The "class" keyword introduces the elaborated-type-specifier.
@@ -3932,7 +3955,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == Elaborated;
}
- static bool classof(const ElaboratedType *T) { return true; }
};
/// \brief Represents a qualified type name for which the type name is
@@ -3996,7 +4018,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == DependentName;
}
- static bool classof(const DependentNameType *T) { return true; }
};
/// DependentTemplateSpecializationType - Represents a template
@@ -4067,9 +4088,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == DependentTemplateSpecialization;
}
- static bool classof(const DependentTemplateSpecializationType *T) {
- return true;
- }
};
/// \brief Represents a pack expansion of types.
@@ -4150,9 +4168,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == PackExpansion;
}
- static bool classof(const PackExpansionType *T) {
- return true;
- }
};
/// ObjCObjectType - Represents a class type in Objective C.
@@ -4263,7 +4278,6 @@ public:
return T->getTypeClass() == ObjCObject ||
T->getTypeClass() == ObjCInterface;
}
- static bool classof(const ObjCObjectType *) { return true; }
};
/// ObjCObjectTypeImpl - A class providing a concrete implementation
@@ -4327,7 +4341,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCInterface;
}
- static bool classof(const ObjCInterfaceType *) { return true; }
// Nonsense to "hide" certain members of ObjCObjectType within this
// class. People asking for protocols on an ObjCInterfaceType are
@@ -4477,7 +4490,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCObjectPointer;
}
- static bool classof(const ObjCObjectPointerType *) { return true; }
};
class AtomicType : public Type, public llvm::FoldingSetNode {
@@ -4508,7 +4520,6 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == Atomic;
}
- static bool classof(const AtomicType *) { return true; }
};
/// A qualifier set is used to build a set of qualifiers.
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 11a878d6b0f3..8a04bd8d5ee0 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -159,8 +159,6 @@ public:
return !(LHS == RHS);
}
- static bool classof(const TypeLoc *TL) { return true; }
-
private:
static void initializeImpl(ASTContext &Context, TypeLoc TL,
SourceLocation Loc);
@@ -192,7 +190,6 @@ public:
static bool classof(const TypeLoc *TL) {
return !TL->getType().hasLocalQualifiers();
}
- static bool classof(const UnqualTypeLoc *TL) { return true; }
};
/// \brief Wrapper of type source information for a type with
@@ -237,7 +234,6 @@ public:
static bool classof(const TypeLoc *TL) {
return TL->getType().hasLocalQualifiers();
}
- static bool classof(const QualifiedTypeLoc *TL) { return true; }
};
inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
@@ -250,11 +246,11 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
/// to a particular Type subclass. It is accepted for a single
/// TypeLoc class to correspond to multiple Type classes.
///
-/// \param Base a class from which to derive
-/// \param Derived the class deriving from this one
-/// \param TypeClass the concrete Type subclass associated with this
+/// \tparam Base a class from which to derive
+/// \tparam Derived the class deriving from this one
+/// \tparam TypeClass the concrete Type subclass associated with this
/// location type
-/// \param LocalData the structure type of local location data for
+/// \tparam LocalData the structure type of local location data for
/// this type
///
/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or
@@ -303,9 +299,6 @@ public:
static bool classof(const UnqualTypeLoc *TL) {
return Derived::classofType(TL->getTypePtr());
}
- static bool classof(const Derived *TL) {
- return true;
- }
TypeLoc getNextTypeLoc() const {
return getNextTypeLoc(asDerived()->getInnerType());
@@ -380,9 +373,6 @@ public:
static bool classof(const UnqualTypeLoc *TL) {
return Derived::classofType(TL->getTypePtr());
}
- static bool classof(const Derived *TL) {
- return true;
- }
const TypeClass *getTypePtr() const {
return cast<TypeClass>(Base::getTypePtr());
@@ -417,7 +407,6 @@ public:
}
static bool classof(const TypeLoc *TL);
- static bool classof(const TypeSpecTypeLoc *TL) { return true; }
};
@@ -866,6 +855,7 @@ public:
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setNameLoc(Loc);
+ setNameEndLoc(Loc);
}
};
@@ -1060,6 +1050,8 @@ public:
struct FunctionLocInfo {
SourceLocation LocalRangeBegin;
+ SourceLocation LParenLoc;
+ SourceLocation RParenLoc;
SourceLocation LocalRangeEnd;
};
@@ -1083,6 +1075,24 @@ public:
getLocalData()->LocalRangeEnd = L;
}
+ SourceLocation getLParenLoc() const {
+ return this->getLocalData()->LParenLoc;
+ }
+ void setLParenLoc(SourceLocation Loc) {
+ this->getLocalData()->LParenLoc = Loc;
+ }
+
+ SourceLocation getRParenLoc() const {
+ return this->getLocalData()->RParenLoc;
+ }
+ void setRParenLoc(SourceLocation Loc) {
+ this->getLocalData()->RParenLoc = Loc;
+ }
+
+ SourceRange getParensRange() const {
+ return SourceRange(getLParenLoc(), getRParenLoc());
+ }
+
ArrayRef<ParmVarDecl *> getParams() const {
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
}
@@ -1110,6 +1120,8 @@ public:
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setLocalRangeBegin(Loc);
+ setLParenLoc(Loc);
+ setRParenLoc(Loc);
setLocalRangeEnd(Loc);
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
setArg(i, NULL);
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 0918dc44aa73..9f11ee5fe3e2 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -94,7 +94,7 @@ class UnresolvedSetImpl {
private:
template <unsigned N> friend class UnresolvedSet;
UnresolvedSetImpl() {}
- UnresolvedSetImpl(const UnresolvedSetImpl &) {}
+ UnresolvedSetImpl(const UnresolvedSetImpl &) LLVM_DELETED_FUNCTION;
public:
// We don't currently support assignment through this iterator, so we might
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index 392dad94a4a3..a6aa40b9d68b 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -147,9 +147,10 @@ private:
assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
- assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
+ assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!");
+ assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!");
- Value = ((Offset.getQuantity() << 3) | ComponentKind);
+ Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind;
}
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index dd237eece3e4..30b4050e1c81 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -85,7 +85,14 @@ public:
class MatchCallback {
public:
virtual ~MatchCallback();
+
+ /// \brief Called on every match by the \c MatchFinder.
virtual void run(const MatchResult &Result) = 0;
+
+ /// \brief Called at the start of each translation unit.
+ ///
+ /// Optionally override to do per translation unit tasks.
+ virtual void onStartOfTranslationUnit() {}
};
/// \brief Called when parsing is finished. Intended for testing only.
@@ -112,11 +119,24 @@ public:
MatchCallback *Action);
void addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action);
+ void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
+ MatchCallback *Action);
+ void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
+ MatchCallback *Action);
+ void addMatcher(const TypeLocMatcher &NodeMatch,
+ MatchCallback *Action);
/// @}
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
+ /// \brief Finds all matches on the given \c Node.
+ ///
+ /// @{
+ void findAll(const Decl &Node, ASTContext &Context);
+ void findAll(const Stmt &Node, 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
@@ -125,11 +145,10 @@ public:
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
private:
- /// \brief The MatchCallback*'s will be called every time the
- /// UntypedBaseMatcher matches on the AST.
- std::vector< std::pair<
- const internal::UntypedBaseMatcher*,
- MatchCallback*> > Triggers;
+ /// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
+ /// when it matches.
+ std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
+ MatcherCallbackPairs;
/// \brief Called when parsing is done.
ParsingDoneTestCallback *ParsingDone;
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 33ef3dc8d6e0..a70dd5c378bd 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -14,7 +14,7 @@
// a functional in-language DSL to express queries over the C++ AST.
//
// For example, to match a class with a certain name, one would call:
-// record(hasName("MyClass"))
+// recordDecl(hasName("MyClass"))
// which returns a matcher that can be used to find all AST nodes that declare
// a class named 'MyClass'.
//
@@ -25,7 +25,7 @@
//
// For example, when we're interested in child classes of a certain class, we
// would write:
-// record(hasName("MyClass"), hasChild(id("child", record())))
+// recordDecl(hasName("MyClass"), hasChild(id("child", recordDecl())))
// When the match is found via the MatchFinder, a user provided callback will
// be called with a BoundNodes instance that contains a mapping from the
// strings that we provided for the id(...) calls to the nodes that were
@@ -57,52 +57,47 @@ namespace ast_matchers {
/// \brief Maps string IDs to AST nodes matched by parts of a matcher.
///
-/// The bound nodes are generated by adding id(...) matchers into the
-/// match expression around the matchers for the nodes we want to access later.
+/// The bound nodes are generated by calling \c bind("id") on the node matchers
+/// of the nodes we want to access later.
///
-/// The instances of BoundNodes are created by MatchFinder when the user's
+/// The instances of BoundNodes are created by \c MatchFinder when the user's
/// callbacks are executed every time a match is found.
class BoundNodes {
public:
- /// \brief Returns the AST node bound to 'ID'.
- /// Returns NULL if there was no node bound to 'ID' or if there is a node but
+ /// \brief Returns the AST node bound to \c ID.
+ ///
+ /// Returns NULL if there was no node bound to \c ID or if there is a node but
/// it cannot be converted to the specified type.
- /// FIXME: We'll need one of those for every base type.
+ template <typename T>
+ const T *getNodeAs(StringRef ID) const {
+ return MyBoundNodes.getNodeAs<T>(ID);
+ }
+
+ /// \brief Deprecated. Please use \c getNodeAs instead.
/// @{
template <typename T>
const T *getDeclAs(StringRef ID) const {
- return getNodeAs<T>(DeclBindings, ID);
+ return getNodeAs<T>(ID);
}
template <typename T>
const T *getStmtAs(StringRef ID) const {
- return getNodeAs<T>(StmtBindings, ID);
+ return getNodeAs<T>(ID);
}
/// @}
private:
/// \brief Create BoundNodes from a pre-filled map of bindings.
- BoundNodes(const std::map<std::string, const Decl*> &DeclBindings,
- const std::map<std::string, const Stmt*> &StmtBindings)
- : DeclBindings(DeclBindings), StmtBindings(StmtBindings) {}
-
- template <typename T, typename MapT>
- const T *getNodeAs(const MapT &Bindings, StringRef ID) const {
- typename MapT::const_iterator It = Bindings.find(ID);
- if (It == Bindings.end()) {
- return NULL;
- }
- return llvm::dyn_cast<T>(It->second);
- }
+ BoundNodes(internal::BoundNodesMap &MyBoundNodes)
+ : MyBoundNodes(MyBoundNodes) {}
- std::map<std::string, const Decl*> DeclBindings;
- std::map<std::string, const Stmt*> StmtBindings;
+ internal::BoundNodesMap MyBoundNodes;
friend class internal::BoundNodesTree;
};
-/// \brief If the provided matcher matches a node, binds the node to 'ID'.
+/// \brief If the provided matcher matches a node, binds the node to \c ID.
///
-/// FIXME: Add example for accessing it.
+/// FIXME: Do we want to support this now that we have bind()?
template <typename T>
internal::Matcher<T> id(const std::string &ID,
const internal::BindableMatcher<T> &InnerMatcher) {
@@ -113,20 +108,27 @@ internal::Matcher<T> id(const std::string &ID,
/// hierarchy.
/// @{
typedef internal::Matcher<Decl> DeclarationMatcher;
-typedef internal::Matcher<QualType> TypeMatcher;
typedef internal::Matcher<Stmt> StatementMatcher;
+typedef internal::Matcher<QualType> TypeMatcher;
+typedef internal::Matcher<TypeLoc> TypeLocMatcher;
+typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher;
+typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
/// @}
/// \brief Matches any node.
///
/// Useful when another matcher requires a child matcher, but there's no
/// additional constraint. This will often be used with an explicit conversion
-/// to a internal::Matcher<> type such as TypeMatcher.
+/// to an \c internal::Matcher<> type such as \c TypeMatcher.
///
-/// Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
+/// Example: \c DeclarationMatcher(anything()) matches all declarations, e.g.,
+/// \code
/// "int* p" and "void f()" in
/// int* p;
/// void f();
+/// \endcode
+///
+/// Usable as: Any Matcher
inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher> anything() {
return internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>();
}
@@ -144,53 +146,69 @@ const internal::VariadicDynCastAllOfMatcher<Decl, Decl> decl;
/// \brief Matches a declaration of anything that could have a name.
///
-/// Example matches X, S, the anonymous union type, i, and U;
+/// Example matches \c X, \c S, the anonymous union type, \c i, and \c U;
+/// \code
/// typedef int X;
/// struct S {
/// union {
/// int i;
/// } U;
/// };
-const internal::VariadicDynCastAllOfMatcher<
- Decl,
- NamedDecl> nameableDeclaration;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl;
/// \brief Matches C++ class declarations.
///
-/// Example matches X, Z
+/// Example matches \c X, \c Z
+/// \code
/// class X;
/// template<class T> class Z {};
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Decl,
- CXXRecordDecl> record;
+ CXXRecordDecl> recordDecl;
+
+/// \brief Matches C++ class template declarations.
+///
+/// Example matches \c Z
+/// \code
+/// template<class T> class Z {};
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ClassTemplateDecl> classTemplateDecl;
/// \brief Matches C++ class template specializations.
///
/// Given
+/// \code
/// template<typename T> class A {};
/// template<> class A<double> {};
/// A<int> a;
-/// classTemplateSpecialization()
+/// \endcode
+/// classTemplateSpecializationDecl()
/// matches the specializations \c A<int> and \c A<double>
const internal::VariadicDynCastAllOfMatcher<
Decl,
- ClassTemplateSpecializationDecl> classTemplateSpecialization;
+ ClassTemplateSpecializationDecl> classTemplateSpecializationDecl;
/// \brief Matches classTemplateSpecializations that have at least one
-/// TemplateArgument matching the given Matcher.
+/// TemplateArgument matching the given InnerMatcher.
///
/// Given
+/// \code
/// template<typename T> class A {};
/// template<> class A<double> {};
/// A<int> a;
-/// classTemplateSpecialization(hasAnyTemplateArgument(
+/// \endcode
+/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
/// refersToType(asString("int"))))
/// matches the specialization \c A<int>
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
- internal::Matcher<TemplateArgument>, Matcher) {
+ internal::Matcher<TemplateArgument>, InnerMatcher) {
const TemplateArgumentList &List = Node.getTemplateArgs();
for (unsigned i = 0; i < List.size(); ++i) {
- if (Matcher.matches(List.get(i), Finder, Builder))
+ if (InnerMatcher.matches(List.get(i), Finder, Builder))
return true;
}
return false;
@@ -201,19 +219,25 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
///
/// Parentheses and explicit casts are not discarded.
/// Given
+/// \code
/// int arr[5];
/// int a = 0;
/// char b = 0;
/// const int c = a;
/// int *d = arr;
/// long e = (long) 0l;
+/// \endcode
/// The matchers
-/// variable(hasInitializer(ignoringImpCasts(integerLiteral())))
-/// variable(hasInitializer(ignoringImpCasts(declarationReference())))
+/// \code
+/// varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))
+/// varDecl(hasInitializer(ignoringImpCasts(declRefExpr())))
+/// \endcode
/// would match the declarations for a, b, c, and d, but not e.
-/// while
-/// variable(hasInitializer(integerLiteral()))
-/// variable(hasInitializer(declarationReference()))
+/// While
+/// \code
+/// varDecl(hasInitializer(integerLiteral()))
+/// varDecl(hasInitializer(declRefExpr()))
+/// \endcode
/// only match the declarations for b, c, and d.
AST_MATCHER_P(Expr, ignoringImpCasts,
internal::Matcher<Expr>, InnerMatcher) {
@@ -225,15 +249,17 @@ AST_MATCHER_P(Expr, ignoringImpCasts,
///
/// Implicit and non-C Style casts are also discarded.
/// Given
+/// \code
/// int a = 0;
/// char b = (0);
/// void* c = reinterpret_cast<char*>(0);
/// char d = char(0);
+/// \endcode
/// The matcher
-/// variable(hasInitializer(ignoringParenCasts(integerLiteral())))
+/// varDecl(hasInitializer(ignoringParenCasts(integerLiteral())))
/// would match the declarations for a, b, c, and d.
/// while
-/// variable(hasInitializer(integerLiteral()))
+/// varDecl(hasInitializer(integerLiteral()))
/// only match the declaration for a.
AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) {
return InnerMatcher.matches(*Node.IgnoreParenCasts(), Finder, Builder);
@@ -244,21 +270,21 @@ AST_MATCHER_P(Expr, ignoringParenCasts, internal::Matcher<Expr>, InnerMatcher) {
///
/// Explicit casts are not discarded.
/// Given
+/// \code
/// int arr[5];
/// int a = 0;
/// char b = (0);
/// const int c = a;
/// int *d = (arr);
/// long e = ((long) 0l);
+/// \endcode
/// The matchers
-/// variable(hasInitializer(ignoringParenImpCasts(
-/// integerLiteral())))
-/// variable(hasInitializer(ignoringParenImpCasts(
-/// declarationReference())))
+/// varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral())))
+/// varDecl(hasInitializer(ignoringParenImpCasts(declRefExpr())))
/// would match the declarations for a, b, c, and d, but not e.
/// while
-/// variable(hasInitializer(integerLiteral()))
-/// variable(hasInitializer(declarationReference()))
+/// varDecl(hasInitializer(integerLiteral()))
+/// varDecl(hasInitializer(declRefExpr()))
/// would only match the declaration for a.
AST_MATCHER_P(Expr, ignoringParenImpCasts,
internal::Matcher<Expr>, InnerMatcher) {
@@ -266,101 +292,119 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
}
/// \brief Matches classTemplateSpecializations where the n'th TemplateArgument
-/// matches the given Matcher.
+/// matches the given InnerMatcher.
///
/// Given
+/// \code
/// template<typename T, typename U> class A {};
/// A<bool, int> b;
/// A<int, bool> c;
-/// classTemplateSpecialization(hasTemplateArgument(
+/// \endcode
+/// classTemplateSpecializationDecl(hasTemplateArgument(
/// 1, refersToType(asString("int"))))
/// matches the specialization \c A<bool, int>
AST_MATCHER_P2(ClassTemplateSpecializationDecl, hasTemplateArgument,
- unsigned, N, internal::Matcher<TemplateArgument>, Matcher) {
+ unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
const TemplateArgumentList &List = Node.getTemplateArgs();
if (List.size() <= N)
return false;
- return Matcher.matches(List.get(N), Finder, Builder);
+ return InnerMatcher.matches(List.get(N), Finder, Builder);
}
/// \brief Matches a TemplateArgument that refers to a certain type.
///
/// Given
+/// \code
/// struct X {};
/// template<typename T> struct A {};
/// A<X> a;
-/// classTemplateSpecialization(hasAnyTemplateArgument(
+/// \endcode
+/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
/// refersToType(class(hasName("X")))))
/// matches the specialization \c A<X>
AST_MATCHER_P(TemplateArgument, refersToType,
- internal::Matcher<QualType>, Matcher) {
+ internal::Matcher<QualType>, InnerMatcher) {
if (Node.getKind() != TemplateArgument::Type)
return false;
- return Matcher.matches(Node.getAsType(), Finder, Builder);
+ return InnerMatcher.matches(Node.getAsType(), Finder, Builder);
}
/// \brief Matches a TemplateArgument that refers to a certain declaration.
///
/// Given
+/// \code
/// template<typename T> struct A {};
/// struct B { B* next; };
/// A<&B::next> a;
-/// classTemplateSpecialization(hasAnyTemplateArgument(
-/// refersToDeclaration(field(hasName("next"))))
-/// matches the specialization \c A<&B::next> with \c field(...) matching
+/// \endcode
+/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
+/// refersToDeclaration(fieldDecl(hasName("next"))))
+/// matches the specialization \c A<&B::next> with \c fieldDecl(...) matching
/// \c B::next
AST_MATCHER_P(TemplateArgument, refersToDeclaration,
- internal::Matcher<Decl>, Matcher) {
- if (const Decl *Declaration = Node.getAsDecl())
- return Matcher.matches(*Declaration, Finder, Builder);
+ internal::Matcher<Decl>, InnerMatcher) {
+ if (Node.getKind() == TemplateArgument::Declaration)
+ return InnerMatcher.matches(*Node.getAsDecl(), Finder, Builder);
return false;
}
/// \brief Matches C++ constructor declarations.
///
/// Example matches Foo::Foo() and Foo::Foo(int)
+/// \code
/// class Foo {
/// public:
/// Foo();
/// Foo(int);
/// int DoSomething();
/// };
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Decl,
- CXXConstructorDecl> constructor;
+ CXXConstructorDecl> constructorDecl;
/// \brief Matches explicit C++ destructor declarations.
///
/// Example matches Foo::~Foo()
+/// \code
/// class Foo {
/// public:
/// virtual ~Foo();
/// };
-const internal::VariadicDynCastAllOfMatcher<Decl, CXXDestructorDecl> destructor;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ CXXDestructorDecl> destructorDecl;
/// \brief Matches enum declarations.
///
/// Example matches X
+/// \code
/// enum X {
/// A, B, C
/// };
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<Decl, EnumDecl> enumDecl;
/// \brief Matches enum constants.
///
/// Example matches A, B, C
+/// \code
/// enum X {
/// A, B, C
/// };
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Decl,
- EnumConstantDecl> enumConstant;
+ EnumConstantDecl> enumConstantDecl;
/// \brief Matches method declarations.
///
/// Example matches y
+/// \code
/// class X { void y() };
-const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> method;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> methodDecl;
/// \brief Matches variable declarations.
///
@@ -368,76 +412,111 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> method;
/// "field" declarations in Clang parlance.
///
/// Example matches a
+/// \code
/// int a;
-const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> variable;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl;
/// \brief Matches field declarations.
///
/// Given
+/// \code
/// class X { int m; };
-/// field()
+/// \endcode
+/// fieldDecl()
/// matches 'm'.
-const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> field;
+const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl;
/// \brief Matches function declarations.
///
/// Example matches f
+/// \code
/// void f();
-const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> function;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> functionDecl;
+/// \brief Matches C++ function template declarations.
+///
+/// Example matches f
+/// \code
+/// template<class T> void f(T t) {}
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ FunctionTemplateDecl> functionTemplateDecl;
/// \brief Matches statements.
///
/// Given
+/// \code
/// { ++a; }
-/// statement()
+/// \endcode
+/// stmt()
/// matches both the compound statement '{ ++a; }' and '++a'.
-const internal::VariadicDynCastAllOfMatcher<Stmt, Stmt> statement;
+const internal::VariadicDynCastAllOfMatcher<Stmt, Stmt> stmt;
/// \brief Matches declaration statements.
///
/// Given
+/// \code
/// int a;
-/// declarationStatement()
+/// \endcode
+/// declStmt()
/// matches 'int a'.
const internal::VariadicDynCastAllOfMatcher<
Stmt,
- DeclStmt> declarationStatement;
+ DeclStmt> declStmt;
/// \brief Matches member expressions.
///
/// Given
+/// \code
/// class Y {
/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
/// int a; static int b;
/// };
-/// memberExpression()
+/// \endcode
+/// memberExpr()
/// matches this->x, x, y.x, a, this->b
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- MemberExpr> memberExpression;
+const internal::VariadicDynCastAllOfMatcher<Stmt, MemberExpr> memberExpr;
/// \brief Matches call expressions.
///
/// Example matches x.y() and y()
+/// \code
/// X x;
/// x.y();
/// y();
-const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> call;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr;
+
+/// \brief Matches lambda expressions.
+///
+/// Example matches [&](){return 5;}
+/// \code
+/// [&](){return 5;}
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, LambdaExpr> lambdaExpr;
/// \brief Matches member call expressions.
///
/// Example matches x.y()
+/// \code
/// X x;
/// x.y();
-const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr> memberCall;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXMemberCallExpr> memberCallExpr;
/// \brief Matches init list expressions.
///
/// Given
+/// \code
/// int a[] = { 1, 2 };
/// struct B { int x, y; };
/// B b = { 5, 6 };
+/// \endcode
/// initList()
/// matches "{ 1, 2 }" and "{ 5, 6 }"
const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
@@ -445,8 +524,10 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
/// \brief Matches using declarations.
///
/// Given
+/// \code
/// namespace X { int x; }
/// using X::x;
+/// \endcode
/// usingDecl()
/// matches \code using X::x \endcode
const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl;
@@ -454,49 +535,89 @@ const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl;
/// \brief Matches constructor call expressions (including implicit ones).
///
/// Example matches string(ptr, n) and ptr within arguments of f
-/// (matcher = constructorCall())
+/// (matcher = constructExpr())
+/// \code
/// void f(const string &a, const string &b);
/// char *ptr;
/// int n;
/// f(string(ptr, n), ptr);
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
- CXXConstructExpr> constructorCall;
+ CXXConstructExpr> constructExpr;
+
+/// \brief Matches implicit and explicit this expressions.
+///
+/// Example matches the implicit this expression in "return i".
+/// (matcher = thisExpr())
+/// \code
+/// struct foo {
+/// int i;
+/// int f() { return i; }
+/// };
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThisExpr> thisExpr;
/// \brief Matches nodes where temporaries are created.
///
/// Example matches FunctionTakesString(GetStringByValue())
-/// (matcher = bindTemporaryExpression())
+/// (matcher = bindTemporaryExpr())
+/// \code
/// FunctionTakesString(GetStringByValue());
/// FunctionTakesStringByPointer(GetStringPointer());
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
- CXXBindTemporaryExpr> bindTemporaryExpression;
+ CXXBindTemporaryExpr> bindTemporaryExpr;
+
+/// \brief Matches nodes where temporaries are materialized.
+///
+/// Example: Given
+/// \code
+/// struct T {void func()};
+/// T f();
+/// void g(T);
+/// \endcode
+/// materializeTemporaryExpr() matches 'f()' in these statements
+/// \code
+/// T u(f());
+/// g(f());
+/// \endcode
+/// but does not match
+/// \code
+/// f();
+/// f().func();
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ MaterializeTemporaryExpr> materializeTemporaryExpr;
/// \brief Matches new expressions.
///
/// Given
+/// \code
/// new X;
-/// newExpression()
+/// \endcode
+/// newExpr()
/// matches 'new X'.
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- CXXNewExpr> newExpression;
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNewExpr> newExpr;
/// \brief Matches delete expressions.
///
/// Given
+/// \code
/// delete X;
-/// deleteExpression()
+/// \endcode
+/// deleteExpr()
/// matches 'delete X'.
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- CXXDeleteExpr> deleteExpression;
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr> deleteExpr;
/// \brief Matches array subscript expressions.
///
/// Given
+/// \code
/// int i = a[1];
+/// \endcode
/// arraySubscriptExpr()
/// matches "a[1]"
const internal::VariadicDynCastAllOfMatcher<
@@ -507,12 +628,14 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example matches the CXXDefaultArgExpr placeholder inserted for the
/// default value of the second parameter in the call expression f(42)
-/// (matcher = defaultArgument())
+/// (matcher = defaultArgExpr())
+/// \code
/// void f(int x, int y = 0);
/// f(42);
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
- CXXDefaultArgExpr> defaultArgument;
+ CXXDefaultArgExpr> defaultArgExpr;
/// \brief Matches overloaded operator calls.
///
@@ -522,50 +645,67 @@ const internal::VariadicDynCastAllOfMatcher<
/// FIXME: figure out why these do not match?
///
/// Example matches both operator<<((o << b), c) and operator<<(o, b)
-/// (matcher = overloadedOperatorCall())
+/// (matcher = operatorCallExpr())
+/// \code
/// ostream &operator<< (ostream &out, int i) { };
/// ostream &o; int b = 1, c = 1;
/// o << b << c;
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
- CXXOperatorCallExpr> overloadedOperatorCall;
+ CXXOperatorCallExpr> operatorCallExpr;
/// \brief Matches expressions.
///
/// Example matches x()
+/// \code
/// void f() { x(); }
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- Expr> expression;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr;
/// \brief Matches expressions that refer to declarations.
///
/// Example matches x in if (x)
+/// \code
/// bool x;
/// if (x) {}
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- DeclRefExpr> declarationReference;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr;
/// \brief Matches if statements.
///
/// Example matches 'if (x) {}'
+/// \code
/// if (x) {}
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<Stmt, IfStmt> ifStmt;
/// \brief Matches for statements.
///
/// Example matches 'for (;;) {}'
+/// \code
/// for (;;) {}
-const internal::VariadicDynCastAllOfMatcher<
- Stmt, ForStmt> forStmt;
+/// int i[] = {1, 2, 3}; for (auto a : i);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, ForStmt> forStmt;
+
+/// \brief Matches range-based for statements.
+///
+/// forRangeStmt() matches 'for (auto a : i)'
+/// \code
+/// int i[] = {1, 2, 3}; for (auto a : i);
+/// for(int j = 0; j < 5; ++j);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXForRangeStmt> forRangeStmt;
/// \brief Matches the increment statement of a for loop.
///
/// Example:
/// forStmt(hasIncrement(unaryOperator(hasOperatorName("++"))))
/// matches '++x' in
+/// \code
/// for (x; x < N; ++x) { }
+/// \endcode
AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
InnerMatcher) {
const Stmt *const Increment = Node.getInc();
@@ -576,9 +716,11 @@ AST_MATCHER_P(ForStmt, hasIncrement, internal::Matcher<Stmt>,
/// \brief Matches the initialization statement of a for loop.
///
/// Example:
-/// forStmt(hasLoopInit(declarationStatement()))
+/// forStmt(hasLoopInit(declStmt()))
/// matches 'int x = 0' in
+/// \code
/// for (int x = 0; x < N; ++x) { }
+/// \endcode
AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>,
InnerMatcher) {
const Stmt *const Init = Node.getInit();
@@ -588,53 +730,167 @@ AST_MATCHER_P(ForStmt, hasLoopInit, internal::Matcher<Stmt>,
/// \brief Matches while statements.
///
/// Given
+/// \code
/// while (true) {}
+/// \endcode
/// whileStmt()
/// matches 'while (true) {}'.
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- WhileStmt> whileStmt;
+const internal::VariadicDynCastAllOfMatcher<Stmt, WhileStmt> whileStmt;
/// \brief Matches do statements.
///
/// Given
+/// \code
/// do {} while (true);
+/// \endcode
/// doStmt()
/// matches 'do {} while(true)'
const internal::VariadicDynCastAllOfMatcher<Stmt, DoStmt> doStmt;
+/// \brief Matches break statements.
+///
+/// Given
+/// \code
+/// while (true) { break; }
+/// \endcode
+/// breakStmt()
+/// matches 'break'
+const internal::VariadicDynCastAllOfMatcher<Stmt, BreakStmt> breakStmt;
+
+/// \brief Matches continue statements.
+///
+/// Given
+/// \code
+/// while (true) { continue; }
+/// \endcode
+/// continueStmt()
+/// matches 'continue'
+const internal::VariadicDynCastAllOfMatcher<Stmt, ContinueStmt> continueStmt;
+
+/// \brief Matches return statements.
+///
+/// Given
+/// \code
+/// return 1;
+/// \endcode
+/// returnStmt()
+/// matches 'return 1'
+const internal::VariadicDynCastAllOfMatcher<Stmt, ReturnStmt> returnStmt;
+
+/// \brief Matches goto statements.
+///
+/// Given
+/// \code
+/// goto FOO;
+/// FOO: bar();
+/// \endcode
+/// gotoStmt()
+/// matches 'goto FOO'
+const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt;
+
+/// \brief Matches label statements.
+///
+/// Given
+/// \code
+/// goto FOO;
+/// FOO: bar();
+/// \endcode
+/// labelStmt()
+/// matches 'FOO:'
+const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt;
+
+/// \brief Matches switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// switchStmt()
+/// matches 'switch(a)'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt;
+
/// \brief Matches case and default statements inside switch statements.
///
/// Given
+/// \code
/// switch(a) { case 42: break; default: break; }
+/// \endcode
/// switchCase()
/// matches 'case 42: break;' and 'default: break;'.
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- SwitchCase> switchCase;
+const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase;
/// \brief Matches compound statements.
///
/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
+/// \code
/// for (;;) {{}}
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- CompoundStmt> compoundStatement;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundStmt> compoundStmt;
+
+/// \brief Matches catch statements.
+///
+/// \code
+/// try {} catch(int i) {}
+/// \endcode
+/// catchStmt()
+/// matches 'catch(int i)'
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXCatchStmt> catchStmt;
+
+/// \brief Matches try statements.
+///
+/// \code
+/// try {} catch(int i) {}
+/// \endcode
+/// tryStmt()
+/// matches 'try {}'
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> tryStmt;
+
+/// \brief Matches throw expressions.
+///
+/// \code
+/// try { throw 5; } catch(int i) {}
+/// \endcode
+/// throwExpr()
+/// matches 'throw 5'
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> throwExpr;
+
+/// \brief Matches null statements.
+///
+/// \code
+/// foo();;
+/// \endcode
+/// nullStmt()
+/// matches the second ';'
+const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt;
+
+/// \brief Matches asm statements.
+///
+/// \code
+/// int i = 100;
+/// __asm("mov al, 2");
+/// \endcode
+/// asmStmt()
+/// matches '__asm("mov al, 2")'
+const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt;
/// \brief Matches bool literals.
///
/// Example matches true
+/// \code
/// true
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
+ Stmt,
CXXBoolLiteralExpr> boolLiteral;
/// \brief Matches string literals (also matches wide string literals).
///
/// Example matches "abcd", L"abcd"
+/// \code
/// char *s = "abcd"; wchar_t *ws = L"abcd"
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
+ Stmt,
StringLiteral> stringLiteral;
/// \brief Matches character literals (also matches wchar_t).
@@ -643,9 +899,11 @@ const internal::VariadicDynCastAllOfMatcher<
/// though.
///
/// Example matches 'a', L'a'
+/// \code
/// char ch = 'a'; wchar_t chw = L'a';
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
+ Stmt,
CharacterLiteral> characterLiteral;
/// \brief Matches integer literals of all sizes / encodings.
@@ -654,13 +912,27 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example matches 1, 1L, 0x1, 1U
const internal::VariadicDynCastAllOfMatcher<
- Expr,
+ Stmt,
IntegerLiteral> integerLiteral;
+/// \brief Matches user defined literal operator call.
+///
+/// Example match: "foo"_suffix
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ UserDefinedLiteral> userDefinedLiteral;
+
+/// \brief Matches nullptr literal.
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXNullPtrLiteralExpr> nullPtrLiteralExpr;
+
/// \brief Matches binary operator expressions.
///
/// Example matches a || b
+/// \code
/// !(a || b)
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
BinaryOperator> binaryOperator;
@@ -668,7 +940,9 @@ const internal::VariadicDynCastAllOfMatcher<
/// \brief Matches unary operator expressions.
///
/// Example matches !a
+/// \code
/// !a || b
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
UnaryOperator> unaryOperator;
@@ -676,7 +950,9 @@ const internal::VariadicDynCastAllOfMatcher<
/// \brief Matches conditional operator expressions.
///
/// Example matches a ? b : c
+/// \code
/// (a ? b : c) + 42
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
ConditionalOperator> conditionalOperator;
@@ -688,10 +964,12 @@ const internal::VariadicDynCastAllOfMatcher<
/// more readable.
///
/// Example matches reinterpret_cast<char*>(&p) in
+/// \code
/// void* p = reinterpret_cast<char*>(&p);
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CXXReinterpretCastExpr> reinterpretCast;
+ Stmt,
+ CXXReinterpretCastExpr> reinterpretCastExpr;
/// \brief Matches a C++ static_cast expression.
///
@@ -699,38 +977,54 @@ const internal::VariadicDynCastAllOfMatcher<
/// \see reinterpretCast
///
/// Example:
-/// staticCast()
+/// staticCastExpr()
/// matches
/// static_cast<long>(8)
/// in
+/// \code
/// long eight(static_cast<long>(8));
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CXXStaticCastExpr> staticCast;
+ Stmt,
+ CXXStaticCastExpr> staticCastExpr;
/// \brief Matches a dynamic_cast expression.
///
/// Example:
-/// dynamicCast()
+/// dynamicCastExpr()
/// matches
/// dynamic_cast<D*>(&b);
/// in
+/// \code
/// struct B { virtual ~B() {} }; struct D : B {};
/// B b;
/// D* p = dynamic_cast<D*>(&b);
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CXXDynamicCastExpr> dynamicCast;
+ Stmt,
+ CXXDynamicCastExpr> dynamicCastExpr;
/// \brief Matches a const_cast expression.
///
/// Example: Matches const_cast<int*>(&r) in
+/// \code
/// int n = 42;
-/// const int& r(n);
+/// const int &r(n);
/// int* p = const_cast<int*>(&r);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXConstCastExpr> constCastExpr;
+
+/// \brief Matches a C-style cast expression.
+///
+/// Example: Matches (int*) 2.2f in
+/// \code
+/// int i = (int) 2.2f;
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CXXConstCastExpr> constCast;
+ Stmt,
+ CStyleCastExpr> cStyleCastExpr;
/// \brief Matches explicit cast expressions.
///
@@ -746,98 +1040,127 @@ const internal::VariadicDynCastAllOfMatcher<
/// \see hasDestinationType.
///
/// Example: matches all five of the casts in
+/// \code
/// int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
+/// \endcode
/// but does not match the implicit conversion in
+/// \code
/// long ell = 42;
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- ExplicitCastExpr> explicitCast;
+ Stmt,
+ ExplicitCastExpr> explicitCastExpr;
/// \brief Matches the implicit cast nodes of Clang's AST.
///
/// This matches many different places, including function call return value
/// eliding, as well as any type conversions.
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- ImplicitCastExpr> implicitCast;
+ Stmt,
+ ImplicitCastExpr> implicitCastExpr;
/// \brief Matches any cast nodes of Clang's AST.
///
/// Example: castExpr() matches each of the following:
+/// \code
/// (int) 3;
/// const_cast<Expr *>(SubExpr);
/// char c = 0;
+/// \endcode
/// but does not match
+/// \code
/// int i = (0);
/// int k = 0;
-const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CastExpr> castExpr;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr;
/// \brief Matches functional cast expressions
///
/// Example: Matches Foo(bar);
+/// \code
/// Foo f = bar;
/// Foo g = (Foo) bar;
/// Foo h = Foo(bar);
+/// \endcode
const internal::VariadicDynCastAllOfMatcher<
- Expr,
- CXXFunctionalCastExpr> functionalCast;
+ Stmt,
+ CXXFunctionalCastExpr> functionalCastExpr;
+
+/// \brief Matches \c QualTypes in the clang AST.
+const internal::VariadicAllOfMatcher<QualType> qualType;
+
+/// \brief Matches \c Types in the clang AST.
+const internal::VariadicDynCastAllOfMatcher<Type, Type> type;
+
+/// \brief Matches \c TypeLocs in the clang AST.
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc;
/// \brief Various overloads for the anyOf matcher.
/// @{
-template<typename C1, typename C2>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1, C2>
-anyOf(const C1 &P1, const C2 &P2) {
+
+/// \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,
- C1, C2 >(P1, P2);
+ M1, M2 >(P1, P2);
}
-template<typename C1, typename C2, typename C3>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2, C3> >
-anyOf(const C1 &P1, const C2 &P2, const C3 &P3) {
+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 C1, typename C2, typename C3, typename C4>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2,
+template<typename M1, typename M2, typename M3, typename M4>
+internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2,
internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- C3, C4> > >
-anyOf(const C1 &P1, const C2 &P2, const C3 &P3, const C4 &P4) {
+ 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 C1, typename C2, typename C3, typename C4, typename C5>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C3,
+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,
- C4, C5> > > >
-anyOf(const C1& P1, const C2& P2, const C3& P3, const C4& P4, const C5& P5) {
+ 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.
/// @{
-template<typename C1, typename C2>
-internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C1, C2>
-allOf(const C1 &P1, const C2 &P2) {
+
+/// \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,
- C1, C2>(P1, P2);
+ M1, M2>(P1, P2);
}
-template<typename C1, typename C2, typename C3>
-internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C1,
- internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C2, C3> >
-allOf(const C1& P1, const C2& P2, const C3& P3) {
+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));
}
+
/// @}
/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
///
/// Given
+/// \code
/// Foo x = bar;
/// int y = sizeof(x) + alignof(x);
+/// \endcode
/// unaryExprOrTypeTraitExpr()
/// matches \c sizeof(x) and \c alignof(x)
const internal::VariadicDynCastAllOfMatcher<
@@ -847,20 +1170,24 @@ const internal::VariadicDynCastAllOfMatcher<
/// \brief Matches unary expressions that have a specific type of argument.
///
/// Given
+/// \code
/// int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c);
+/// \endcode
/// unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
/// matches \c sizeof(a) and \c alignof(c)
AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType,
- internal::Matcher<QualType>, Matcher) {
+ internal::Matcher<QualType>, InnerMatcher) {
const QualType ArgumentType = Node.getTypeOfArgument();
- return Matcher.matches(ArgumentType, Finder, Builder);
+ return InnerMatcher.matches(ArgumentType, Finder, Builder);
}
/// \brief Matches unary expressions of a certain kind.
///
/// Given
+/// \code
/// int x;
/// int s = sizeof(x) + alignof(x)
+/// \endcode
/// unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf))
/// matches \c sizeof(x)
AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) {
@@ -870,17 +1197,17 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) {
/// \brief Same as unaryExprOrTypeTraitExpr, but only matching
/// alignof.
inline internal::Matcher<Stmt> alignOfExpr(
- const internal::Matcher<UnaryExprOrTypeTraitExpr> &Matcher) {
+ const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
return internal::Matcher<Stmt>(unaryExprOrTypeTraitExpr(allOf(
- ofKind(UETT_AlignOf), Matcher)));
+ ofKind(UETT_AlignOf), InnerMatcher)));
}
/// \brief Same as unaryExprOrTypeTraitExpr, but only matching
/// sizeof.
inline internal::Matcher<Stmt> sizeOfExpr(
- const internal::Matcher<UnaryExprOrTypeTraitExpr> &Matcher) {
+ const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
return internal::Matcher<Stmt>(unaryExprOrTypeTraitExpr(allOf(
- ofKind(UETT_SizeOf), Matcher)));
+ ofKind(UETT_SizeOf), InnerMatcher)));
}
/// \brief Matches NamedDecl nodes that have the specified name.
@@ -890,10 +1217,14 @@ inline internal::Matcher<Stmt> sizeOfExpr(
/// Does not match typedefs of an underlying type with the given name.
///
/// Example matches X (Name == "X")
+/// \code
/// class X;
+/// \endcode
///
/// Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
-/// namespace a { namespace b { class X; } }
+/// \code
+/// namespace a { namespace b { class X; } }
+/// \endcode
AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
assert(!Name.empty());
const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
@@ -914,10 +1245,14 @@ AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
/// of an underlying type with the given name.
///
/// Example matches X (regexp == "::X")
+/// \code
/// class X;
+/// \endcode
///
/// Example matches X (regexp is one of "::X", "^foo::.*X", among others)
-/// namespace foo { namespace bar { class X; } }
+/// \code
+/// namespace foo { namespace bar { class X; } }
+/// \endcode
AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
assert(!RegExp.empty());
std::string FullNameString = "::" + Node.getQualifiedNameAsString();
@@ -931,10 +1266,12 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
/// "operator" prefix, such as "<<", for OverloadedOperatorCall's.
///
/// Example matches a << b
-/// (matcher == overloadedOperatorCall(hasOverloadedOperatorName("<<")))
+/// (matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
+/// \code
/// a << b;
/// c && d; // assuming both operator<<
/// // and operator&& are overloaded somewhere.
+/// \endcode
AST_MATCHER_P(CXXOperatorCallExpr,
hasOverloadedOperatorName, std::string, Name) {
return getOperatorSpelling(Node.getOperator()) == Name;
@@ -943,20 +1280,24 @@ AST_MATCHER_P(CXXOperatorCallExpr,
/// \brief Matches C++ classes that are directly or indirectly derived from
/// a class matching \c Base.
///
-/// Note that a class is considered to be also derived from itself.
+/// Note that a class is not considered to be derived from itself.
///
-/// Example matches X, Y, Z, C (Base == hasName("X"))
-/// class X; // A class is considered to be derived from itself
+/// Example matches Y, Z, C (Base == hasName("X"))
+/// \code
+/// class X;
/// class Y : public X {}; // directly derived
/// class Z : public Y {}; // indirectly derived
/// typedef X A;
/// typedef A B;
/// class C : public B {}; // derived from a typedef of X
+/// \endcode
///
/// In the following example, Bar matches isDerivedFrom(hasName("X")):
+/// \code
/// class Foo;
/// typedef Foo X;
/// class Bar : public Foo {}; // derived from a type that X is a typedef of
+/// \endcode
AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
internal::Matcher<NamedDecl>, Base) {
return Finder->classIsDerivedFrom(&Node, Base, Builder);
@@ -968,15 +1309,34 @@ inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
return isDerivedFrom(hasName(BaseName));
}
+/// \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));
+}
+
+/// \brief Overloaded method as shortcut for
+/// \c isSameOrDerivedFrom(hasName(...)).
+inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
+ StringRef BaseName) {
+ assert(!BaseName.empty());
+ return isSameOrDerivedFrom(hasName(BaseName));
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
-/// Example matches X, Y (matcher = record(has(record(hasName("X")))
+/// Example matches X, Y (matcher = recordDecl(has(recordDecl(hasName("X")))
+/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class Y { class X {}; };
/// class Z { class Y { class X {}; }; }; // Does not match Z.
+/// \endcode
///
/// 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) {
@@ -988,12 +1348,16 @@ internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
/// provided matcher.
///
/// Example matches X, Y, Z
-/// (matcher = record(hasDescendant(record(hasName("X")))))
+/// (matcher = recordDecl(hasDescendant(recordDecl(hasName("X")))))
+/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class Y { class X {}; };
/// class Z { class Y { class X {}; }; };
+/// \endcode
///
/// 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) {
@@ -1002,22 +1366,25 @@ hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
DescendantT>(DescendantMatcher);
}
-
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
-/// Example matches X, Y (matcher = record(forEach(record(hasName("X")))
+/// Example matches X, Y (matcher = recordDecl(forEach(recordDecl(hasName("X")))
+/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class Y { class X {}; };
/// class Z { class Y { class X {}; }; }; // Does not match Z.
+/// \endcode
///
/// ChildT must be an AST base type.
///
/// As opposed to 'has', 'forEach' will cause a match for each result that
/// 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) {
+ const internal::Matcher<ChildT> &ChildMatcher) {
return internal::ArgumentAdaptingMatcher<
internal::ForEachMatcher,
ChildT>(ChildMatcher);
@@ -1027,10 +1394,12 @@ internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
/// provided matcher.
///
/// Example matches X, A, B, C
-/// (matcher = record(forEachDescendant(record(hasName("X")))))
+/// (matcher = recordDecl(forEachDescendant(recordDecl(hasName("X")))))
+/// \code
/// class X {}; // Matches X, because X::X is a class of name X inside X.
/// class A { class X {}; };
/// class B { class C { class X {}; }; };
+/// \endcode
///
/// DescendantT must be an AST base type.
///
@@ -1038,25 +1407,72 @@ internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
/// each result that matches instead of only on the first one.
///
/// Note: Recursively combined ForEachDescendant can cause many matches:
-/// record(forEachDescendant(record(forEachDescendant(record()))))
+/// recordDecl(forEachDescendant(recordDecl(forEachDescendant(recordDecl()))))
/// will match 10 times (plus injected class name matches) on:
+/// \code
/// class A { class B { class C { class D { class E {}; }; }; }; };
+/// \endcode
+///
+/// Usable as: Any Matcher
template <typename DescendantT>
-internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, DescendantT>
+internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher,
+ DescendantT>
forEachDescendant(
- const internal::Matcher<DescendantT>& DescendantMatcher) {
+ const internal::Matcher<DescendantT> &DescendantMatcher) {
return internal::ArgumentAdaptingMatcher<
internal::ForEachDescendantMatcher,
DescendantT>(DescendantMatcher);
}
+/// \brief Matches AST nodes that have a parent that matches the provided
+/// matcher.
+///
+/// Given
+/// \code
+/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+/// \endcode
+/// \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);
+}
+
+/// \brief Matches AST nodes that have an ancestor that matches the provided
+/// matcher.
+///
+/// Given
+/// \code
+/// void f() { if (true) { int x = 42; } }
+/// void g() { for (;;) { int x = 43; } }
+/// \endcode
+/// \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);
+}
+
/// \brief Matches if the provided matcher does not match.
///
-/// Example matches Y (matcher = record(unless(hasName("X"))))
+/// Example matches Y (matcher = recordDecl(unless(hasName("X"))))
+/// \code
/// class X {};
/// class Y {};
+/// \endcode
+///
+/// Usable as: Any Matcher
template <typename M>
-internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M> unless(const M &InnerMatcher) {
+internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M>
+unless(const M &InnerMatcher) {
return internal::PolymorphicMatcherWithParam1<
internal::NotMatcher, M>(InnerMatcher);
}
@@ -1064,7 +1480,8 @@ internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M> unless(const M &
/// \brief Matches a type if the declaration of the type matches the given
/// matcher.
///
-/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>
+/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>,
+/// Matcher<MemberExpr>
inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
internal::Matcher<Decl> >
hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
@@ -1075,9 +1492,11 @@ inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
/// \brief Matches on the implicit object argument of a member call expression.
///
-/// Example matches y.x() (matcher = call(on(hasType(record(hasName("Y"))))))
+/// Example matches y.x() (matcher = callExpr(on(hasType(recordDecl(hasName("Y"))))))
+/// \code
/// class Y { public: void x(); };
/// void z() { Y y; y.x(); }",
+/// \endcode
///
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
@@ -1092,9 +1511,11 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
/// \brief Matches if the call expression's callee expression matches.
///
/// Given
+/// \code
/// class Y { void x() { this->x(); x(); Y y; y.x(); } };
/// void f() { f(); }
-/// call(callee(expression()))
+/// \endcode
+/// callExpr(callee(expr()))
/// matches this->x(), x(), y.x(), f()
/// with callee(...)
/// matching this->x, x, y.x, f respectively
@@ -1113,9 +1534,11 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
/// \brief Matches if the call expression's callee's declaration matches the
/// given matcher.
///
-/// Example matches y.x() (matcher = call(callee(method(hasName("x")))))
+/// Example matches y.x() (matcher = callExpr(callee(methodDecl(hasName("x")))))
+/// \code
/// class Y { public: void x(); };
/// void z() { Y y; y.x();
+/// \endcode
inline internal::Matcher<CallExpr> callee(
const internal::Matcher<Decl> &InnerMatcher) {
return internal::Matcher<CallExpr>(hasDeclaration(InnerMatcher));
@@ -1124,12 +1547,12 @@ inline internal::Matcher<CallExpr> callee(
/// \brief Matches if the expression's or declaration's type matches a type
/// matcher.
///
-/// Example matches x (matcher = expression(hasType(
-/// hasDeclaration(record(hasName("X"))))))
-/// and z (matcher = variable(hasType(
-/// hasDeclaration(record(hasName("X"))))))
+/// Example matches x (matcher = expr(hasType(recordDecl(hasName("X")))))
+/// and z (matcher = varDecl(hasType(recordDecl(hasName("X")))))
+/// \code
/// 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 ||
@@ -1143,14 +1566,16 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
///
/// In case of a value declaration (for example a variable declaration),
/// this resolves one layer of indirection. For example, in the value
-/// declaration "X x;", record(hasName("X")) matches the declaration of X,
-/// while variable(hasType(record(hasName("X")))) matches the declaration
+/// declaration "X x;", recordDecl(hasName("X")) matches the declaration of X,
+/// while varDecl(hasType(recordDecl(hasName("X")))) matches the declaration
/// of x."
///
-/// Example matches x (matcher = expression(hasType(record(hasName("X")))))
-/// and z (matcher = variable(hasType(record(hasName("X")))))
+/// Example matches x (matcher = expr(hasType(recordDecl(hasName("X")))))
+/// and z (matcher = varDecl(hasType(recordDecl(hasName("X")))))
+/// \code
/// class X {};
/// void y(X &x) { x; X z; }
+/// \endcode
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
inline internal::PolymorphicMatcherWithParam1<
@@ -1164,9 +1589,11 @@ hasType(const internal::Matcher<Decl> &InnerMatcher) {
/// \brief Matches if the matched type is represented by the given string.
///
/// Given
+/// \code
/// class Y { public: void x(); };
/// void z() { Y* y; y->x(); }
-/// call(on(hasType(asString("class Y *"))))
+/// \endcode
+/// callExpr(on(hasType(asString("class Y *"))))
/// matches y->x()
AST_MATCHER_P(QualType, asString, std::string, Name) {
return Name == Node.getAsString();
@@ -1176,9 +1603,11 @@ AST_MATCHER_P(QualType, asString, std::string, Name) {
/// matches the specified matcher.
///
/// Example matches y->x()
-/// (matcher = call(on(hasType(pointsTo(record(hasName("Y")))))))
+/// (matcher = callExpr(on(hasType(pointsTo(recordDecl(hasName("Y")))))))
+/// \code
/// class Y { public: void x(); };
/// void z() { Y *y; y->x(); }
+/// \endcode
AST_MATCHER_P(
QualType, pointsTo, internal::Matcher<QualType>,
InnerMatcher) {
@@ -1197,12 +1626,14 @@ inline internal::Matcher<QualType> pointsTo(
/// type matches the specified matcher.
///
/// Example matches X &x and const X &y
-/// (matcher = variable(hasType(references(record(hasName("X"))))))
+/// (matcher = varDecl(hasType(references(recordDecl(hasName("X"))))))
+/// \code
/// class X {
/// void a(X b) {
/// X &x = b;
/// const X &y = b;
/// };
+/// \endcode
AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
InnerMatcher) {
return (!Node.isNull() && Node->isReferenceType() &&
@@ -1243,9 +1674,11 @@ inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
/// specified matcher.
///
/// Example matches x in if(x)
-/// (matcher = declarationReference(to(variable(hasName("x")))))
+/// (matcher = declRefExpr(to(varDecl(hasName("x")))))
+/// \code
/// bool x;
/// if (x) {}
+/// \endcode
AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
InnerMatcher) {
const Decl *DeclNode = Node.getDecl();
@@ -1259,29 +1692,33 @@ AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
/// FIXME: This currently only works for functions. Fix.
///
/// Given
+/// \code
/// namespace a { void f() {} }
/// using a::f;
/// void g() {
/// f(); // Matches this ..
/// a::f(); // .. but not this.
/// }
-/// declarationReference(throughUsingDeclaration(anything()))
+/// \endcode
+/// declRefExpr(throughUsingDeclaration(anything()))
/// matches \c f()
AST_MATCHER_P(DeclRefExpr, throughUsingDecl,
- internal::Matcher<UsingShadowDecl>, Matcher) {
+ internal::Matcher<UsingShadowDecl>, InnerMatcher) {
const NamedDecl *FoundDecl = Node.getFoundDecl();
if (const UsingShadowDecl *UsingDecl =
llvm::dyn_cast<UsingShadowDecl>(FoundDecl))
- return Matcher.matches(*UsingDecl, Finder, Builder);
+ return InnerMatcher.matches(*UsingDecl, Finder, Builder);
return false;
}
/// \brief Matches the Decl of a DeclStmt which has a single declaration.
///
/// Given
+/// \code
/// int a, b;
/// int c;
-/// declarationStatement(hasSingleDecl(anything()))
+/// \endcode
+/// declStmt(hasSingleDecl(anything()))
/// matches 'int c;' but not 'int a, b;'.
AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) {
if (Node.isSingleDecl()) {
@@ -1294,9 +1731,11 @@ AST_MATCHER_P(DeclStmt, hasSingleDecl, internal::Matcher<Decl>, InnerMatcher) {
/// \brief Matches a variable declaration that has an initializer expression
/// that matches the given matcher.
///
-/// Example matches x (matcher = variable(hasInitializer(call())))
+/// Example matches x (matcher = varDecl(hasInitializer(callExpr())))
+/// \code
/// bool y() { return true; }
/// bool x = y();
+/// \endcode
AST_MATCHER_P(
VarDecl, hasInitializer, internal::Matcher<Expr>,
InnerMatcher) {
@@ -1308,9 +1747,11 @@ AST_MATCHER_P(
/// \brief 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 = call(argumentCountIs(2)))
+/// Example matches f(0, 0) (matcher = callExpr(argumentCountIs(2)))
+/// \code
/// 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,
@@ -1323,8 +1764,10 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
/// call expression.
///
/// Example matches y in x(y)
-/// (matcher = call(hasArgument(0, declarationReference())))
+/// (matcher = callExpr(hasArgument(0, declRefExpr())))
+/// \code
/// 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 ||
@@ -1340,13 +1783,15 @@ AST_POLYMORPHIC_MATCHER_P2(
/// declarations.
///
/// Example: Given
+/// \code
/// int a, b;
/// int c;
/// int d = 2, e;
+/// \endcode
/// declCountIs(2)
/// matches 'int a, b;' and 'int d = 2, e;', but not 'int c;'.
AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) {
- return std::distance(Node.decl_begin(), Node.decl_end()) == N;
+ return std::distance(Node.decl_begin(), Node.decl_end()) == (ptrdiff_t)N;
}
/// \brief Matches the n'th declaration of a declaration statement.
@@ -1355,15 +1800,19 @@ AST_MATCHER_P(DeclStmt, declCountIs, unsigned, N) {
/// breaks up multiple-declaration DeclStmt's into multiple single-declaration
/// DeclStmt's.
/// Example: Given non-global declarations
+/// \code
/// int a, b = 0;
/// int c;
/// int d = 2, e;
-/// declarationStatement(containsDeclaration(
-/// 0, variable(hasInitializer(anything()))))
+/// \endcode
+/// declStmt(containsDeclaration(
+/// 0, varDecl(hasInitializer(anything()))))
/// matches only 'int d = 2, e;', and
-/// declarationStatement(containsDeclaration(1, variable()))
+/// declStmt(containsDeclaration(1, varDecl()))
+/// \code
/// matches 'int a, b = 0' as well as 'int d = 2, e;'
/// but 'int c;' is not matched.
+/// \endcode
AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
internal::Matcher<Decl>, InnerMatcher) {
const unsigned NumDecls = std::distance(Node.decl_begin(), Node.decl_end());
@@ -1377,11 +1826,13 @@ AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
/// \brief Matches a constructor initializer.
///
/// Given
+/// \code
/// struct Foo {
/// Foo() : foo_(1) { }
/// int foo_;
/// };
-/// record(has(constructor(hasAnyConstructorInitializer(anything()))))
+/// \endcode
+/// recordDecl(has(constructorDecl(hasAnyConstructorInitializer(anything()))))
/// record matches Foo, hasAnyConstructorInitializer matches foo_(1)
AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
@@ -1397,11 +1848,13 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
/// \brief Matches the field declaration of a constructor initializer.
///
/// Given
+/// \code
/// struct Foo {
/// Foo() : foo_(1) { }
/// int foo_;
/// };
-/// record(has(constructor(hasAnyConstructorInitializer(
+/// \endcode
+/// recordDecl(has(constructorDecl(hasAnyConstructorInitializer(
/// forField(hasName("foo_"))))))
/// matches Foo
/// with forField matching foo_
@@ -1415,11 +1868,13 @@ AST_MATCHER_P(CXXCtorInitializer, forField,
/// \brief Matches the initializer expression of a constructor initializer.
///
/// Given
+/// \code
/// struct Foo {
/// Foo() : foo_(1) { }
/// int foo_;
/// };
-/// record(has(constructor(hasAnyConstructorInitializer(
+/// \endcode
+/// recordDecl(has(constructorDecl(hasAnyConstructorInitializer(
/// withInitializer(integerLiteral(equals(1)))))))
/// matches Foo
/// with withInitializer matching (1)
@@ -1434,12 +1889,14 @@ AST_MATCHER_P(CXXCtorInitializer, withInitializer,
/// code (as opposed to implicitly added by the compiler).
///
/// Given
+/// \code
/// struct Foo {
/// Foo() { }
/// Foo(int) : foo_("A") { }
/// string foo_;
/// };
-/// constructor(hasAnyConstructorInitializer(isWritten()))
+/// \endcode
+/// constructorDecl(hasAnyConstructorInitializer(isWritten()))
/// will match Foo(int), but not Foo()
AST_MATCHER(CXXCtorInitializer, isWritten) {
return Node.isWritten();
@@ -1455,8 +1912,10 @@ AST_MATCHER(CXXConstructorDecl, isImplicit) {
/// expression.
///
/// Given
+/// \code
/// void x(int, int, int) { int y; x(1, y, 42); }
-/// call(hasAnyArgument(declarationReference()))
+/// \endcode
+/// callExpr(hasAnyArgument(declRefExpr()))
/// matches x(1, y, 42)
/// with hasAnyArgument(...)
/// matching y
@@ -1478,8 +1937,10 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher<Expr>,
/// \brief Matches the n'th parameter of a function declaration.
///
/// Given
+/// \code
/// class X { void f(int x) {} };
-/// method(hasParameter(0, hasType(variable())))
+/// \endcode
+/// methodDecl(hasParameter(0, hasType(varDecl())))
/// matches f(int x) {}
/// with hasParameter(...)
/// matching int x
@@ -1496,8 +1957,10 @@ AST_MATCHER_P2(FunctionDecl, hasParameter,
/// Does not match the 'this' parameter of a method.
///
/// Given
+/// \code
/// class X { void f(int x, int y, int z) {} };
-/// method(hasAnyParameter(hasName("y")))
+/// \endcode
+/// methodDecl(hasAnyParameter(hasName("y")))
/// matches f(int x, int y, int z) {}
/// with hasAnyParameter(...)
/// matching int y
@@ -1514,20 +1977,25 @@ AST_MATCHER_P(FunctionDecl, hasAnyParameter,
/// \brief Matches the return type of a function declaration.
///
/// Given:
+/// \code
/// class X { int f() { return 1; } };
-/// method(returns(asString("int")))
+/// \endcode
+/// methodDecl(returns(asString("int")))
/// matches int f() { return 1; }
-AST_MATCHER_P(FunctionDecl, returns, internal::Matcher<QualType>, Matcher) {
- return Matcher.matches(Node.getResultType(), Finder, Builder);
+AST_MATCHER_P(FunctionDecl, returns,
+ internal::Matcher<QualType>, InnerMatcher) {
+ return InnerMatcher.matches(Node.getResultType(), Finder, Builder);
}
/// \brief Matches extern "C" function declarations.
///
/// Given:
+/// \code
/// extern "C" void f() {}
/// extern "C" { void g() {} }
/// void h() {}
-/// function(isExternC())
+/// \endcode
+/// functionDecl(isExternC())
/// matches the declaration of f and g, but not the declaration h
AST_MATCHER(FunctionDecl, isExternC) {
return Node.isExternC();
@@ -1537,7 +2005,9 @@ AST_MATCHER(FunctionDecl, isExternC) {
/// or conditional operator.
///
/// Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
+/// \code
/// if (true) {}
+/// \endcode
AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher<Expr>,
InnerMatcher) {
TOOLING_COMPILE_ASSERT(
@@ -1555,7 +2025,9 @@ AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher<Expr>,
/// \brief Matches the condition variable statement in an if statement.
///
/// Given
+/// \code
/// if (A* a = GetAPointer()) {}
+/// \endcode
/// hasConditionVariableStatment(...)
/// matches 'A* a = GetAPointer()'.
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
@@ -1569,29 +2041,33 @@ AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
/// \brief Matches the index expression of an array subscript expression.
///
/// Given
+/// \code
/// int i[5];
/// void f() { i[1] = 42; }
+/// \endcode
/// arraySubscriptExpression(hasIndex(integerLiteral()))
/// matches \c i[1] with the \c integerLiteral() matching \c 1
AST_MATCHER_P(ArraySubscriptExpr, hasIndex,
- internal::Matcher<Expr>, matcher) {
+ internal::Matcher<Expr>, InnerMatcher) {
if (const Expr* Expression = Node.getIdx())
- return matcher.matches(*Expression, Finder, Builder);
+ return InnerMatcher.matches(*Expression, Finder, Builder);
return false;
}
/// \brief Matches the base expression of an array subscript expression.
///
/// Given
+/// \code
/// int i[5];
/// void f() { i[1] = 42; }
-/// arraySubscriptExpression(hasBase(implicitCast(
-/// hasSourceExpression(declarationReference()))))
-/// matches \c i[1] with the \c declarationReference() matching \c i
+/// \endcode
+/// arraySubscriptExpression(hasBase(implicitCastExpr(
+/// hasSourceExpression(declRefExpr()))))
+/// matches \c i[1] with the \c declRefExpr() matching \c i
AST_MATCHER_P(ArraySubscriptExpr, hasBase,
- internal::Matcher<Expr>, matcher) {
+ internal::Matcher<Expr>, InnerMatcher) {
if (const Expr* Expression = Node.getBase())
- return matcher.matches(*Expression, Finder, Builder);
+ return InnerMatcher.matches(*Expression, Finder, Builder);
return false;
}
@@ -1599,10 +2075,12 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
/// a given body.
///
/// Given
+/// \code
/// for (;;) {}
-/// hasBody(compoundStatement())
+/// \endcode
+/// hasBody(compoundStmt())
/// matches 'for (;;) {}'
-/// with compoundStatement()
+/// with compoundStmt()
/// matching '{}'
AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
InnerMatcher) {
@@ -1620,10 +2098,12 @@ AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
/// a given matcher.
///
/// Given
+/// \code
/// { {}; 1+2; }
-/// hasAnySubstatement(compoundStatement())
+/// \endcode
+/// hasAnySubstatement(compoundStmt())
/// matches '{ {}; 1+2; }'
-/// with compoundStatement()
+/// with compoundStmt()
/// matching '{}'
AST_MATCHER_P(CompoundStmt, hasAnySubstatement,
internal::Matcher<Stmt>, InnerMatcher) {
@@ -1639,8 +2119,10 @@ AST_MATCHER_P(CompoundStmt, hasAnySubstatement,
/// child statements.
///
/// Example: Given
+/// \code
/// { for (;;) {} }
-/// compoundStatement(statementCountIs(0)))
+/// \endcode
+/// compoundStmt(statementCountIs(0)))
/// matches '{}'
/// but does not match the outer compound statement.
AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
@@ -1650,7 +2132,9 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
/// \brief Matches literals that are equal to the given value.
///
/// Example matches true (matcher = boolLiteral(equals(true)))
+/// \code
/// true
+/// \endcode
///
/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
@@ -1666,7 +2150,9 @@ equals(const ValueT &Value) {
/// unary).
///
/// Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+/// \code
/// !(a || b)
+/// \endcode
AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) {
TOOLING_COMPILE_ASSERT(
(llvm::is_base_of<BinaryOperator, NodeType>::value) ||
@@ -1678,7 +2164,9 @@ AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) {
/// \brief Matches the left hand side of binary operator expressions.
///
/// Example matches a (matcher = binaryOperator(hasLHS()))
+/// \code
/// a || b
+/// \endcode
AST_MATCHER_P(BinaryOperator, hasLHS,
internal::Matcher<Expr>, InnerMatcher) {
Expr *LeftHandSide = Node.getLHS();
@@ -1689,7 +2177,9 @@ AST_MATCHER_P(BinaryOperator, hasLHS,
/// \brief Matches the right hand side of binary operator expressions.
///
/// Example matches b (matcher = binaryOperator(hasRHS()))
+/// \code
/// a || b
+/// \endcode
AST_MATCHER_P(BinaryOperator, hasRHS,
internal::Matcher<Expr>, InnerMatcher) {
Expr *RightHandSide = Node.getRHS();
@@ -1706,8 +2196,10 @@ inline internal::Matcher<BinaryOperator> hasEitherOperand(
/// \brief Matches if the operand of a unary operator matches.
///
-/// Example matches true (matcher = hasOperand(boolLiteral(equals(true))))
+/// Example matches true (matcher = hasUnaryOperand(boolLiteral(equals(true))))
+/// \code
/// !true
+/// \endcode
AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
internal::Matcher<Expr>, InnerMatcher) {
const Expr * const Operand = Node.getSubExpr();
@@ -1718,8 +2210,8 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
/// \brief Matches if the cast's source expression matches the given matcher.
///
/// Example: matches "a string" (matcher =
-/// hasSourceExpression(constructorCall()))
-///
+/// hasSourceExpression(constructExpr()))
+/// \code
/// class URL { URL(string); };
/// URL url = "a string";
AST_MATCHER_P(CastExpr, hasSourceExpression,
@@ -1751,7 +2243,9 @@ AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType,
/// \brief Matches the true branch expression of a conditional operator.
///
/// Example matches a
+/// \code
/// condition ? a : b
+/// \endcode
AST_MATCHER_P(ConditionalOperator, hasTrueExpression,
internal::Matcher<Expr>, InnerMatcher) {
Expr *Expression = Node.getTrueExpr();
@@ -1762,7 +2256,9 @@ AST_MATCHER_P(ConditionalOperator, hasTrueExpression,
/// \brief Matches the false branch expression of a conditional operator.
///
/// Example matches b
+/// \code
/// condition ? a : b
+/// \endcode
AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
internal::Matcher<Expr>, InnerMatcher) {
Expr *Expression = Node.getFalseExpr();
@@ -1773,12 +2269,14 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
/// \brief Matches if a declaration has a body attached.
///
/// Example matches A, va, fa
+/// \code
/// class A {};
/// class B; // Doesn't match, as it has no body.
/// int va;
/// extern int vb; // Doesn't match, as it doesn't define the variable.
/// void fa() {}
/// void fb(); // Doesn't match, as it has no body.
+/// \endcode
///
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
inline internal::PolymorphicMatcherWithParam0<internal::IsDefinitionMatcher>
@@ -1795,13 +2293,15 @@ isDefinition() {
/// this to?
///
/// Example matches A() in the last line
-/// (matcher = constructorCall(hasDeclaration(method(
+/// (matcher = constructExpr(hasDeclaration(methodDecl(
/// ofClass(hasName("A"))))))
+/// \code
/// class A {
/// public:
/// A();
/// };
/// A a = A();
+/// \endcode
AST_MATCHER_P(CXXMethodDecl, ofClass,
internal::Matcher<CXXRecordDecl>, InnerMatcher) {
const CXXRecordDecl *Parent = Node.getParent();
@@ -1815,12 +2315,14 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
/// Member calls on the implicit this pointer match as called with '->'.
///
/// Given
+/// \code
/// class Y {
/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
/// int a;
/// static int b;
/// };
-/// memberExpression(isArrow())
+/// \endcode
+/// memberExpr(isArrow())
/// matches this->x, x, y.x, a, this->b
inline internal::Matcher<MemberExpr> isArrow() {
return makeMatcher(new internal::IsArrowMatcher());
@@ -1829,10 +2331,12 @@ inline internal::Matcher<MemberExpr> isArrow() {
/// \brief Matches QualType nodes that are of integer type.
///
/// Given
+/// \code
/// void a(int);
/// void b(long);
/// void c(double);
-/// function(hasAnyParameter(hasType(isInteger())))
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isInteger())))
/// matches "a(int)", "b(long)", but not "c(double)".
AST_MATCHER(QualType, isInteger) {
return Node->isIntegerType();
@@ -1842,12 +2346,14 @@ AST_MATCHER(QualType, isInteger) {
/// include "top-level" const.
///
/// Given
+/// \code
/// void a(int);
/// void b(int const);
/// void c(const int);
/// void d(const int*);
/// void e(int const) {};
-/// function(hasAnyParameter(hasType(isConstQualified())))
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isConstQualified())))
/// matches "void b(int const)", "void c(const int)" and
/// "void e(int const) {}". It does not match d as there
/// is no top-level const on the parameter type "const int *".
@@ -1859,10 +2365,12 @@ inline internal::Matcher<QualType> isConstQualified() {
/// given matcher.
///
/// Given
+/// \code
/// struct { int first, second; } first, second;
/// int i(second.first);
/// int j(first.second);
-/// memberExpression(member(hasName("first")))
+/// \endcode
+/// memberExpr(member(hasName("first")))
/// matches second.first
/// but not first.second (because the member name there is "second").
AST_MATCHER_P(MemberExpr, member,
@@ -1874,9 +2382,11 @@ AST_MATCHER_P(MemberExpr, member,
/// matched by a given matcher.
///
/// Given
+/// \code
/// struct X { int m; };
/// void f(X x) { x.m; m; }
-/// memberExpression(hasObjectExpression(hasType(record(hasName("X")))))))
+/// \endcode
+/// memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))))
/// matches "x.m" and "m"
/// with hasObjectExpression(...)
/// matching "x" and the implicit object expression of "m" which has type X*.
@@ -1888,15 +2398,17 @@ AST_MATCHER_P(MemberExpr, hasObjectExpression,
/// \brief Matches any using shadow declaration.
///
/// Given
+/// \code
/// namespace X { void b(); }
/// using X::b;
+/// \endcode
/// usingDecl(hasAnyUsingShadowDecl(hasName("b"))))
/// matches \code using X::b \endcode
AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl,
- internal::Matcher<UsingShadowDecl>, Matcher) {
+ internal::Matcher<UsingShadowDecl>, InnerMatcher) {
for (UsingDecl::shadow_iterator II = Node.shadow_begin();
II != Node.shadow_end(); ++II) {
- if (Matcher.matches(**II, Finder, Builder))
+ if (InnerMatcher.matches(**II, Finder, Builder))
return true;
}
return false;
@@ -1906,31 +2418,39 @@ AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl,
/// matched by the given matcher.
///
/// Given
+/// \code
/// namespace X { int a; void b(); }
/// using X::a;
/// using X::b;
-/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(function())))
+/// \endcode
+/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl())))
/// matches \code using X::b \endcode
/// but not \code using X::a \endcode
AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
- internal::Matcher<NamedDecl>, Matcher) {
- return Matcher.matches(*Node.getTargetDecl(), Finder, Builder);
+ internal::Matcher<NamedDecl>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getTargetDecl(), Finder, Builder);
}
/// \brief Matches template instantiations of function, class, or static
/// member variable template instantiations.
///
/// Given
+/// \code
/// template <typename T> class X {}; class A {}; X<A> x;
+/// \endcode
/// or
+/// \code
/// template <typename T> class X {}; class A {}; template class X<A>;
-/// record(hasName("::X"), isTemplateInstantiation())
+/// \endcode
+/// recordDecl(hasName("::X"), isTemplateInstantiation())
/// matches the template instantiation of X<A>.
///
/// But given
-/// template <typename T> class X {}; class A {};
+/// \code
+/// template <typename T> class X {}; class A {};
/// template <> class X<A> {}; X<A> x;
-/// record(hasName("::X"), isTemplateInstantiation())
+/// \endcode
+/// recordDecl(hasName("::X"), isTemplateInstantiation())
/// does not match, as X<A> is an explicit template specialization.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
@@ -1941,6 +2461,411 @@ isTemplateInstantiation() {
internal::IsTemplateInstantiationMatcher>();
}
+/// \brief Matches explicit template specializations of function, class, or
+/// static member variable template instantiations.
+///
+/// Given
+/// \code
+/// template<typename T> void A(T t) { }
+/// template<> void A(int N) { }
+/// \endcode
+/// functionDecl(isExplicitTemplateSpecialization())
+/// matches the specialization A<int>().
+///
+/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
+inline internal::PolymorphicMatcherWithParam0<
+ internal::IsExplicitTemplateSpecializationMatcher>
+isExplicitTemplateSpecialization() {
+ return internal::PolymorphicMatcherWithParam0<
+ internal::IsExplicitTemplateSpecializationMatcher>();
+}
+
+/// \brief Matches \c TypeLocs for which the given inner
+/// QualType-matcher matches.
+inline internal::BindableMatcher<TypeLoc> loc(
+ const internal::Matcher<QualType> &InnerMatcher) {
+ return internal::BindableMatcher<TypeLoc>(
+ new internal::TypeLocTypeMatcher(InnerMatcher));
+}
+
+/// \brief Matches builtin Types.
+///
+/// Given
+/// \code
+/// struct A {};
+/// A a;
+/// int b;
+/// float c;
+/// bool d;
+/// \endcode
+/// builtinType()
+/// matches "int b", "float c" and "bool d"
+AST_TYPE_MATCHER(BuiltinType, builtinType);
+
+/// \brief Matches all kinds of arrays.
+///
+/// Given
+/// \code
+/// int a[] = { 2, 3 };
+/// int b[4];
+/// void f() { int c[a[0]]; }
+/// \endcode
+/// arrayType()
+/// matches "int a[]", "int b[4]" and "int c[a[0]]";
+AST_TYPE_MATCHER(ArrayType, arrayType);
+
+/// \brief Matches C99 complex types.
+///
+/// Given
+/// \code
+/// _Complex float f;
+/// \endcode
+/// complexType()
+/// matches "_Complex float f"
+AST_TYPE_MATCHER(ComplexType, complexType);
+
+/// \brief Matches arrays and C99 complex types that have a specific element
+/// type.
+///
+/// Given
+/// \code
+/// struct A {};
+/// A a[7];
+/// int b[7];
+/// \endcode
+/// arrayType(hasElementType(builtinType()))
+/// matches "int b[7]"
+///
+/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
+AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement);
+
+/// \brief Matches C arrays with a specified constant size.
+///
+/// Given
+/// \code
+/// void() {
+/// int a[2];
+/// int b[] = { 2, 3 };
+/// int c[b[0]];
+/// }
+/// \endcode
+/// constantArrayType()
+/// matches "int a[2]"
+AST_TYPE_MATCHER(ConstantArrayType, constantArrayType);
+
+/// \brief Matches \c ConstantArrayType nodes that have the specified size.
+///
+/// Given
+/// \code
+/// int a[42];
+/// int b[2 * 21];
+/// int c[41], d[43];
+/// \endcode
+/// constantArrayType(hasSize(42))
+/// matches "int a[42]" and "int b[2 * 21]"
+AST_MATCHER_P(ConstantArrayType, hasSize, unsigned, N) {
+ return Node.getSize() == N;
+}
+
+/// \brief Matches C++ arrays whose size is a value-dependent expression.
+///
+/// Given
+/// \code
+/// template<typename T, int Size>
+/// class array {
+/// T data[Size];
+/// };
+/// \endcode
+/// dependentSizedArrayType
+/// matches "T data[Size]"
+AST_TYPE_MATCHER(DependentSizedArrayType, dependentSizedArrayType);
+
+/// \brief Matches C arrays with unspecified size.
+///
+/// Given
+/// \code
+/// int a[] = { 2, 3 };
+/// int b[42];
+/// void f(int c[]) { int d[a[0]]; };
+/// \endcode
+/// incompleteArrayType()
+/// matches "int a[]" and "int c[]"
+AST_TYPE_MATCHER(IncompleteArrayType, incompleteArrayType);
+
+/// \brief Matches C arrays with a specified size that is not an
+/// integer-constant-expression.
+///
+/// Given
+/// \code
+/// void f() {
+/// int a[] = { 2, 3 }
+/// int b[42];
+/// int c[a[0]];
+/// \endcode
+/// variableArrayType()
+/// matches "int c[a[0]]"
+AST_TYPE_MATCHER(VariableArrayType, variableArrayType);
+
+/// \brief Matches \c VariableArrayType nodes that have a specific size
+/// expression.
+///
+/// Given
+/// \code
+/// void f(int b) {
+/// int a[b];
+/// }
+/// \endcode
+/// variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+/// varDecl(hasName("b")))))))
+/// matches "int a[b]"
+AST_MATCHER_P(VariableArrayType, hasSizeExpr,
+ internal::Matcher<Expr>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getSizeExpr(), Finder, Builder);
+}
+
+/// \brief Matches atomic types.
+///
+/// Given
+/// \code
+/// _Atomic(int) i;
+/// \endcode
+/// atomicType()
+/// matches "_Atomic(int) i"
+AST_TYPE_MATCHER(AtomicType, atomicType);
+
+/// \brief Matches atomic types with a specific value type.
+///
+/// Given
+/// \code
+/// _Atomic(int) i;
+/// _Atomic(float) f;
+/// \endcode
+/// atomicType(hasValueType(isInteger()))
+/// matches "_Atomic(int) i"
+///
+/// Usable as: Matcher<AtomicType>
+AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue);
+
+/// \brief Matches types nodes representing C++11 auto types.
+///
+/// Given:
+/// \code
+/// auto n = 4;
+/// int v[] = { 2, 3 }
+/// for (auto i : v) { }
+/// \endcode
+/// autoType()
+/// matches "auto n" and "auto i"
+AST_TYPE_MATCHER(AutoType, autoType);
+
+/// \brief Matches \c AutoType nodes where the deduced type is a specific type.
+///
+/// Note: There is no \c TypeLoc for the deduced type and thus no
+/// \c getDeducedLoc() matcher.
+///
+/// Given
+/// \code
+/// auto a = 1;
+/// auto b = 2.0;
+/// \endcode
+/// autoType(hasDeducedType(isInteger()))
+/// matches "auto a"
+///
+/// Usable as: Matcher<AutoType>
+AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
+
+/// \brief Matches \c FunctionType nodes.
+///
+/// Given
+/// \code
+/// int (*f)(int);
+/// void g();
+/// \endcode
+/// functionType()
+/// matches "int (*f)(int)" and the type of "g".
+AST_TYPE_MATCHER(FunctionType, functionType);
+
+/// \brief Matches block pointer types, i.e. types syntactically represented as
+/// "void (^)(int)".
+///
+/// The \c pointee is always required to be a \c FunctionType.
+AST_TYPE_MATCHER(BlockPointerType, blockPointerType);
+
+/// \brief Matches member pointer types.
+/// Given
+/// \code
+/// struct A { int i; }
+/// A::* ptr = A::i;
+/// \endcode
+/// memberPointerType()
+/// matches "A::* ptr"
+AST_TYPE_MATCHER(MemberPointerType, memberPointerType);
+
+/// \brief Matches pointer types.
+///
+/// Given
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int c = 5;
+/// \endcode
+/// pointerType()
+/// matches "int *a"
+AST_TYPE_MATCHER(PointerType, pointerType);
+
+/// \brief Matches reference types.
+///
+/// Given
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int c = 5;
+/// \endcode
+/// pointerType()
+/// matches "int &b"
+AST_TYPE_MATCHER(ReferenceType, referenceType);
+
+/// \brief Narrows PointerType (and similar) matchers to those where the
+/// \c pointee matches a given matcher.
+///
+/// Given
+/// \code
+/// int *a;
+/// int const *b;
+/// float const *f;
+/// \endcode
+/// pointerType(pointee(isConstQualified(), isInteger()))
+/// matches "int const *b"
+///
+/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
+/// Matcher<PointerType>, Matcher<ReferenceType>
+AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
+
+/// \brief Matches typedef types.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// \endcode
+/// typedefType()
+/// matches "typedef int X"
+AST_TYPE_MATCHER(TypedefType, typedefType);
+
+/// \brief Matches \c TypedefTypes referring to a specific
+/// \c TypedefNameDecl.
+AST_MATCHER_P(TypedefType, hasDecl,
+ internal::Matcher<TypedefNameDecl>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getDecl(), Finder, Builder);
+}
+
+/// \brief Matches nested name specifiers.
+///
+/// Given
+/// \code
+/// namespace ns {
+/// struct A { static void f(); };
+/// void A::f() {}
+/// void g() { A::f(); }
+/// }
+/// ns::A a;
+/// \endcode
+/// nestedNameSpecifier()
+/// matches "ns::" and both "A::"
+const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
+
+/// \brief Same as \c nestedNameSpecifier but matches \c NestedNameSpecifierLoc.
+const internal::VariadicAllOfMatcher<
+ NestedNameSpecifierLoc> nestedNameSpecifierLoc;
+
+/// \brief Matches \c NestedNameSpecifierLocs for which the given inner
+/// NestedNameSpecifier-matcher matches.
+inline internal::BindableMatcher<NestedNameSpecifierLoc> loc(
+ const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
+ return internal::BindableMatcher<NestedNameSpecifierLoc>(
+ new internal::LocMatcher<NestedNameSpecifierLoc, NestedNameSpecifier>(
+ InnerMatcher));
+}
+
+/// \brief Matches nested name specifiers that specify a type matching the
+/// given \c QualType matcher without qualifiers.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
+/// nestedNameSpecifier(specifiesType(hasDeclaration(recordDecl(hasName("A")))))
+/// matches "A::"
+AST_MATCHER_P(NestedNameSpecifier, specifiesType,
+ internal::Matcher<QualType>, InnerMatcher) {
+ if (Node.getAsType() == NULL)
+ return false;
+ return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder);
+}
+
+/// \brief Matches nested name specifier locs that specify a type matching the
+/// given \c TypeLoc.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
+/// nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
+/// hasDeclaration(recordDecl(hasName("A")))))))
+/// matches "A::"
+AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
+ internal::Matcher<TypeLoc>, InnerMatcher) {
+ return InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
+}
+
+/// \brief Matches on the prefix of a \c NestedNameSpecifier.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
+/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
+/// matches "A::"
+inline internal::Matcher<NestedNameSpecifier> hasPrefix(
+ const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
+ return internal::makeMatcher(
+ new internal::NestedNameSpecifierPrefixMatcher(InnerMatcher));
+}
+
+/// \brief Matches on the prefix of a \c NestedNameSpecifierLoc.
+///
+/// Given
+/// \code
+/// struct A { struct B { struct C {}; }; };
+/// A::B::C c;
+/// \endcode
+/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
+/// matches "A::"
+inline internal::Matcher<NestedNameSpecifierLoc> hasPrefix(
+ const internal::Matcher<NestedNameSpecifierLoc> &InnerMatcher) {
+ return internal::makeMatcher(
+ new internal::NestedNameSpecifierLocPrefixMatcher(InnerMatcher));
+}
+
+/// \brief Matches nested name specifiers that specify a namespace matching the
+/// given namespace matcher.
+///
+/// Given
+/// \code
+/// namespace ns { struct A {}; }
+/// ns::A a;
+/// \endcode
+/// nestedNameSpecifier(specifiesNamespace(hasName("ns")))
+/// matches "ns::"
+AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
+ internal::Matcher<NamespaceDecl>, InnerMatcher) {
+ if (Node.getAsNamespace() == NULL)
+ return false;
+ return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 3f5568521c0e..e5365ff89d72 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -39,7 +39,11 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTTypeTraits.h"
#include "llvm/ADT/VariadicFunction.h"
+#include "llvm/Support/type_traits.h"
#include <map>
#include <string>
#include <vector>
@@ -57,6 +61,45 @@ class BoundNodes;
namespace internal {
class BoundNodesTreeBuilder;
+/// \brief Internal version of BoundNodes. Holds all the bound nodes.
+class BoundNodesMap {
+public:
+ /// \brief Adds \c Node to the map with key \c ID.
+ ///
+ /// The node's base type should be in NodeBaseType or it will be unaccessible.
+ template <typename T>
+ 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.
+ ///
+ /// Returns NULL if there was no node bound to \c ID or if there is a node but
+ /// it cannot be converted to the specified type.
+ template <typename T>
+ const T *getNodeAs(StringRef ID) const {
+ IDToNodeMap::const_iterator It = NodeMap.find(ID);
+ if (It == NodeMap.end()) {
+ return NULL;
+ }
+ return It->second.get<T>();
+ }
+
+ /// \brief Copies all ID/Node pairs to BoundNodesTreeBuilder \c Builder.
+ void copyTo(BoundNodesTreeBuilder *Builder) const;
+
+ /// \brief Copies all ID/Node pairs to BoundNodesMap \c Other.
+ void copyTo(BoundNodesMap *Other) const;
+
+private:
+ /// \brief A map from IDs to the bound nodes.
+ typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap;
+
+ IDToNodeMap NodeMap;
+};
/// \brief A tree of bound nodes in match results.
///
@@ -84,11 +127,10 @@ public:
BoundNodesTree();
/// \brief Create a BoundNodesTree from pre-filled maps of bindings.
- BoundNodesTree(const std::map<std::string, const Decl*>& DeclBindings,
- const std::map<std::string, const Stmt*>& StmtBindings,
+ BoundNodesTree(const BoundNodesMap& Bindings,
const std::vector<BoundNodesTree> RecursiveBindings);
- /// \brief Adds all bound nodes to bound_nodes_builder.
+ /// \brief Adds all bound nodes to \c Builder.
void copyTo(BoundNodesTreeBuilder* Builder) const;
/// \brief Visits all matches that this BoundNodesTree represents.
@@ -99,17 +141,12 @@ public:
private:
void visitMatchesRecursively(
Visitor* ResultVistior,
- std::map<std::string, const Decl*> DeclBindings,
- std::map<std::string, const Stmt*> StmtBindings);
-
- template <typename T>
- void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
+ const BoundNodesMap& AggregatedBindings);
// FIXME: Find out whether we want to use different data structures here -
// first benchmarks indicate that it doesn't matter though.
- std::map<std::string, const Decl*> DeclBindings;
- std::map<std::string, const Stmt*> StmtBindings;
+ BoundNodesMap Bindings;
std::vector<BoundNodesTree> RecursiveBindings;
};
@@ -123,12 +160,13 @@ public:
BoundNodesTreeBuilder();
/// \brief Add a binding from an id to a node.
- ///
- /// FIXME: Add overloads for all AST base types.
- /// @{
- void setBinding(const std::string &Id, const Decl *Node);
- void setBinding(const std::string &Id, const Stmt *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);
+ }
/// \brief Adds a branch in the tree.
void addMatch(const BoundNodesTree& Bindings);
@@ -137,11 +175,10 @@ public:
BoundNodesTree build() const;
private:
- BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
- void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
+ BoundNodesTreeBuilder(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
+ void operator=(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
- std::map<std::string, const Decl*> DeclBindings;
- std::map<std::string, const Stmt*> StmtBindings;
+ BoundNodesMap Bindings;
std::vector<BoundNodesTree> RecursiveBindings;
};
@@ -169,7 +206,8 @@ public:
BoundNodesTreeBuilder *Builder) const = 0;
};
-/// \brief Interface for matchers that only evaluate properties on a single node.
+/// \brief Interface for matchers that only evaluate properties on a single
+/// node.
template <typename T>
class SingleNodeMatcherInterface : public MatcherInterface<T> {
public:
@@ -187,6 +225,24 @@ 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
@@ -196,12 +252,32 @@ private:
/// operator rather than a type hierarchy to be able to templatize the
/// type hierarchy instead of spelling it out.
template <typename T>
-class Matcher {
+class Matcher : public DynTypedMatcher {
public:
/// \brief Takes ownership of the provided implementation pointer.
explicit Matcher(MatcherInterface<T> *Implementation)
: Implementation(Implementation) {}
+ /// \brief Implicitly converts \c Other to a Matcher<T>.
+ ///
+ /// Requires \c T to be derived from \c From.
+ template <typename From>
+ Matcher(const Matcher<From> &Other,
+ typename llvm::enable_if_c<
+ llvm::is_base_of<From, T>::value &&
+ !llvm::is_same<From, T>::value >::type* = 0)
+ : Implementation(new ImplicitCastMatcher<From>(Other)) {}
+
+ /// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
+ ///
+ /// The resulting matcher is not strict, i.e. ignores qualifiers.
+ template <typename TypeT>
+ Matcher(const Matcher<TypeT> &Other,
+ typename llvm::enable_if_c<
+ llvm::is_same<T, QualType>::value &&
+ llvm::is_same<TypeT, Type>::value >::type* = 0)
+ : Implementation(new TypeToQualType<TypeT>(Other)) {}
+
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
@@ -209,14 +285,6 @@ public:
return Implementation->matches(Node, Finder, Builder);
}
- /// \brief Implicitly converts this object to a Matcher<Derived>.
- ///
- /// Requires Derived to be derived from T.
- template <typename Derived>
- operator Matcher<Derived>() const {
- return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
- }
-
/// \brief Returns an ID that uniquely identifies the matcher.
uint64_t getID() const {
/// FIXME: Document the requirements this imposes on matcher
@@ -224,23 +292,55 @@ 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>.
+ ///
+ /// Depending on the constructor argument, the matcher is either strict, i.e.
+ /// does only matches in the absence of qualifiers, or not, i.e. simply
+ /// ignores any qualifiers.
+ template <typename TypeT>
+ class TypeToQualType : public MatcherInterface<QualType> {
+ public:
+ TypeToQualType(const Matcher<TypeT> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const QualType &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (Node.isNull())
+ return false;
+ return InnerMatcher.matches(*Node, Finder, Builder);
+ }
+ private:
+ const Matcher<TypeT> InnerMatcher;
+ };
+
private:
- /// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
- /// is derived from T.
- template <typename Derived>
- class ImplicitCastMatcher : public MatcherInterface<Derived> {
+ /// \brief Allows conversion from Matcher<Base> to Matcher<T> if T
+ /// is derived from Base.
+ template <typename Base>
+ class ImplicitCastMatcher : public MatcherInterface<T> {
public:
- explicit ImplicitCastMatcher(const Matcher<T> &From)
+ explicit ImplicitCastMatcher(const Matcher<Base> &From)
: From(From) {}
- virtual bool matches(const Derived &Node,
+ virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return From.matches(Node, Finder, Builder);
}
private:
- const Matcher<T> From;
+ const Matcher<Base> From;
};
llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
@@ -280,18 +380,14 @@ private:
/// FIXME: Add other ways to convert...
if (Node.isNull())
return false;
- CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
- return NodeAsRecordDecl != NULL &&
- InnerMatcher.matches(*NodeAsRecordDecl, Finder, Builder);
+ return matchesDecl(Node->getAsCXXRecordDecl(), Finder, Builder);
}
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
/// the inner matcher matches on it.
bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- const Decl *NodeAsDecl = Node.getCalleeDecl();
- return NodeAsDecl != NULL &&
- InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
+ return matchesDecl(Node.getCalleeDecl(), Finder, Builder);
}
/// \brief Extracts the Decl of the constructor call and returns whether the
@@ -299,96 +395,63 @@ private:
bool matchesSpecialized(const CXXConstructExpr &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- const Decl *NodeAsDecl = Node.getConstructor();
- return NodeAsDecl != NULL &&
- InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
+ return matchesDecl(Node.getConstructor(), Finder, Builder);
+ }
+
+ /// \brief Extracts the \c ValueDecl a \c MemberExpr refers to and returns
+ /// whether the inner matcher matches on it.
+ bool matchesSpecialized(const MemberExpr &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return matchesDecl(Node.getMemberDecl(), Finder, Builder);
+ }
+
+ /// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
+ /// is \c NULL.
+ bool matchesDecl(const Decl *Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Node != NULL && InnerMatcher.matches(*Node, Finder, Builder);
}
const Matcher<Decl> InnerMatcher;
};
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
-/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
+/// node class hierarchies.
template <typename T>
struct IsBaseType {
static const bool value =
(llvm::is_same<T, Decl>::value ||
llvm::is_same<T, Stmt>::value ||
llvm::is_same<T, QualType>::value ||
+ llvm::is_same<T, Type>::value ||
+ llvm::is_same<T, TypeLoc>::value ||
+ llvm::is_same<T, NestedNameSpecifier>::value ||
+ llvm::is_same<T, NestedNameSpecifierLoc>::value ||
llvm::is_same<T, CXXCtorInitializer>::value);
};
template <typename T>
const bool IsBaseType<T>::value;
-/// \brief Interface that can match any AST base node type and contains default
-/// implementations returning false.
-class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
-public:
- virtual ~UntypedBaseMatcher() {}
-
- virtual bool matches(const Decl &DeclNode, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return false;
- }
- virtual bool matches(const QualType &TypeNode, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return false;
- }
- virtual bool matches(const Stmt &StmtNode, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return false;
- }
- virtual bool matches(const CXXCtorInitializer &CtorInitNode,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return false;
- }
-
- /// \brief Returns a unique ID for the matcher.
- virtual uint64_t getID() const = 0;
-};
-
-/// \brief An UntypedBaseMatcher that overwrites the Matches(...) method for
-/// node type T. T must be an AST base type.
-template <typename T>
-class TypedBaseMatcher : public UntypedBaseMatcher {
- TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
- typed_base_matcher_can_only_be_used_with_base_type);
-public:
- explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
-
- using UntypedBaseMatcher::matches;
- /// \brief Implements UntypedBaseMatcher::Matches.
- ///
- /// Since T is guaranteed to be a "base" AST node type, this method is
- /// guaranteed to override one of the matches() methods from
- /// UntypedBaseMatcher.
- virtual bool matches(const T &Node,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return InnerMatcher.matches(Node, Finder, Builder);
- }
-
- /// \brief Implements UntypedBaseMatcher::getID.
- virtual uint64_t getID() const {
- return InnerMatcher.getID();
- }
-
-private:
- Matcher<T> InnerMatcher;
-};
-
/// \brief Interface that allows matchers to traverse the AST.
/// FIXME: Find a better name.
///
-/// This provides two entry methods for each base node type in the AST:
-/// - matchesChildOf:
+/// This provides three entry methods for each base node type in the AST:
+/// - \c matchesChildOf:
/// Matches a matcher on every child node of the given node. Returns true
/// if at least one child node could be matched.
-/// - matchesDescendantOf:
+/// - \c matchesDescendantOf:
/// Matches a matcher on all descendant nodes of the given node. Returns true
/// if at least one descendant matched.
+/// - \c matchesAncestorOf:
+/// Matches a matcher on all ancestors of the given node. Returns true if
+/// at least one ancestor matched.
+///
+/// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal.
+/// In the future, we wan to implement this for all nodes for which it makes
+/// sense. In the case of matchesAncestorOf, we'll want to implement it for
+/// all nodes, as all nodes have ancestors.
class ASTMatchFinder {
public:
/// \brief Defines how we descend a level in the AST when we pass
@@ -408,6 +471,14 @@ public:
BK_All
};
+ /// \brief Defines which ancestors are considered for a match.
+ enum AncestorMatchMode {
+ /// All ancestors.
+ AMM_All,
+ /// Direct parent only.
+ AMM_ParentOnly
+ };
+
virtual ~ASTMatchFinder() {}
/// \brief Returns true if the given class is directly or indirectly derived
@@ -418,26 +489,70 @@ public:
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder) = 0;
- // FIXME: Implement for other base nodes.
- virtual bool matchesChildOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- TraversalKind Traverse,
- BindKind Bind) = 0;
- virtual bool matchesChildOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
+ template <typename T>
+ bool matchesChildOf(const T &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traverse,
+ BindKind Bind) {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<Decl, T>::value ||
+ llvm::is_base_of<Stmt, T>::value ||
+ llvm::is_base_of<NestedNameSpecifier, T>::value ||
+ llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
+ llvm::is_base_of<TypeLoc, T>::value ||
+ llvm::is_base_of<QualType, T>::value),
+ unsupported_type_for_recursive_matching);
+ return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
+ Matcher, Builder, Traverse, Bind);
+ }
+
+ template <typename T>
+ bool matchesDescendantOf(const T &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ BindKind Bind) {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<Decl, T>::value ||
+ llvm::is_base_of<Stmt, T>::value ||
+ llvm::is_base_of<NestedNameSpecifier, T>::value ||
+ llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
+ llvm::is_base_of<TypeLoc, T>::value ||
+ llvm::is_base_of<QualType, T>::value),
+ unsupported_type_for_recursive_matching);
+ return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node),
+ Matcher, Builder, Bind);
+ }
+
+ // FIXME: Implement support for BindKind.
+ template <typename T>
+ bool matchesAncestorOf(const T &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
+ llvm::is_base_of<Stmt, T>::value),
+ only_Decl_or_Stmt_allowed_for_recursive_matching);
+ return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
+ Matcher, Builder, MatchMode);
+ }
+
+protected:
+ virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traverse,
BindKind Bind) = 0;
- virtual bool matchesDescendantOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- BindKind Bind) = 0;
- virtual bool matchesDescendantOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
+ virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) = 0;
+
+ virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) = 0;
};
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
@@ -606,9 +721,6 @@ public:
/// The returned matcher is equivalent to this matcher, but will
/// bind the matched node on a match.
Matcher<T> bind(StringRef ID) const {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, T>::value ||
- llvm::is_base_of<Decl, T>::value),
- trying_to_bind_unsupported_node_type__only_decl_and_stmt_supported);
return Matcher<T>(new IdMatcher<T>(ID, *this));
}
};
@@ -635,7 +747,7 @@ public:
}
private:
- const TypedBaseMatcher<ChildT> ChildMatcher;
+ const Matcher<ChildT> ChildMatcher;
};
/// \brief Matches nodes of type T that have child nodes of type ChildT for
@@ -661,7 +773,7 @@ class ForEachMatcher : public MatcherInterface<T> {
}
private:
- const TypedBaseMatcher<ChildT> ChildMatcher;
+ const Matcher<ChildT> ChildMatcher;
};
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
@@ -733,6 +845,20 @@ private:
const Matcher<T> InnertMatcher2;
};
+/// \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);
+}
+
/// \brief Creates a Matcher<T> that matches if
/// T is dyn_cast'able into InnerT and all inner matchers match.
///
@@ -742,17 +868,8 @@ private:
template<typename T, typename InnerT>
BindableMatcher<T> makeDynCastAllOfComposite(
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
- if (InnerMatchers.empty()) {
- Matcher<InnerT> InnerMatcher = makeMatcher(new TrueMatcher<InnerT>);
- return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
- }
- Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
- for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
- InnerMatcher = makeMatcher(
- new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
- *InnerMatchers[i], InnerMatcher));
- }
- return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
+ return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(
+ makeAllOfComposite(InnerMatchers)));
}
/// \brief Matches nodes of type T that have at least one descendant node of
@@ -775,7 +892,53 @@ public:
}
private:
- const TypedBaseMatcher<DescendantT> DescendantMatcher;
+ const Matcher<DescendantT> DescendantMatcher;
+};
+
+/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT
+/// for which the given inner matcher matches.
+///
+/// \c ParentT must be an AST base type.
+template <typename T, typename ParentT>
+class HasParentMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<ParentT>::value,
+ has_parent_only_accepts_base_type_matcher);
+public:
+ explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
+ : ParentMatcher(ParentMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Finder->matchesAncestorOf(
+ Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
+ }
+
+ private:
+ const Matcher<ParentT> ParentMatcher;
+};
+
+/// \brief Matches nodes of type \c T that have at least one ancestor node of
+/// type \c AncestorT for which the given inner matcher matches.
+///
+/// \c AncestorT must be an AST base type.
+template <typename T, typename AncestorT>
+class HasAncestorMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<AncestorT>::value,
+ has_ancestor_only_accepts_base_type_matcher);
+public:
+ explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher)
+ : AncestorMatcher(AncestorMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Finder->matchesAncestorOf(
+ Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
+ }
+
+ private:
+ const Matcher<AncestorT> AncestorMatcher;
};
/// \brief Matches nodes of type T that have at least one descendant node of
@@ -801,7 +964,7 @@ class ForEachDescendantMatcher : public MatcherInterface<T> {
}
private:
- const TypedBaseMatcher<DescendantT> DescendantMatcher;
+ const Matcher<DescendantT> DescendantMatcher;
};
/// \brief Matches on nodes that have a getValue() method if getValue() equals
@@ -858,6 +1021,22 @@ class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
}
};
+/// \brief Matches on explicit template specializations for FunctionDecl,
+/// VarDecl or CXXRecordDecl nodes.
+template <typename T>
+class IsExplicitTemplateSpecializationMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
+ (llvm::is_base_of<VarDecl, T>::value) ||
+ (llvm::is_base_of<CXXRecordDecl, T>::value),
+ requires_getTemplateSpecializationKind_method);
+ public:
+ virtual bool matches(const T& Node,
+ ASTMatchFinder* Finder,
+ BoundNodesTreeBuilder* Builder) const {
+ return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
+ }
+};
+
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
public:
virtual bool matchesNode(const MemberExpr &Node) const {
@@ -894,6 +1073,166 @@ public:
VariadicDynCastAllOfMatcher() {}
};
+/// \brief A \c VariadicAllOfMatcher<T> object is a variadic functor that takes
+/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T
+/// nodes that are matched by all of the given matchers.
+///
+/// For example:
+/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
+/// Creates a functor nestedNameSpecifier(...) that creates a
+/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type
+/// \c Matcher<NestedNameSpecifier>.
+/// The returned matcher matches if all given matchers match.
+template <typename T>
+class VariadicAllOfMatcher : public llvm::VariadicFunction<
+ BindableMatcher<T>, Matcher<T>,
+ makeAllOfComposite<T> > {
+public:
+ VariadicAllOfMatcher() {}
+};
+
+/// \brief Matches nodes of type \c TLoc for which the inner
+/// \c Matcher<T> matches.
+template <typename TLoc, typename T>
+class LocMatcher : public MatcherInterface<TLoc> {
+public:
+ explicit LocMatcher(const Matcher<T> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const TLoc &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (!Node)
+ return false;
+ return InnerMatcher.matches(*extract(Node), Finder, Builder);
+ }
+
+private:
+ const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
+ return Loc.getNestedNameSpecifier();
+ }
+
+ const Matcher<T> InnerMatcher;
+};
+
+/// \brief Matches \c NestedNameSpecifiers with a prefix matching another
+/// \c Matcher<NestedNameSpecifier>.
+class NestedNameSpecifierPrefixMatcher
+ : public MatcherInterface<NestedNameSpecifier> {
+public:
+ explicit NestedNameSpecifierPrefixMatcher(
+ const Matcher<NestedNameSpecifier> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const NestedNameSpecifier &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ NestedNameSpecifier *NextNode = Node.getPrefix();
+ if (NextNode == NULL)
+ return false;
+ return InnerMatcher.matches(*NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<NestedNameSpecifier> InnerMatcher;
+};
+
+/// \brief Matches \c NestedNameSpecifierLocs with a prefix matching another
+/// \c Matcher<NestedNameSpecifierLoc>.
+class NestedNameSpecifierLocPrefixMatcher
+ : public MatcherInterface<NestedNameSpecifierLoc> {
+public:
+ explicit NestedNameSpecifierLocPrefixMatcher(
+ const Matcher<NestedNameSpecifierLoc> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const NestedNameSpecifierLoc &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ NestedNameSpecifierLoc NextNode = Node.getPrefix();
+ if (!NextNode)
+ return false;
+ return InnerMatcher.matches(NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<NestedNameSpecifierLoc> InnerMatcher;
+};
+
+/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
+/// \c QualType.
+///
+/// Used to implement the \c loc() matcher.
+class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
+public:
+ explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const TypeLoc &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ if (!Node)
+ return false;
+ return InnerMatcher.matches(Node.getType(), Finder, Builder);
+ }
+
+private:
+ const Matcher<QualType> InnerMatcher;
+};
+
+/// \brief Matches nodes of type \c T for which the inner matcher matches on a
+/// another node of type \c T that can be reached using a given traverse
+/// function.
+template <typename T>
+class TypeTraverseMatcher : public MatcherInterface<T> {
+public:
+ explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher,
+ QualType (T::*TraverseFunction)() const)
+ : InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ QualType NextNode = (Node.*TraverseFunction)();
+ if (NextNode.isNull())
+ return false;
+ return InnerMatcher.matches(NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<QualType> InnerMatcher;
+ QualType (T::*TraverseFunction)() const;
+};
+
+/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner
+/// matcher matches on a another node of type \c T that can be reached using a
+/// given traverse function.
+template <typename T>
+class TypeLocTraverseMatcher : public MatcherInterface<T> {
+public:
+ explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher,
+ TypeLoc (T::*TraverseFunction)() const)
+ : InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ TypeLoc NextNode = (Node.*TraverseFunction)();
+ if (!NextNode)
+ return false;
+ return InnerMatcher.matches(NextNode, Finder, Builder);
+ }
+
+private:
+ const Matcher<TypeLoc> InnerMatcher;
+ TypeLoc (T::*TraverseFunction)() const;
+};
+
+template <typename T, typename InnerT>
+T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
+ return T(makeAllOfComposite<InnerT>(InnerMatchers));
+}
+
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index c68534acae35..953abc2a2ec9 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -221,4 +221,69 @@
const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
+/// \brief Creates a variadic matcher for both a specific \c Type as well as
+/// the corresponding \c TypeLoc.
+#define AST_TYPE_MATCHER(NodeType, MatcherName) \
+ const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName; \
+ const internal::VariadicDynCastAllOfMatcher<TypeLoc, \
+ NodeType##Loc> MatcherName##Loc
+
+/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
+/// the matcher \c MatcherName that can be used to traverse from one \c Type
+/// to another.
+///
+/// For a specific \c SpecificType, the traversal is done using
+/// \c SpecificType::FunctionName. The existance 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() {} \
+}; \
+const Variadic##MatcherName##TypeTraverseMatcher 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() {} \
+}; \
+const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
+AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
+
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
diff --git a/include/clang/ASTMatchers/ASTTypeTraits.h b/include/clang/ASTMatchers/ASTTypeTraits.h
new file mode 100644
index 000000000000..bda53eaf70f6
--- /dev/null
+++ b/include/clang/ASTMatchers/ASTTypeTraits.h
@@ -0,0 +1,209 @@
+//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/Support/AlignOf.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+/// \brief A dynamically typed AST node container.
+///
+/// Stores an AST node in a type safe way. This allows writing code that
+/// works with different kinds of AST nodes, despite the fact that they don't
+/// have a common base class.
+///
+/// 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;
+/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
+/// the supported base types.
+class DynTypedNode {
+public:
+ /// \brief Creates a \c DynTypedNode from \c Node.
+ template <typename T>
+ static DynTypedNode create(const T &Node) {
+ return BaseConverter<T>::create(Node);
+ }
+
+ /// \brief Retrieve the stored node as type \c T.
+ ///
+ /// Returns NULL if the stored node does not have a type that is
+ /// 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.
+ /// 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);
+ }
+
+ /// \brief Returns a pointer that identifies the stored AST node.
+ ///
+ /// Note that this is not supported by all AST nodes. For AST nodes
+ /// that don't have a pointer-defined identity inside the AST, this
+ /// method returns NULL.
+ const void *getMemoizationData() const;
+
+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 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
+ /// pointers and thus need to be stored by value.
+ llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
+ 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;
+ }
+};
+// 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; }
+};
+
+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;
+ };
+}
+
+} // end namespace ast_type_traits
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 7f50ee392be6..5cb973122d72 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -23,6 +23,8 @@
namespace clang {
+class TargetInfo;
+
//===----------------------------------------------------------------------===//
/// Common components of both fprintf and fscanf format strings.
namespace analyze_format_string {
@@ -115,11 +117,14 @@ public:
// C99 conversion specifiers.
cArg,
dArg,
+ DArg, // Apple extension
iArg,
- IntArgBeg = cArg, IntArgEnd = iArg,
+ IntArgBeg = dArg, IntArgEnd = iArg,
oArg,
+ OArg, // Apple extension
uArg,
+ UArg, // Apple extension
xArg,
XArg,
UIntArgBeg = oArg, UIntArgEnd = XArg,
@@ -157,7 +162,7 @@ public:
ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
};
- ConversionSpecifier(bool isPrintf)
+ ConversionSpecifier(bool isPrintf = true)
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
@@ -189,10 +194,14 @@ public:
return EndScanList ? EndScanList - Position : 1;
}
+ bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
+ bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
const char *toString() const;
bool isPrintfKind() const { return IsPrintf; }
+
+ llvm::Optional<ConversionSpecifier> getStandardSpecifier() const;
protected:
bool IsPrintf;
@@ -348,10 +357,12 @@ public:
bool usesPositionalArg() const { return UsesPositionalArg; }
- bool hasValidLengthModifier() const;
+ bool hasValidLengthModifier(const TargetInfo &Target) const;
bool hasStandardLengthModifier() const;
+ llvm::Optional<LengthModifier> getCorrectedLengthModifier() const;
+
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
bool hasStandardLengthConversionCombination() const;
@@ -378,7 +389,6 @@ public:
: ConversionSpecifier(true, pos, k) {}
bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
- bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
bool isDoubleArg() const { return kind >= DoubleArgBeg &&
kind <= DoubleArgEnd; }
unsigned getLength() const {
@@ -623,10 +633,12 @@ public:
};
bool ParsePrintfString(FormatStringHandler &H,
- const char *beg, const char *end, const LangOptions &LO);
+ const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target);
bool ParseScanfString(FormatStringHandler &H,
- const char *beg, const char *end, const LangOptions &LO);
+ const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target);
} // end analyze_format_string namespace
} // end clang namespace
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index 742cc0434456..ef6b821e390b 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -132,7 +132,8 @@ public:
/// \param Loc -- The location of the protected operation.
virtual void handleMutexNotHeld(const NamedDecl *D,
ProtectedOperationKind POK, Name LockName,
- LockKind LK, SourceLocation Loc) {}
+ LockKind LK, SourceLocation Loc,
+ Name *PossibleMatch=0) {}
/// Warn when a function is called while an excluded mutex is locked. For
/// example, the mutex may be locked inside the function.
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 46b4e93bb7d4..52466786b341 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -72,7 +72,7 @@ class AnalysisDeclContext {
/// AnalysisDeclContext. This may be null.
AnalysisDeclContextManager *Manager;
- const Decl *D;
+ const Decl * const D;
OwningPtr<CFG> cfg, completeCFG;
OwningPtr<CFGStmtMap> cfgStmtMap;
@@ -81,9 +81,6 @@ class AnalysisDeclContext {
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
bool builtCFG, builtCompleteCFG;
-
- OwningPtr<LiveVariables> liveness;
- OwningPtr<LiveVariables> relaxedLiveness;
OwningPtr<ParentMap> PM;
OwningPtr<PseudoConstantAnalysis> PCA;
OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
@@ -104,9 +101,15 @@ public:
~AnalysisDeclContext();
- ASTContext &getASTContext() { return D->getASTContext(); }
+ ASTContext &getASTContext() const { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
+ /// Return the AnalysisDeclContextManager (if any) that created
+ /// this AnalysisDeclContext.
+ AnalysisDeclContextManager *getManager() const {
+ return Manager;
+ }
+
/// Return the build options used to construct the CFG.
CFG::BuildOptions &getCFGBuildOptions() {
return cfgBuildOptions;
@@ -234,9 +237,10 @@ public:
const StackFrameContext *getCurrentStackFrame() const;
- virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
+ /// Return true if the current LocationContext has no caller context.
+ virtual bool inTopFrame() const;
- static bool classof(const LocationContext*) { return true; }
+ virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
public:
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
@@ -270,6 +274,9 @@ public:
const CFGBlock *getCallSiteBlock() const { return Block; }
+ /// Return true if the current LocationContext has no caller context.
+ virtual bool inTopFrame() const { return getParent() == 0; }
+
unsigned getIndex() const { return Index; }
void Profile(llvm::FoldingSetNodeID &ID);
@@ -379,11 +386,17 @@ class AnalysisDeclContextManager {
ContextMap Contexts;
LocationContextManager LocContexts;
CFG::BuildOptions cfgBuildOptions;
+
+ /// Flag to indicate whether or not bodies should be synthesized
+ /// for well-known functions.
+ bool SynthesizeBodies;
public:
AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
- bool addImplicitDtors = false,
- bool addInitializers = false);
+ bool addImplicitDtors = false,
+ bool addInitializers = false,
+ bool addTemporaryDtors = false,
+ bool synthesizeBodies = false);
~AnalysisDeclContextManager();
@@ -396,6 +409,10 @@ public:
CFG::BuildOptions &getCFGBuildOptions() {
return cfgBuildOptions;
}
+
+ /// Return true if faux bodies should be synthesized for well-known
+ /// functions.
+ bool synthesizeBodies() const { return SynthesizeBodies; }
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
LocationContext const *Parent,
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 4d087e749830..8cc5d814e822 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -88,8 +88,6 @@ public:
return static_cast<const ElemTy*>(this);
return 0;
}
-
- static bool classof(const CFGElement *E) { return true; }
};
class CFGStmt : public CFGElement {
@@ -568,6 +566,7 @@ public:
bool AddEHEdges;
bool AddInitializers;
bool AddImplicitDtors;
+ bool AddTemporaryDtors;
bool alwaysAdd(const Stmt *stmt) const {
return alwaysAddMask[stmt->getStmtClass()];
@@ -587,7 +586,8 @@ public:
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
,AddEHEdges(false)
,AddInitializers(false)
- ,AddImplicitDtors(false) {}
+ ,AddImplicitDtors(false)
+ ,AddTemporaryDtors(false) {}
};
/// \brief Provides a custom implementation of the iterator class to have the
diff --git a/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
new file mode 100644
index 000000000000..930c2bd0925b
--- /dev/null
+++ b/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
@@ -0,0 +1,46 @@
+//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- 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 special handling of recognizing ObjC API hooks that
+// do not return but aren't marked as such in API headers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
+#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
+
+#include "clang/Basic/IdentifierTable.h"
+
+namespace clang {
+
+class ASTContext;
+class ObjCMessageExpr;
+
+class ObjCNoReturn {
+ /// Cached "raise" selector.
+ Selector RaiseSel;
+
+ /// Cached identifier for "NSException".
+ IdentifierInfo *NSExceptionII;
+
+ enum { NUM_RAISE_SELECTORS = 2 };
+
+ /// Cached set of selectors in NSException that are 'noreturn'.
+ Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS];
+
+public:
+ ObjCNoReturn(ASTContext &C);
+
+ /// Return true if the given message expression is known to never
+ /// return.
+ bool isImplicitNoReturn(const ObjCMessageExpr *ME);
+};
+}
+
+#endif
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 5de06cd3a54d..947997804388 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -140,8 +140,6 @@ public:
return ID.ComputeHash();
}
- static bool classof(const ProgramPoint*) { return true; }
-
bool operator==(const ProgramPoint & RHS) const {
return Data1 == RHS.Data1 &&
Data2 == RHS.Data2 &&
@@ -213,7 +211,9 @@ class StmtPoint : public ProgramPoint {
public:
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
const ProgramPointTag *tag)
- : ProgramPoint(S, p2, k, L, tag) {}
+ : ProgramPoint(S, p2, k, L, tag) {
+ assert(S);
+ }
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
@@ -461,6 +461,7 @@ public:
};
/// Represents a point when we begin processing an inlined call.
+/// CallEnter uses the caller's location context.
class CallEnter : public ProgramPoint {
public:
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index fade83ef9361..bfe8093079b7 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -190,7 +190,7 @@ def Availability : InheritableAttr {
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
return llvm::StringSwitch<llvm::StringRef>(Platform)
.Case("ios", "iOS")
- .Case("macosx", "Mac OS X")
+ .Case("macosx", "OS X")
.Default(llvm::StringRef());
} }];
}
@@ -341,6 +341,11 @@ def Final : InheritableAttr {
let SemaHandler = 0;
}
+def MinSize : InheritableAttr {
+ let Spellings = [GNU<"minsize">];
+ let Subjects = [Function];
+}
+
def Format : InheritableAttr {
let Spellings = [GNU<"format">];
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
@@ -528,6 +533,11 @@ def ObjCReturnsInnerPointer : Attr {
let Subjects = [ObjCMethod];
}
+def ObjCRequiresSuper : InheritableAttr {
+ let Spellings = [GNU<"objc_requires_super">];
+ let Subjects = [ObjCMethod];
+}
+
def ObjCRootClass : Attr {
let Spellings = [GNU<"objc_root_class">];
let Subjects = [ObjCInterface];
@@ -556,6 +566,10 @@ def Packed : InheritableAttr {
let Spellings = [GNU<"packed">];
}
+def PnaclCall : InheritableAttr {
+ let Spellings = [GNU<"pnaclcall">];
+}
+
def Pcs : InheritableAttr {
let Spellings = [GNU<"pcs">];
let Args = [EnumArgument<"PCS", "PCSType",
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 84b28811728e..d48eadcd6b61 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -41,6 +41,7 @@
// J -> jmp_buf
// SJ -> sigjmp_buf
// K -> ucontext_t
+// p -> pid_t
// . -> "...". This may only occur at the end of the function list.
//
// Types may be prefixed with the following modifiers:
@@ -388,6 +389,7 @@ BUILTIN(__builtin_popcountll, "iULLi", "nc")
// FIXME: These type signatures are not correct for targets with int != 32-bits
// or with ULL != 64-bits.
+BUILTIN(__builtin_bswap16, "UsUs", "nc")
BUILTIN(__builtin_bswap32, "UiUi", "nc")
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
@@ -478,6 +480,7 @@ BUILTIN(__builtin_expect, "LiLiLi" , "nc")
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
BUILTIN(__builtin_readcyclecounter, "ULLi", "n")
BUILTIN(__builtin_trap, "v", "nr")
+BUILTIN(__builtin_debugtrap, "v", "n")
BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
BUILTIN(__builtin_alloca, "v*z" , "n")
@@ -735,7 +738,7 @@ LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
-LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES)
+LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
// POSIX setjmp.h
// In some systems setjmp is a macro that expands to _setjmp. We undefine
@@ -826,9 +829,13 @@ 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(ceil, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(ceill, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(ceilf, "ff", "fe", "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(copysign, "ddd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(copysignl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(copysignf, "fff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
@@ -838,37 +845,53 @@ 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(fabs, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fabsl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fabsf, "ff", "fe", "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(fabs, "dd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fabsl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(fabsf, "ff", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floor, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floorl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(floorf, "ff", "fe", "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(fma, "dddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmax, "ddd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmaxl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fmaxf, "fff", "fe", "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(fmin, "ddd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fminl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(fminf, "fff", "fe", "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(log, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(logl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(logf, "ff", "fe", "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", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nearbyintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nearbyintf, "ff", "fc", "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(round, "dd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(roundl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(roundf, "ff", "fe", "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(round, "dd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(roundl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(roundf, "ff", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
@@ -882,6 +905,10 @@ 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(trunc, "dd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(truncl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(truncf, "ff", "fc", "math.h", ALL_LANGUAGES)
+
// Blocks runtime Builtin math library functions
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
diff --git a/include/clang/Basic/BuiltinsMips.def b/include/clang/Basic/BuiltinsMips.def
index d0137155a2d0..43fb90756efb 100644
--- a/include/clang/Basic/BuiltinsMips.def
+++ b/include/clang/Basic/BuiltinsMips.def
@@ -14,6 +14,8 @@
// The format of this database matches clang/Basic/Builtins.def.
+// MIPS DSP Rev 1
+
// Add/subtract with optional saturation
BUILTIN(__builtin_mips_addu_qb, "V4ScV4ScV4Sc", "n")
BUILTIN(__builtin_mips_addu_s_qb, "V4ScV4ScV4Sc", "n")
@@ -122,4 +124,65 @@ BUILTIN(__builtin_mips_lbux, "iv*i", "n")
BUILTIN(__builtin_mips_lhx, "iv*i", "n")
BUILTIN(__builtin_mips_lwx, "iv*i", "n")
+// MIPS DSP Rev 2
+
+BUILTIN(__builtin_mips_absq_s_qb, "V4ScV4Sc", "n")
+
+BUILTIN(__builtin_mips_addqh_ph, "V2sV2sV2s", "nc")
+BUILTIN(__builtin_mips_addqh_r_ph, "V2sV2sV2s", "nc")
+BUILTIN(__builtin_mips_addqh_w, "iii", "nc")
+BUILTIN(__builtin_mips_addqh_r_w, "iii", "nc")
+
+BUILTIN(__builtin_mips_addu_ph, "V2sV2sV2s", "n")
+BUILTIN(__builtin_mips_addu_s_ph, "V2sV2sV2s", "n")
+
+BUILTIN(__builtin_mips_adduh_qb, "V4ScV4ScV4Sc", "nc")
+BUILTIN(__builtin_mips_adduh_r_qb, "V4ScV4ScV4Sc", "nc")
+
+BUILTIN(__builtin_mips_append, "iiiIi", "nc")
+BUILTIN(__builtin_mips_balign, "iiiIi", "nc")
+
+BUILTIN(__builtin_mips_cmpgdu_eq_qb, "iV4ScV4Sc", "n")
+BUILTIN(__builtin_mips_cmpgdu_lt_qb, "iV4ScV4Sc", "n")
+BUILTIN(__builtin_mips_cmpgdu_le_qb, "iV4ScV4Sc", "n")
+
+BUILTIN(__builtin_mips_dpa_w_ph, "LLiLLiV2sV2s", "nc")
+BUILTIN(__builtin_mips_dps_w_ph, "LLiLLiV2sV2s", "nc")
+
+BUILTIN(__builtin_mips_dpaqx_s_w_ph, "LLiLLiV2sV2s", "n")
+BUILTIN(__builtin_mips_dpaqx_sa_w_ph, "LLiLLiV2sV2s", "n")
+BUILTIN(__builtin_mips_dpax_w_ph, "LLiLLiV2sV2s", "nc")
+BUILTIN(__builtin_mips_dpsx_w_ph, "LLiLLiV2sV2s", "nc")
+BUILTIN(__builtin_mips_dpsqx_s_w_ph, "LLiLLiV2sV2s", "n")
+BUILTIN(__builtin_mips_dpsqx_sa_w_ph, "LLiLLiV2sV2s", "n")
+
+BUILTIN(__builtin_mips_mul_ph, "V2sV2sV2s", "n")
+BUILTIN(__builtin_mips_mul_s_ph, "V2sV2sV2s", "n")
+
+BUILTIN(__builtin_mips_mulq_rs_w, "iii", "n")
+BUILTIN(__builtin_mips_mulq_s_ph, "V2sV2sV2s", "n")
+BUILTIN(__builtin_mips_mulq_s_w, "iii", "n")
+BUILTIN(__builtin_mips_mulsa_w_ph, "LLiLLiV2sV2s", "nc")
+
+BUILTIN(__builtin_mips_precr_qb_ph, "V4ScV2sV2s", "n")
+BUILTIN(__builtin_mips_precr_sra_ph_w, "V2siiIi", "nc")
+BUILTIN(__builtin_mips_precr_sra_r_ph_w, "V2siiIi", "nc")
+
+BUILTIN(__builtin_mips_prepend, "iiiIi", "nc")
+
+BUILTIN(__builtin_mips_shra_qb, "V4ScV4Sci", "nc")
+BUILTIN(__builtin_mips_shra_r_qb, "V4ScV4Sci", "nc")
+BUILTIN(__builtin_mips_shrl_ph, "V2sV2si", "nc")
+
+BUILTIN(__builtin_mips_subqh_ph, "V2sV2sV2s", "nc")
+BUILTIN(__builtin_mips_subqh_r_ph, "V2sV2sV2s", "nc")
+BUILTIN(__builtin_mips_subqh_w, "iii", "nc")
+BUILTIN(__builtin_mips_subqh_r_w, "iii", "nc")
+
+BUILTIN(__builtin_mips_subu_ph, "V2sV2sV2s", "n")
+BUILTIN(__builtin_mips_subu_s_ph, "V2sV2sV2s", "n")
+
+BUILTIN(__builtin_mips_subuh_qb, "V4ScV4ScV4Sc", "nc")
+BUILTIN(__builtin_mips_subuh_r_qb, "V4ScV4ScV4Sc", "nc")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def
index f90a43f7f404..3c3f06c5ea3a 100644
--- a/include/clang/Basic/BuiltinsNVPTX.def
+++ b/include/clang/Basic/BuiltinsNVPTX.def
@@ -14,6 +14,7 @@
// The format of this database matches clang/Basic/Builtins.def.
+// Builtins retained from previous PTX back-end
BUILTIN(__builtin_ptx_read_tid_x, "i", "nc")
BUILTIN(__builtin_ptx_read_tid_y, "i", "nc")
BUILTIN(__builtin_ptx_read_tid_z, "i", "nc")
@@ -59,4 +60,249 @@ BUILTIN(__builtin_ptx_read_pm3, "i", "n")
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")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 75e60742148d..5b46f8e6ad11 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -613,6 +613,12 @@ BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iV8iC*V8iV8iIc", "")
BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iV4iC*V2LLiV4iIc", "")
BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "")
+// F16C
+BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "")
+BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "")
+BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "")
+BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "")
+
// RDRAND
BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "")
BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "")
@@ -730,5 +736,8 @@ BUILTIN(__builtin_ia32_vfrczps, "V4fV4f", "")
BUILTIN(__builtin_ia32_vfrczpd, "V2dV2d", "")
BUILTIN(__builtin_ia32_vfrczps256, "V8fV8f", "")
BUILTIN(__builtin_ia32_vfrczpd256, "V4dV4d", "")
+BUILTIN(__builtin_ia32_xbegin, "i", "")
+BUILTIN(__builtin_ia32_xend, "v", "")
+BUILTIN(__builtin_ia32_xabort, "vIc", "")
#undef BUILTIN
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
index e7cfa8a7677c..cdc42699e3eb 100644
--- a/include/clang/Basic/ConvertUTF.h
+++ b/include/clang/Basic/ConvertUTF.h
@@ -147,7 +147,6 @@ ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-#ifdef CLANG_NEEDS_THESE_ONE_DAY
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
@@ -159,7 +158,9 @@ ConversionResult ConvertUTF32toUTF16 (
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
-Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd);
+Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
+
+unsigned getNumBytesForUTF8(UTF8 firstByte);
#ifdef __cplusplus
}
@@ -175,11 +176,13 @@ namespace clang {
* Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
* WideCharWidth. The converted data is written to ResultPtr, which needs to
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
- * ResultPtr will point one after the end of the copied string.
+ * ResultPtr will point one after the end of the copied string. On failure,
+ * ResultPtr will not be changed, and ErrorPtr will be set to the location of
+ * the first character which could not be converted.
* \return true on success.
*/
bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr);
+ char *&ResultPtr, const UTF8 *&ErrorPtr);
/**
* Convert an Unicode code point to UTF8 sequence.
@@ -194,7 +197,6 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
}
-#endif
#endif
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3997fb89ba82..e47f3e185741 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_DIAGNOSTIC_H
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -29,6 +30,7 @@
namespace clang {
class DiagnosticConsumer;
class DiagnosticBuilder;
+ class DiagnosticOptions;
class IdentifierInfo;
class DeclContext;
class LangOptions;
@@ -160,13 +162,6 @@ public:
ak_qualtype_pair ///< pair<QualType, QualType>
};
- /// \brief Specifies which overload candidates to display when overload
- /// resolution fails.
- enum OverloadsShown {
- Ovl_All, ///< Show all overloads.
- Ovl_Best ///< Show just the "best" overload candidates.
- };
-
/// \brief Represents on argument value, which is a union discriminated
/// by ArgumentKind, with a value.
typedef std::pair<ArgumentKind, intptr_t> ArgumentValue;
@@ -190,6 +185,7 @@ private:
// backtrace stack, 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticConsumer *Client;
bool OwnsDiagClient;
SourceManager *SourceMgr;
@@ -341,6 +337,7 @@ private:
public:
explicit DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
+ DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client = 0,
bool ShouldOwnClient = true);
~DiagnosticsEngine();
@@ -349,6 +346,9 @@ public:
return Diags;
}
+ /// \brief Retrieve the diagnostic options.
+ DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
+
DiagnosticConsumer *getClient() { return Client; }
const DiagnosticConsumer *getClient() const { return Client; }
@@ -478,10 +478,13 @@ public:
}
OverloadsShown getShowOverloads() const { return ShowOverloads; }
- /// \brief Pretend that the last diagnostic issued was ignored.
+ /// \brief Pretend that the last diagnostic issued was ignored, so any
+ /// subsequent notes will be suppressed.
///
/// This can be used by clients who suppress diagnostics themselves.
void setLastDiagnosticIgnored() {
+ if (LastDiagLevel == DiagnosticIDs::Fatal)
+ FatalErrorOccurred = true;
LastDiagLevel = DiagnosticIDs::Ignored;
}
@@ -584,7 +587,7 @@ public:
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
- SmallVectorImpl<intptr_t> &QualTypeVals) const {
+ ArrayRef<intptr_t> QualTypeVals) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
QualTypeVals);
@@ -837,7 +840,7 @@ class DiagnosticBuilder {
/// call to ForceEmit.
mutable bool IsForceEmit;
- void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
+ void operator=(const DiagnosticBuilder &) LLVM_DELETED_FUNCTION;
friend class DiagnosticsEngine;
DiagnosticBuilder()
@@ -961,6 +964,10 @@ public:
"Too many arguments to diagnostic!");
DiagObj->DiagFixItHints[NumFixits++] = Hint;
}
+
+ bool hasMaxRanges() const {
+ return NumRanges == DiagnosticsEngine::MaxRanges;
+ }
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 9cfe5efae259..d869c9983bd7 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -137,7 +137,7 @@ def err_odr_function_type_inconsistent : Error<
def warn_odr_tag_type_inconsistent : Warning<
"type %0 has incompatible definitions in different translation units">;
def note_odr_tag_kind_here: Note<
- "%0 is a %select{struct|union|class|enum}1 here">;
+ "%0 is a %select{struct|interface|union|class|enum}1 here">;
def note_odr_field : Note<"field %0 has type %1 here">;
def note_odr_missing_field : Note<"no corresponding field here">;
def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index 235ca79564d3..e6dfe5b6387c 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -121,5 +121,21 @@ def warn_doc_returns_attached_to_a_void_function : Warning<
"method returning void}1">,
InGroup<Documentation>, DefaultIgnore;
+// \deprecated command
+
+def warn_doc_deprecated_not_sync : Warning<
+ "declaration is marked with '\\deprecated' command but does not have "
+ "a deprecation attribute">,
+ InGroup<DocumentationDeprecatedSync>, DefaultIgnore;
+
+def note_add_deprecation_attr : Note<
+ "add a deprecation attribute to the declaration to silence this warning">;
+
+// verbatim block commands
+
+def warn_verbatim_block_end_without_start : Warning<
+ "'\\%0' command does not terminate a verbatim text block">,
+ 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 f85928740b4c..a6ce9d4a2d21 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -78,9 +78,12 @@ def note_decl_hiding_tag_type : Note<
"%1 %0 is hidden by a non-type declaration of %0 here">;
// Sema && Lex
-def ext_longlong : Extension<
+def ext_c99_longlong : Extension<
"'long long' is an extension when C99 mode is not enabled">,
InGroup<LongLong>;
+def ext_cxx11_longlong : Extension<
+ "'long long' is a C++11 extension">,
+ InGroup<CXX11LongLong>;
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 583b2345c935..4b430351756a 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -11,6 +11,8 @@ let Component = "Driver" in {
def err_drv_no_such_file : Error<"no such file or directory: '%0'">;
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
+def err_drv_unsupported_opt_for_target : Error<
+ "unsupported option '%0' for target '%1'">;
def err_drv_unsupported_option_argument : Error<
"unsupported argument '%1' to option '%0'">;
def err_drv_unknown_stdin_type : Error<
@@ -91,10 +93,10 @@ def err_drv_invalid_arch_for_deployment_target : Error<
"invalid architecture '%0' for deployment target '%1'">;
def err_drv_objc_gc_arr : Error<
"cannot specify both '-fobjc-arc' and '%0'">;
-def err_arc_nonfragile_abi : Error<
- "-fobjc-arc is not supported with legacy abi">;
-def err_arc_unsupported : Error<
- "-fobjc-arc is not supported on current deployment target">;
+def err_arc_unsupported_on_runtime : Error<
+ "-fobjc-arc is not supported on platforms using the legacy runtime">;
+def err_arc_unsupported_on_toolchain : Error< // feel free to generalize this
+ "-fobjc-arc is not supported on versions of OS X prior to 10.6">;
def err_drv_mg_requires_m_or_mm : Error<
"option '-MG' requires '-M' or '-MM'">;
def err_drv_asan_android_requires_pie : Error<
@@ -119,14 +121,10 @@ def warn_drv_unused_argument : Warning<
def warn_drv_empty_joined_argument : Warning<
"joined argument expects additional value: '%0'">,
InGroup<DiagGroup<"unused-command-line-argument">>;
-def warn_drv_not_using_clang_cpp : Warning<
- "not using the clang preprocessor due to user override">;
-def warn_drv_not_using_clang_cxx : Warning<
- "not using the clang compiler for C++ inputs">;
-def warn_drv_not_using_clang_arch : Warning<
- "not using the clang compiler for the '%0' architecture">;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
+def warn_drv_deprecated_arg : Warning<
+ "argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>;
def warn_drv_assuming_mfloat_abi_is : Warning<
"unknown platform, assuming -mfloat-abi=%0">;
def warn_ignoring_ftabstop_value : Warning<
@@ -141,5 +139,9 @@ def warn_drv_pch_not_first_include : Warning<
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
-
+
+def err_analyzer_config_no_value : Error<
+ "analyzer-config option '%0' has a key but no value">;
+def err_analyzer_config_multiple_values : Error<
+ "analyzer-config option '%0' should contain only one '='">;
}
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 417a22c96df5..b7a84764391b 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -58,6 +58,8 @@ def warn_fe_cc_print_header_failure : Warning<
"unable to open CC_PRINT_HEADERS file: %0 (using stderr)">;
def warn_fe_cc_log_diagnostics_failure : Warning<
"unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">;
+def err_fe_no_pch_in_dir : Error<
+ "no suitable precompiled header file found in directory '%0'">;
def warn_fe_serialized_diag_failure : Warning<
"unable to open file %0 for serializing diagnostics (%1)">,
@@ -76,6 +78,11 @@ def err_verify_invalid_content : Error<
def err_verify_inconsistent_diags : Error<
"'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: "
"%2">;
+def err_verify_invalid_no_diags : Error<
+ "%select{expected|'expected-no-diagnostics'}0 directive cannot follow "
+ "%select{'expected-no-diagnostics' directive|other expected directives}0">;
+def err_verify_no_directives : Error<
+ "no expected directives found: consider use of 'expected-no-diagnostics'">;
def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
def note_fixit_in_macro : Note<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index d8632dd8c39d..f9f9ec78309a 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -22,8 +22,6 @@ def : DiagGroup<"address">;
def AddressOfTemporary : DiagGroup<"address-of-temporary">;
def : DiagGroup<"aggregate-return">;
def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
-def : DiagGroup<"attributes">;
-def : DiagGroup<"bad-function-cast">;
def Availability : DiagGroup<"availability">;
def Section : DiagGroup<"section">;
def AutoImport : DiagGroup<"auto-import">;
@@ -33,8 +31,11 @@ def StringConversion : DiagGroup<"string-conversion">;
def SignConversion : DiagGroup<"sign-conversion">;
def BoolConversion : DiagGroup<"bool-conversion">;
def IntConversion : DiagGroup<"int-conversion">;
+def EnumConversion : DiagGroup<"enum-conversion">;
def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
+def ImplicitConversionFloatingPointToBool :
+ DiagGroup<"implicit-conversion-floating-point-to-bool">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def CXXCompat: DiagGroup<"c++-compat">;
def CastAlign : DiagGroup<"cast-align">;
@@ -42,11 +43,11 @@ def : DiagGroup<"cast-qual">;
def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
def : DiagGroup<"ctor-dtor-privacy">;
-def : DiagGroup<"declaration-after-statement">;
def DefaultArgSpecialMember : DiagGroup<"default-arg-special-member">;
def GNUDesignator : DiagGroup<"gnu-designator">;
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
+def AbstractFinalClass : DiagGroup<"abstract-final-class">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
@@ -58,9 +59,14 @@ def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
def : DiagGroup<"div-by-zero">;
+
def DocumentationHTML : DiagGroup<"documentation-html">;
def DocumentationPedantic : DiagGroup<"documentation-pedantic">;
-def Documentation : DiagGroup<"documentation", [DocumentationHTML]>;
+def DocumentationDeprecatedSync : DiagGroup<"documentation-deprecated-sync">;
+def Documentation : DiagGroup<"documentation",
+ [DocumentationHTML,
+ DocumentationDeprecatedSync]>;
+
def EmptyBody : DiagGroup<"empty-body">;
def ExtraTokens : DiagGroup<"extra-tokens">;
def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
@@ -108,9 +114,9 @@ def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
def GlobalConstructors : DiagGroup<"global-constructors">;
-def : DiagGroup<"idiomatic-parentheses">;
def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
+def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
@@ -119,7 +125,6 @@ def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
-def : DiagGroup<"int-to-pointer-cast">;
def : DiagGroup<"invalid-pch">;
def LiteralRange : DiagGroup<"literal-range">;
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args",
@@ -131,11 +136,12 @@ def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
def : DiagGroup<"missing-format-attribute">;
def : DiagGroup<"missing-include-dirs">;
-def : DiagGroup<"missing-noreturn">;
def MultiChar : DiagGroup<"multichar">;
def : DiagGroup<"nested-externs">;
-def : DiagGroup<"newline-eof">;
-def LongLong : DiagGroup<"long-long">;
+def CXX11LongLong : DiagGroup<"c++11-long-long">;
+def LongLong : DiagGroup<"long-long", [CXX11LongLong]>;
+def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
+def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def ModuleBuild : DiagGroup<"module-build">;
@@ -157,6 +163,7 @@ def OverlengthStrings : DiagGroup<"overlength-strings">;
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
def PrivateExtern : DiagGroup<"private-extern">;
def SelTypeCast : DiagGroup<"cast-of-sel-type">;
+def BadFunctionCast : DiagGroup<"bad-function-cast">;
def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">;
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
@@ -183,7 +190,7 @@ def Sentinel : DiagGroup<"sentinel">;
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
def : DiagGroup<"sequence-point">;
def Shadow : DiagGroup<"shadow">;
-def : DiagGroup<"shorten-64-to-32">;
+def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
def : DiagGroup<"sign-promo">;
def SignCompare : DiagGroup<"sign-compare">;
def : DiagGroup<"stack-protector">;
@@ -192,11 +199,15 @@ def : DiagGroup<"synth">;
def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">;
def StringPlusInt : DiagGroup<"string-plus-int">;
def StrncatSize : DiagGroup<"strncat-size">;
-def TautologicalCompare : DiagGroup<"tautological-compare">;
+def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
+def TautologicalCompare : DiagGroup<"tautological-compare",
+ [TautologicalOutOfRangeCompare]>;
def HeaderHygiene : DiagGroup<"header-hygiene">;
+def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
+def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
// Preprocessor warnings.
-def : DiagGroup<"builtin-macro-redefined">;
+def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
// Just silence warnings about -Wstrict-aliasing for now.
def : DiagGroup<"strict-aliasing=0">;
@@ -262,26 +273,29 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
def CustomAtomic : DiagGroup<"custom-atomic-properties">;
def AtomicProperties : DiagGroup<"atomic-properties",
[ImplicitAtomic, CustomAtomic]>;
-def AutomaticReferenceCountingABI : DiagGroup<"arc-abi">;
+// FIXME: Remove arc-abi once an Xcode is released that doesn't pass this flag.
+def : DiagGroup<"arc-abi">;
def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">;
def ARCRetainCycles : DiagGroup<"arc-retain-cycles">;
def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">;
def AutomaticReferenceCounting : DiagGroup<"arc",
- [AutomaticReferenceCountingABI,
- ARCUnsafeRetainedAssign,
+ [ARCUnsafeRetainedAssign,
ARCRetainCycles,
ARCNonPodMemAccess]>;
+def ARCRepeatedUseOfWeakMaybe : DiagGroup<"arc-maybe-repeated-use-of-weak">;
+def ARCRepeatedUseOfWeak : DiagGroup<"arc-repeated-use-of-weak",
+ [ARCRepeatedUseOfWeakMaybe]>;
def Selector : DiagGroup<"selector">;
def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
-def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversion : DiagGroup<"vector-conversion">; // clang specific
def VexingParse : DiagGroup<"vexing-parse">;
def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def Visibility : DiagGroup<"visibility">;
+def ZeroLengthArray : DiagGroup<"zero-length-array">;
// GCC calls -Wdeprecated-writable-strings -Wwrite-strings.
def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>;
@@ -300,6 +314,7 @@ def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
def Parentheses : DiagGroup<"parentheses",
[LogicalOpParentheses,
BitwiseOpParentheses,
+ ShiftOpParentheses,
ParenthesesOnEquality,
DanglingElse]>;
@@ -311,15 +326,16 @@ def Parentheses : DiagGroup<"parentheses",
// - bool-to-pointer conversion warnings are on by default
// - __null-to-integer conversion warnings are on by default
def Conversion : DiagGroup<"conversion",
- [DiagGroup<"shorten-64-to-32">,
+ [BoolConversion,
ConstantConversion,
+ EnumConversion,
+ Shorten64To32,
+ IntConversion,
LiteralConversion,
- StringConversion,
- SignConversion,
- BoolConversion,
- NullConversion, // NULL->non-pointer
NonLiteralNullConversion, // (1-1)->pointer (etc)
- IntConversion]>,
+ NullConversion, // NULL->non-pointer
+ SignConversion,
+ StringConversion]>,
DiagCategory<"Value Conversion Issue">;
def Unused : DiagGroup<"unused",
@@ -345,6 +361,8 @@ def Format2 : DiagGroup<"format=2",
def TypeSafety : DiagGroup<"type-safety">;
+def IntToPointerCast : DiagGroup<"int-to-pointer-cast">;
+
def Extra : DiagGroup<"extra", [
MissingFieldInitializers,
IgnoredQualifiers,
@@ -361,6 +379,7 @@ def Most : DiagGroup<"most", [
DeleteNonVirtualDtor,
Format,
Implicit,
+ IntToPointerCast,
MismatchedTags,
MissingBraces,
MultiChar,
@@ -382,9 +401,12 @@ def Most : DiagGroup<"most", [
// Thread Safety warnings
def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">;
-def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">;
-def ThreadSafety : DiagGroup<"thread-safety",
- [ThreadSafetyAttributes, ThreadSafetyAnalysis]>;
+def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">;
+def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">;
+def ThreadSafety : DiagGroup<"thread-safety",
+ [ThreadSafetyAttributes,
+ ThreadSafetyAnalysis,
+ ThreadSafetyPrecise]>;
// 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
@@ -414,7 +436,8 @@ def NonGCC : DiagGroup<"non-gcc",
// A warning group for warnings about using C++11 features as extensions in
// earlier C++ versions.
-def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi]>;
+def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>;
+
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
@@ -426,7 +449,7 @@ def C11 : DiagGroup<"c11-extensions">;
def C99 : DiagGroup<"c99-extensions">;
// A warning group for warnings about GCC extensions.
-def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
+def GNU : DiagGroup<"gnu", [GNUDesignator, VLA, ZeroLengthArray]>;
// A warning group for warnings about code that clang accepts but gcc doesn't.
def GccCompat : DiagGroup<"gcc-compat">;
@@ -451,3 +474,9 @@ def ObjCStringComparison : DiagGroup<"objc-string-compare">;
def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [
ObjCStringComparison
]>;
+
+// Inline ASM warnings.
+def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
+def ASM : DiagGroup<"asm", [
+ ASMOperandWidths
+ ]>;
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index cc958dbdfea2..c6c50ab37b87 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -41,9 +41,9 @@ def trigraph_ends_block_comment : Warning<"trigraph ends block comment">,
def trigraph_converted : Warning<"trigraph converted to '%0' character">,
InGroup<Trigraphs>;
-def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">,
+def ext_multi_line_line_comment : Extension<"multi-line // comment">,
InGroup<Comment>;
-def ext_bcpl_comment : Extension<
+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">,
@@ -55,7 +55,7 @@ def warn_cxx98_compat_no_newline_eof : Warning<
def ext_dollar_in_identifier : Extension<"'$' in identifier">,
InGroup<DiagGroup<"dollar-in-identifier-extension">>;
-def ext_charize_microsoft : Extension<"@# is a microsoft extension">,
+def ext_charize_microsoft : Extension<"charizing operator #@ is a Microsoft extension">,
InGroup<Microsoft>;
def ext_token_used : Extension<"extension used">,
@@ -127,15 +127,16 @@ def warn_char_constant_too_large : Warning<
def err_multichar_utf_character_literal : Error<
"Unicode character literals may not contain multiple characters">;
def err_exponent_has_no_digits : Error<"exponent has no digits">;
-def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
+def ext_imaginary_constant : Extension<
+ "imaginary constants are a GNU extension">, InGroup<GNU>;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
def err_hexconstant_requires_digits : Error<
"hexadecimal floating constants require a significand">;
def ext_hexconstant_invalid : Extension<
- "hexadecimal floating constants are a C99 feature">;
+ "hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_binary_literal : Extension<
- "binary integer literals are an extension">;
+ "binary integer literals are a GNU extension">, InGroup<GNU>;
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">;
@@ -228,6 +229,12 @@ def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore,
def warn_pp_undef_identifier : Warning<
"%0 is not defined, evaluates to 0">,
InGroup<DiagGroup<"undef">>, DefaultIgnore;
+def warn_pp_ambiguous_macro : Warning<
+ "ambiguous expansion of macro %0">, InGroup<AmbiguousMacro>;
+def note_pp_ambiguous_macro_chosen : Note<
+ "expanding this definition of %0">;
+def note_pp_ambiguous_macro_other : Note<
+ "other definition of %0">;
def pp_invalid_string_literal : Warning<
"invalid string literal, ignoring final '\\'">;
@@ -484,15 +491,21 @@ def err_mmap_missing_module_unqualified : Error<
def err_mmap_missing_module_qualified : Error<
"no module named '%0' in '%1'">;
def err_mmap_top_level_inferred_submodule : Error<
- "only submodules may be inferred with wildcard syntax">;
+ "only submodules and framework modules may be inferred with wildcard syntax">;
def err_mmap_inferred_no_umbrella : Error<
"inferred submodules require a module with an umbrella">;
+def err_mmap_inferred_framework_submodule : Error<
+ "inferred submodule cannot be a framework submodule">;
+def err_mmap_explicit_inferred_framework : Error<
+ "inferred framework modules cannot be 'explicit'">;
+def err_mmap_missing_exclude_name : Error<
+ "expected excluded module name">;
def err_mmap_inferred_redef : Error<
"redefinition of inferred submodule">;
def err_mmap_expected_lbrace_wildcard : Error<
"expected '{' to start inferred submodule">;
-def err_mmap_expected_wildcard_member : Error<
- "expected module export wildcard">;
+def err_mmap_expected_inferred_member : Error<
+ "expected %select{module exclusion with 'exclude'|'export *'}0">;
def err_mmap_expected_export_wildcard : Error<
"only '*' can be exported from an inferred submodule">;
def err_mmap_explicit_top_level : Error<
@@ -509,5 +522,7 @@ def warn_auto_module_import : Warning<
"import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
def warn_uncovered_module_header : Warning<
"umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>;
-
+def err_expected_id_building_module : Error<
+ "expected a module name in '__building_module' expression">;
+
}
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
new file mode 100644
index 000000000000..476ac1e373f0
--- /dev/null
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -0,0 +1,93 @@
+//===--- DiagOptions.def - Diagnostic option 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 diagnostic options. Users of this file
+// must define the DIAGOPT macro to make use of this information.
+// Optionally, the user may also define ENUM_DIAGOPT (for options
+// that have enumeration type and VALUE_DIAGOPT (for options that
+// describe a value rather than a flag). The SEMANTIC_* variants of these macros
+// indicate options that affect the processing of the program, rather than
+// simply the output.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DIAGOPT
+# error Define the DIAGOPT macro to handle language options
+#endif
+
+#ifndef VALUE_DIAGOPT
+# define VALUE_DIAGOPT(Name, Bits, Default) \
+DIAGOPT(Name, Bits, Default)
+#endif
+
+#ifndef ENUM_DIAGOPT
+# define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+DIAGOPT(Name, Bits, Default)
+#endif
+
+#ifndef SEMANTIC_DIAGOPT
+# define SEMANTIC_DIAGOPT(Name, Bits, Default) DIAGOPT(Name, Bits, Default)
+#endif
+
+#ifndef SEMANTIC_VALUE_DIAGOPT
+# define SEMANTIC_VALUE_DIAGOPT(Name, Bits, Default) \
+ VALUE_DIAGOPT(Name, Bits, Default)
+#endif
+
+#ifndef SEMANTIC_ENUM_DIAGOPT
+# define SEMANTIC_ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ ENUM_DIAGOPT(Name, Type, Bits, Default)
+#endif
+
+SEMANTIC_DIAGOPT(IgnoreWarnings, 1, 0) /// -w
+DIAGOPT(NoRewriteMacros, 1, 0) /// -Wno-rewrite-macros
+DIAGOPT(Pedantic, 1, 0) /// -pedantic
+DIAGOPT(PedanticErrors, 1, 0) /// -pedantic-errors
+DIAGOPT(ShowColumn, 1, 1) /// Show column number on diagnostics.
+DIAGOPT(ShowLocation, 1, 1) /// Show source location information.
+DIAGOPT(ShowCarets, 1, 1) /// Show carets in diagnostics.
+DIAGOPT(ShowFixits, 1, 1) /// Show fixit information.
+DIAGOPT(ShowSourceRanges, 1, 0) /// Show source ranges in numeric form.
+DIAGOPT(ShowParseableFixits, 1, 0) /// Show machine parseable fix-its.
+DIAGOPT(ShowOptionNames, 1, 0) /// Show the option name for mappable
+ /// diagnostics.
+DIAGOPT(ShowNoteIncludeStack, 1, 0) /// Show include stacks for notes.
+VALUE_DIAGOPT(ShowCategories, 2, 0) /// Show categories: 0 -> none, 1 -> Number,
+ /// 2 -> Full Name.
+
+ENUM_DIAGOPT(Format, TextDiagnosticFormat, 2, Clang) /// Format for diagnostics:
+
+DIAGOPT(ShowColors, 1, 0) /// Show diagnostics with ANSI color sequences.
+ENUM_DIAGOPT(ShowOverloads, OverloadsShown, 1,
+ Ovl_All) /// Overload candidates to show.
+DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected
+ /// diagnostics, indicated by markers in the
+ /// input source file.
+
+DIAGOPT(ElideType, 1, 0) /// Elide identical types in template diffing
+DIAGOPT(ShowTemplateTree, 1, 0) /// Print a template tree when diffing
+
+VALUE_DIAGOPT(ErrorLimit, 32, 0) /// Limit # errors emitted.
+/// Limit depth of macro expansion backtrace.
+VALUE_DIAGOPT(MacroBacktraceLimit, 32, DefaultMacroBacktraceLimit)
+/// Limit depth of instantiation backtrace.
+VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
+/// Limit depth of constexpr backtrace.
+VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
+
+VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
+/// Column limit for formatting message diagnostics, or 0 if unused.
+VALUE_DIAGOPT(MessageLength, 32, 0)
+
+#undef DIAGOPT
+#undef ENUM_DIAGOPT
+#undef VALUE_DIAGOPT
+#undef SEMANTIC_DIAGOPT
+#undef SEMANTIC_ENUM_DIAGOPT
+#undef SEMANTIC_VALUE_DIAGOPT
+
diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h
new file mode 100644
index 000000000000..b75cb0c24da3
--- /dev/null
+++ b/include/clang/Basic/DiagnosticOptions.h
@@ -0,0 +1,85 @@
+//===--- DiagnosticOptions.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
+#define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// \brief Specifies which overload candidates to display when overload
+/// resolution fails.
+enum OverloadsShown {
+ Ovl_All, ///< Show all overloads.
+ Ovl_Best ///< Show just the "best" overload candidates.
+};
+
+/// DiagnosticOptions - Options for controlling the compiler diagnostics
+/// engine.
+class DiagnosticOptions : public llvm::RefCountedBase<DiagnosticOptions>{
+public:
+ enum TextDiagnosticFormat { Clang, Msvc, Vi };
+
+ // Default values.
+ enum { DefaultTabStop = 8, MaxTabStop = 100,
+ DefaultMacroBacktraceLimit = 6,
+ DefaultTemplateBacktraceLimit = 10,
+ DefaultConstexprBacktraceLimit = 10 };
+
+ // Define simple diagnostic options (with no accessors).
+#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;
+#define ENUM_DIAGOPT(Name, Type, Bits, Default)
+#include "clang/Basic/DiagnosticOptions.def"
+
+protected:
+ // Define diagnostic options of enumeration type. These are private, and will
+ // have accessors (below).
+#define DIAGOPT(Name, Bits, Default)
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) unsigned Name : Bits;
+#include "clang/Basic/DiagnosticOptions.def"
+
+public:
+ /// If non-empty, a file to log extended build information to, for development
+ /// testing and analysis.
+ std::string DumpBuildInformation;
+
+ /// The file to log diagnostic output to.
+ std::string DiagnosticLogFile;
+
+ /// The file to serialize diagnostics to (non-appending).
+ std::string DiagnosticSerializationFile;
+
+ /// The list of -W... options used to alter the diagnostic mappings, with the
+ /// prefixes removed.
+ std::vector<std::string> Warnings;
+
+public:
+ // Define accessors/mutators for diagnostic options of enumeration type.
+#define DIAGOPT(Name, Bits, Default)
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Type get##Name() const { return static_cast<Type>(Name); } \
+ void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }
+#include "clang/Basic/DiagnosticOptions.def"
+
+ DiagnosticOptions() {
+#define DIAGOPT(Name, Bits, Default) Name = Default;
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) set##Name(Default);
+#include "clang/Basic/DiagnosticOptions.def"
+ }
+};
+
+typedef DiagnosticOptions::TextDiagnosticFormat TextDiagnosticFormat;
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index b1c16fa8529f..21eeccb5a3e4 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -18,10 +18,13 @@ def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">,
def warn_file_asm_volatile : Warning<
"meaningless 'volatile' on asm outside function">, CatInlineAsm;
+def warn_unsupported_msasm : Warning<
+ "MS-style inline assembly is not supported">, InGroup<Microsoft>;
+
let CategoryName = "Parse Issue" in {
def ext_empty_translation_unit : Extension<
- "ISO C requires a translation unit to contain at least one declaration.">,
+ "ISO C requires a translation unit to contain at least one declaration">,
InGroup<DiagGroup<"empty-translation-unit">>;
def warn_cxx98_compat_top_level_semi : Warning<
"extra ';' outside of a function is incompatible with C++98">,
@@ -40,11 +43,14 @@ def warn_extra_semi_after_mem_fn_def : Warning<
"extra ';' after member function definition">,
InGroup<ExtraSemi>, DefaultIgnore;
-def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">;
+def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">,
+ InGroup<DuplicateDeclSpecifier>;
+def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">,
+ InGroup<DuplicateDeclSpecifier>;
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
def ext_integer_complex : Extension<
- "complex integer types are an extension">;
+ "complex integer types are a GNU extension">, InGroup<GNU>;
def ext_thread_before : Extension<"'__thread' before '%0'">;
def ext_empty_struct_union : Extension<
@@ -80,8 +86,11 @@ def err_enumerator_list_missing_comma : Error<
"missing ',' between enumerators">;
def err_enumerator_unnamed_no_def : Error<
"unnamed enumeration must be a definition">;
-def ext_ms_enum_fixed_underlying_type : Extension<
- "enumeration types with a fixed underlying type are a Microsoft extension">,
+def ext_cxx11_enum_fixed_underlying_type : Extension<
+ "enumeration types with a fixed underlying type are a C++11 extension">,
+ InGroup<CXX11>;
+def ext_c_enum_fixed_underlying_type : Extension<
+ "enumeration types with a fixed underlying type are a Microsoft extension">,
InGroup<Microsoft>;
def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
"enumeration types with a fixed underlying type are incompatible with C++98">,
@@ -207,6 +216,17 @@ def err_expected_semi_after_static_assert : Error<
"expected ';' after static_assert">;
def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
def err_expected_colon_after : Error<"expected ':' after %0">;
+def warn_missing_selector_name : Warning<
+ "%0 used as the name of the previous parameter rather than as part "
+ "of the selector">,
+ InGroup<DiagGroup<"missing-selector-name">>;
+def note_missing_selector_name : Note<
+ "introduce a parameter name to make %0 part of the selector">;
+def note_force_empty_selector_name : Note<
+ "or insert whitespace before ':' to use %0 as parameter name "
+ "and have an empty entry in the selector">;
+def note_missing_argument_name : Note<
+ "did you mean to use %0 as the selector name instead of %1">;
def err_label_end_of_compound_statement : Error<
"label at end of compound statement: expected statement">;
def err_address_of_label_outside_fn : Error<
@@ -331,6 +351,8 @@ def ext_c11_static_assert : Extension<
def warn_cxx98_compat_static_assert : Warning<
"static_assert declarations are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def err_paren_after_colon_colon : Error<
+ "unexpected parenthesis after '::'">;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
@@ -423,7 +445,8 @@ def err_expected_member_or_base_name : Error<
def err_expected_lbrace_after_base_specifiers : Error<
"expected '{' after base class list">;
def ext_ellipsis_exception_spec : Extension<
- "exception specification of '...' is a Microsoft extension">;
+ "exception specification of '...' is a Microsoft extension">,
+ InGroup<Microsoft>;
def err_dynamic_and_noexcept_specification : Error<
"cannot have both throw() and noexcept() clause on the same function">;
def warn_cxx98_compat_noexcept_decl : Warning<
@@ -455,9 +478,6 @@ def err_literal_operator_string_prefix : Error<
"string literal after 'operator' cannot have an encoding prefix">;
def err_literal_operator_string_not_empty : Error<
"string literal after 'operator' must be '\"\"'">;
-def err_literal_operator_missing_space : Error<
- "C++11 requires a space between the \"\" and the user-defined suffix in a "
- "literal operator">;
def warn_cxx98_compat_literal_operator : Warning<
"literal operators are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -570,7 +590,7 @@ def err_expected_type_name_after_typename : Error<
"expected an identifier or template-id after '::'">;
def err_explicit_spec_non_template : Error<
"explicit %select{specialization|instantiation}0 of non-template "
- "%select{class|struct|union}1 %2">;
+ "%select{class|struct|union|interface}1 %2">;
def err_default_template_template_parameter_not_template : Error<
"default template argument for a template template parameter must be a class "
@@ -627,6 +647,11 @@ def ext_override_control_keyword : ExtWarn<
def warn_cxx98_compat_override_control_keyword : Warning<
"'%0' keyword is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def err_override_control_interface : Error<
+ "'%0' keyword not permitted with interface types">;
+
+def err_access_specifier_interface : Error<
+ "interface types cannot specify '%select{private|protected}0' access">;
def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">;
@@ -710,6 +735,11 @@ def warn_pragma_unused_expected_var : Warning<
"expected '#pragma unused' argument to be a variable name">;
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">;
+
// OpenCL Section 6.8.g
def err_not_opencl_storage_class_specifier : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2d63dc42fd94..0d64bf38ad7c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -20,13 +20,6 @@ def warn_variables_not_in_loop_body : Warning<
"used in loop condition not modified in loop body">,
InGroup<DiagGroup<"loop-analysis">>, DefaultIgnore;
-def warn_identical_enum_values : Warning<
- "all elements of %0 are initialized with literals to value %1">,
- InGroup<DiagGroup<"unique-enum">>;
-def note_identical_enum_values : Note<
- "initialize the last element with the previous element to silence "
- "this warning">;
-
// Constant expressions
def err_expr_not_ice : Error<
"expression is not an %select{integer|integral}0 constant expression">;
@@ -102,7 +95,7 @@ def err_variably_modified_new_type : Error<
// C99 Designated Initializers
def ext_designated_init : Extension<
- "designated initializers are a C99 feature">;
+ "designated initializers are a C99 feature">, InGroup<C99>;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
def err_array_designator_empty_range : Error<
@@ -410,12 +403,10 @@ def err_statically_allocated_object : Error<
"interface type cannot be statically allocated">;
def err_object_cannot_be_passed_returned_by_value : Error<
"interface type %1 cannot be %select{returned|passed}0 by value"
- "; did you forget * in %1">;
+ "; did you forget * in %1?">;
def err_parameters_retval_cannot_have_fp16_type : Error<
"%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
-def warn_pragma_options_align_unsupported_option : Warning<
- "unsupported alignment option in '#pragma options align'">;
def warn_pragma_options_align_reset_failed : Warning<
"#pragma options align=reset failed: %0">;
def err_pragma_options_align_mac68k_target_unsupported : Error<
@@ -521,7 +512,8 @@ def warn_conflicting_overriding_ret_types : Warning<
def warn_conflicting_ret_types : Warning<
"conflicting return type in "
- "implementation of %0%diff{: $ vs $|}1,2">;
+ "implementation of %0%diff{: $ vs $|}1,2">,
+ InGroup<MismatchedReturnTypes>;
def warn_conflicting_overriding_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
@@ -550,7 +542,9 @@ def warn_conflicting_overriding_param_types : Warning<
def warn_conflicting_param_types : Warning<
"conflicting parameter types in "
- "implementation of %0%diff{: $ vs $|}1,2">;
+ "implementation of %0%diff{: $ vs $|}1,2">,
+ InGroup<MismatchedParameterTypes>;
+
def warn_conflicting_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
"in implementation of %0">,
@@ -595,6 +589,8 @@ def warn_accessor_property_type_mismatch : Warning<
"type of property %0 does not match type of accessor %1">;
def not_conv_function_declared_at : Note<"type conversion function declared here">;
def note_method_declared_at : Note<"method %0 declared here">;
+def note_property_attribute : Note<"property %0 is declared "
+ "%select{deprecated|unavailable}1 here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
def warn_duplicate_method_decl :
@@ -700,7 +696,7 @@ def error_bad_property_context : Error<
"property implementation must be in a class or category implementation">;
def error_missing_property_ivar_decl : Error<
"synthesized property %0 must either be named the same as a compatible"
- " ivar or must explicitly name an ivar">;
+ " instance variable or must explicitly name an instance variable">;
def error_synthesize_weak_non_arc_or_gc : Error<
"@synthesize of 'weak' property is only allowed in ARC or GC mode">;
def err_arc_perform_selector_retains : Error<
@@ -712,38 +708,55 @@ def err_gc_weak_property_strong_type : Error<
"weak attribute declared on a __strong type property in GC mode">;
def warn_receiver_is_weak : Warning <
"weak %select{receiver|property|implicit property}0 may be "
- "unpredictably null in ARC mode">,
+ "unpredictably set to nil">,
InGroup<DiagGroup<"receiver-is-weak">>, DefaultIgnore;
+def note_arc_assign_to_strong : Note<
+ "assign the value to a strong variable to keep the object alive during use">;
+def warn_arc_repeated_use_of_weak : Warning <
+ "weak %select{variable|property|implicit property|instance variable}0 %1 is "
+ "accessed multiple times in this %select{function|method|block|lambda}2 "
+ "but may be unpredictably set to nil; assign to a strong variable to keep "
+ "the object alive">,
+ InGroup<ARCRepeatedUseOfWeak>, DefaultIgnore;
+def warn_implicitly_retains_self : Warning <
+ "block implicitly retains 'self'; explicitly mention 'self' to indicate "
+ "this is intended behavior">,
+ InGroup<DiagGroup<"implicit-retain-self">>, DefaultIgnore;
+def warn_arc_possible_repeated_use_of_weak : Warning <
+ "weak %select{variable|property|implicit property|instance variable}0 %1 may "
+ "be accessed multiple times in this %select{function|method|block|lambda}2 "
+ "and may be unpredictably set to nil; assign to a strong variable to keep "
+ "the object alive">,
+ InGroup<ARCRepeatedUseOfWeakMaybe>, DefaultIgnore;
+def note_arc_weak_also_accessed_here : Note<
+ "also accessed here">;
def err_incomplete_synthesized_property : Error<
"cannot synthesize property %0 with incomplete type %1">;
def error_property_ivar_type : Error<
- "type of property %0 (%1) does not match type of ivar %2 (%3)">;
+ "type of property %0 (%1) does not match type of instance variable %2 (%3)">;
def error_property_accessor_type : Error<
"type of property %0 (%1) does not match type of accessor %2 (%3)">;
def error_ivar_in_superclass_use : Error<
- "property %0 attempting to use ivar %1 declared in super class %2">;
+ "property %0 attempting to use instance variable %1 declared in super class %2">;
def error_weak_property : Error<
- "existing ivar %1 for __weak property %0 must be __weak">;
+ "existing instance variable %1 for __weak property %0 must be __weak">;
def error_strong_property : Error<
- "existing ivar %1 for strong property %0 may not be __weak">;
+ "existing instance variable %1 for strong property %0 may not be __weak">;
def error_dynamic_property_ivar_decl : Error<
- "dynamic property can not have ivar specification">;
+ "dynamic property can not have instance variable specification">;
def error_duplicate_ivar_use : Error<
- "synthesized properties %0 and %1 both claim ivar %2">;
+ "synthesized properties %0 and %1 both claim instance variable %2">;
def error_property_implemented : Error<"property %0 is already implemented">;
def warn_objc_property_attr_mutually_exclusive : Warning<
"property attributes '%0' and '%1' are mutually exclusive">,
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
-def warn_objc_missing_super_dealloc : Warning<
- "method possibly missing a [super dealloc] call">,
+def warn_objc_missing_super_call : Warning<
+ "method possibly missing a [super %0] call">,
InGroup<ObjCMissingSuperCalls>;
def error_dealloc_bad_result_type : Error<
"dealloc return type must be correctly specified as 'void' under ARC, "
"instead of %0">;
-def warn_objc_missing_super_finalize : Warning<
- "method possibly missing a [super finalize] call">,
- InGroup<ObjCMissingSuperCalls>;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_implicit_atomic_property : Warning<
@@ -768,7 +781,7 @@ def err_static_assert_expression_is_not_constant : Error<
def err_static_assert_failed : Error<"static_assert failed %0">;
def warn_inline_namespace_reopened_noninline : Warning<
- "inline namespace cannot be re-opened as a non-inline namespace">;
+ "inline namespace cannot be reopened as a non-inline namespace">;
def err_inline_namespace_mismatch : Error<
"%select{|non-}0inline namespace "
"cannot be reopened as %select{non-|}0inline">;
@@ -792,10 +805,11 @@ def warn_cxx98_compat_friend_is_member : Warning<
"with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def ext_unelaborated_friend_type : ExtWarn<
"unelaborated friend declaration is a C++11 extension; specify "
- "'%select{struct|union|class|enum}0' to befriend %1">, InGroup<CXX11>;
+ "'%select{struct|interface|union|class|enum}0' to befriend %1">,
+ InGroup<CXX11>;
def warn_cxx98_compat_unelaborated_friend_type : Warning<
- "befriending %1 without '%select{struct|union|class|enum}0' keyword is "
- "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+ "befriending %1 without '%select{struct|interface|union|class|enum}0' "
+ "keyword is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
@@ -806,16 +820,26 @@ 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 %2?">;
def err_partial_specialization_friend : Error<
"partial specialization cannot be declared as a friend">;
def err_qualified_friend_def : Error<
"friend function definition cannot be qualified with '%0'">;
def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
+def err_friend_not_first_in_declaration : Error<
+ "'friend' must appear first in a non-function declaration">;
+def err_invalid_member_in_interface : Error<
+ "%select{data member |non-public member function |static member function |"
+ "user-declared constructor|user-declared destructor|operator |"
+ "nested class }0%1 is not permitted within an interface type">;
+def err_invalid_base_in_interface : Error<
+ "interface type cannot inherit from "
+ "%select{'struct|non-public 'interface|'class}0 %1'">;
+
def err_abstract_type_in_decl : Error<
- "%select{return|parameter|variable|field|ivar}0 type %1 is an abstract class">;
+ "%select{return|parameter|variable|field|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<
@@ -841,6 +865,12 @@ def note_pure_virtual_function : Note<
def err_deleted_decl_not_first : Error<
"deleted definition must be first declaration">;
+def err_deleted_override : Error<
+ "deleted function %0 cannot override a non-deleted function">;
+
+def err_non_deleted_override : Error<
+ "non-deleted function %0 cannot override a deleted function">;
+
def warn_weak_vtable : Warning<
"%0 has no out-of-line virtual method definitions; its vtable will be "
"emitted in every translation unit">,
@@ -1030,7 +1060,7 @@ def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning<
"not available in the %select{constructor|destructor}1 of %2">;
def note_field_decl : Note<"member is declared here">;
-def note_ivar_decl : Note<"ivar is declared here">;
+def note_ivar_decl : Note<"instance variable is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_member_synthesized_at : Note<
@@ -1113,8 +1143,8 @@ def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
def err_constructor_byvalue_arg : Error<
"copy constructor must pass its first argument by reference">;
def warn_no_constructor_for_refconst : Warning<
- "%select{struct|union|class|enum}0 %1 does not declare any constructor to "
- "initialize its non-modifiable members">;
+ "%select{struct|interface|union|class|enum}0 %1 does not declare any "
+ "constructor to initialize its non-modifiable members">;
def note_refconst_member_not_initialized : Note<
"%select{const|reference}0 member %1 will never be initialized">;
def ext_ms_explicit_constructor_call : ExtWarn<
@@ -1214,11 +1244,18 @@ def err_init_reference_member_uninitialized : Error<
"reference member of type %0 uninitialized">;
def note_uninit_reference_member : Note<
"uninitialized reference member is here">;
-def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
+def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
+ InGroup<Uninitialized>;
+def warn_reference_field_is_uninit : Warning<
+ "reference %0 is not yet bound to a value when used here">,
InGroup<Uninitialized>;
def warn_uninit_self_reference_in_init : Warning<
"variable %0 is uninitialized when used within its own initialization">,
InGroup<Uninitialized>;
+def warn_uninit_self_reference_in_reference_init : Warning<
+ "reference %0 is not yet bound to a value when used within its own"
+ " initialization">,
+ InGroup<Uninitialized>;
def warn_uninit_var : Warning<
"variable %0 is uninitialized when %select{used here|captured by block}1">,
InGroup<Uninitialized>, DefaultIgnore;
@@ -1300,9 +1337,10 @@ 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"
- "|in non-static union member|in non-static class member|in exception declaration"
- "|in template parameter|in block literal|in template argument"
- "|in typedef|in type alias|in function return type|here}0">;
+ "|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"
+ "|here}0">;
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<
@@ -1346,6 +1384,8 @@ 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'">;
+def warn_abstract_final_class : Warning<
+ "abstract class is marked 'final'">, InGroup<AbstractFinalClass>;
// C++11 attributes
def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">;
@@ -1408,7 +1448,17 @@ def err_for_range_member_begin_end_mismatch : Error<
"range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
def err_for_range_begin_end_types_differ : Error<
"'begin' and 'end' must return the same type (got %0 and %1)">;
-def note_for_range_type : Note<"range has type %0">;
+def note_in_for_range: Note<
+ "when looking up '%select{begin|end}0' function for range expression "
+ "of type %1">;
+def err_for_range_invalid: Error<
+ "invalid range expression of type %0; no viable '%select{begin|end}1' "
+ "function available">;
+def err_for_range_dereference : Error<
+ "invalid range expression of type %0; did you mean to dereference it "
+ "with '*'?">;
+def note_for_range_invalid_iterator : Note <
+ "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
@@ -1420,7 +1470,7 @@ def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
"cannot be constexpr">;
def err_constexpr_tag : Error<
- "%select{class|struct|union|enum}0 cannot be marked constexpr">;
+ "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
def err_constexpr_no_declarators : Error<
"constexpr can only be used in variable and function declarations">;
@@ -1438,11 +1488,12 @@ def err_constexpr_redecl_mismatch : Error<
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
def err_constexpr_virtual_base : Error<
"constexpr %select{member function|constructor}0 not allowed in "
- "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">;
+ "%select{struct|interface|class}1 with virtual base "
+ "%plural{1:class|:classes}2">;
def note_non_literal_incomplete : Note<
"incomplete type %0 is not a literal type">;
-def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
- "base %plural{1:class|:classes}1 is not a literal type">;
+def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
+ "with virtual base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
"constexpr function's return type %0 is not a literal type">;
@@ -1490,10 +1541,10 @@ def note_non_literal_user_provided_dtor : Note<
def note_non_literal_nontrivial_dtor : Note<
"%0 is not literal because it has a non-trivial destructor">;
def warn_private_extern : Warning<
- "Use of __private_extern__ on tentative definition has unexpected"
- " behaviour - use __attribute__((visibility(\"hidden\"))) on extern"
- " declaration or definition instead">,
- InGroup<PrivateExtern>, DefaultIgnore;
+ "use of __private_extern__ on a declaration may not produce external symbol "
+ "private to the linkage unit and is deprecated">, InGroup<PrivateExtern>;
+def note_private_extern : Note<
+ "use __attribute__((visibility(\"hidden\"))) attribute instead">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
@@ -1681,7 +1732,9 @@ def warn_attribute_invalid_on_stmt : Warning<
"attribute %0 cannot be specified on a statement">,
InGroup<IgnoredAttributes>;
def warn_declspec_attribute_ignored : Warning<
- "attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup<IgnoredAttributes>;
+ "attribute %0 is ignored, place it after "
+ "\"%select{class|struct|union|interface|enum}1\" to apply attribute to "
+ "type declaration">, InGroup<IgnoredAttributes>;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">,
InGroup<IgnoredAttributes>;
@@ -1699,7 +1752,8 @@ def warn_nsobject_attribute : Warning<
"__attribute ((NSObject)) may be put on a typedef only, "
"attribute is ignored">, InGroup<NSobjectAttribute>;
def warn_attribute_weak_on_local : Warning<
- "__weak attribute cannot be specified on an automatic variable">,
+ "__weak attribute cannot be specified on an automatic variable when ARC "
+ "is not enabled">,
InGroup<IgnoredAttributes>;
def warn_weak_identifier_undeclared : Warning<
"weak identifier %0 never declared">;
@@ -1753,6 +1807,8 @@ def err_attribute_vecreturn_only_pod_record : Error<
def err_cconv_change : Error<
"function declared '%0' here was previously declared "
"%select{'%2'|without calling convention}1">;
+def warn_cconv_ignored : Warning<
+ "calling convention %0 ignored for this target">, InGroup<IgnoredAttributes>;
def err_cconv_knr : Error<
"function with no prototype cannot use %0 calling convention">;
def err_cconv_varargs : Error<
@@ -1840,14 +1896,6 @@ def warn_lock_exclusive_and_shared : Warning<
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def note_lock_exclusive_and_shared : Note<
"the other lock of mutex '%0' is here">;
-def warn_variable_requires_lock : Warning<
- "%select{reading|writing}2 variable '%0' requires locking "
- "%select{'%1'|'%1' exclusively}2">,
- InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
-def warn_var_deref_requires_lock : Warning<
- "%select{reading|writing}2 the value pointed to by '%0' requires locking "
- "%select{'%1'|'%1' exclusively}2">,
- InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_variable_requires_any_lock : Warning<
"%select{reading|writing}1 variable '%0' requires locking "
"%select{any mutex|any mutex exclusively}1">,
@@ -1856,9 +1904,6 @@ def warn_var_deref_requires_any_lock : Warning<
"%select{reading|writing}1 the value pointed to by '%0' requires locking "
"%select{any mutex|any mutex exclusively}1">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
-def warn_fun_requires_lock : Warning<
- "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">,
- InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_fun_excludes_mutex : Warning<
"cannot call function '%0' while mutex '%1' is locked">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
@@ -1866,6 +1911,32 @@ def warn_cannot_resolve_lock : Warning<
"cannot resolve lock expression">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
+// Imprecise thread safety warnings
+def warn_variable_requires_lock : Warning<
+ "%select{reading|writing}2 variable '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
+def warn_var_deref_requires_lock : Warning<
+ "%select{reading|writing}2 the value pointed to by '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
+def warn_fun_requires_lock : Warning<
+ "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">,
+ InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
+
+// Precise thread safety warnings
+def warn_variable_requires_lock_precise : Warning<
+ "%select{reading|writing}2 variable '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafetyPrecise>, DefaultIgnore;
+def warn_var_deref_requires_lock_precise : Warning<
+ "%select{reading|writing}2 the value pointed to by '%0' requires locking "
+ "%select{'%1'|'%1' exclusively}2">,
+ InGroup<ThreadSafetyPrecise>, DefaultIgnore;
+def warn_fun_requires_lock_precise : Warning<
+ "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">,
+ InGroup<ThreadSafetyPrecise>, DefaultIgnore;
+def note_found_mutex_near_match : Note<"found near match '%0'">;
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
@@ -1890,7 +1961,7 @@ def warn_impcast_integer_precision : Warning<
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
def warn_impcast_integer_64_32 : Warning<
"implicit conversion loses integer precision: %0 to %1">,
- InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore;
+ InGroup<Shorten64To32>, DefaultIgnore;
def warn_impcast_integer_precision_constant : Warning<
"implicit conversion from %2 to %3 changes value from %0 to %1">,
InGroup<ConstantConversion>;
@@ -1905,7 +1976,7 @@ def warn_impcast_string_literal_to_bool : Warning<
InGroup<StringConversion>, DefaultIgnore;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
- "%1">, InGroup<DiagGroup<"conversion">>;
+ "%1">, InGroup<EnumConversion>;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversion>;
@@ -1915,6 +1986,9 @@ def warn_non_literal_null_pointer : Warning<
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of NULL constant to %0">,
InGroup<NullConversion>;
+def warn_impcast_floating_point_to_bool : Warning<
+ "implicit conversion turns floating-point number into bool: %0 to %1">,
+ InGroup<ImplicitConversionFloatingPointToBool>;
def warn_impcast_function_to_bool : Warning<
"address of function %q0 will always evaluate to 'true'">,
InGroup<BoolConversion>;
@@ -1927,6 +2001,10 @@ def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
InGroup<CastAlign>, DefaultIgnore;
+def warn_int_to_pointer_cast : Warning<
+ "cast to %1 from smaller integer type %0">,
+ InGroup<IntToPointerCast>;
+
def warn_attribute_ignored_for_field_of_type : Warning<
"%0 attribute ignored for field of type %1">,
InGroup<IgnoredAttributes>;
@@ -2008,7 +2086,7 @@ def warn_attribute_ibaction: Warning<
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
def warn_iboutlet_object_type : Warning<
- "%select{ivar|property}2 with %0 attribute must "
+ "%select{instance variable|property}2 with %0 attribute must "
"be an object type (invalid %1)">,
InGroup<DiagGroup<"invalid-iboutlet">>;
def err_attribute_overloadable_not_function : Error<
@@ -2028,6 +2106,12 @@ def warn_ns_attribute_wrong_parameter_type : Warning<
"%0 attribute only applies to %select{Objective-C object|pointer}1 "
"parameters">,
InGroup<IgnoredAttributes>;
+def warn_objc_requires_super_protocol : Warning<
+ "%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">,
+ InGroup<DiagGroup<"requires-super-attribute">>;
+def note_protocol_decl : Note<
+ "protocol is declared here">;
+
def err_ns_bridged_not_interface : Error<
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;
@@ -3058,6 +3142,9 @@ def note_sentinel_here : Note<
def warn_missing_prototype : Warning<
"no previous prototype for function %0">,
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
+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_definition_of_implicitly_declared_member : Error<
"definition of implicitly declared %select{default constructor|copy "
@@ -3144,7 +3231,7 @@ def err_non_thread_thread : Error<
def err_thread_non_thread : Error<
"thread-local declaration of %0 follows non-thread-local declaration">;
def err_redefinition_different_type : Error<
- "redefinition of %0 with a different type">;
+ "redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def warn_forward_class_redefinition : Warning<
@@ -3159,8 +3246,8 @@ def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with "
"%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
def err_dependent_tag_decl : Error<
- "%select{declaration|definition}0 of %select{struct|union|class|enum}1 "
- "in a dependent scope">;
+ "%select{declaration|definition}0 of "
+ "%select{struct|interface|union|class|enum}1 in a dependent scope">;
def err_tag_definition_of_typedef : Error<
"definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
@@ -3168,15 +3255,16 @@ def err_nested_redefinition : Error<"nested redefinition of %0">;
def err_use_with_wrong_tag : Error<
"use of %0 with tag type that does not match previous declaration">;
def warn_struct_class_tag_mismatch : Warning<
- "%select{struct|class}0%select{| template}1 %2 was previously declared "
- "as a %select{class|struct}0%select{| template}1">,
+ "%select{struct|interface|class}0%select{| template}1 %2 was previously "
+ "declared as a %select{struct|interface|class}3%select{| template}1">,
InGroup<MismatchedTags>, DefaultIgnore;
def warn_struct_class_previous_tag_mismatch : Warning<
- "%2 defined as a %select{struct|class}0%select{| template}1 here but "
- "previously declared as a %select{class|struct}0%select{| template}1">,
+ "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 "
+ "here but previously declared as "
+ "%select{a struct|an interface|a class}3%select{| template}1">,
InGroup<MismatchedTags>, DefaultIgnore;
def note_struct_class_suggestion : Note<
- "did you mean %select{struct|class}0 here?">;
+ "did you mean %select{struct|interface|class}0 here?">;
def ext_forward_ref_enum : Extension<
"ISO C forbids forward references to 'enum' types">;
def err_forward_ref_enum : Error<
@@ -3189,9 +3277,9 @@ def ext_forward_ref_enum_def : Extension<
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def err_misplaced_ivar : Error<
- "ivars may not be placed in %select{categories|class extension}0">;
+ "instance variables may not be placed in %select{categories|class extension}0">;
def warn_ivars_in_interface : Warning<
- "declaration of ivars in the interface is deprecated">,
+ "declaration of instance variables in the interface is deprecated">,
InGroup<DiagGroup<"objc-interface-ivars">>, DefaultIgnore;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
@@ -3220,11 +3308,13 @@ def warn_array_new_too_large : Warning<"array is too large (%0 elements)">,
// -Wpadded, -Wpacked
def warn_padded_struct_field : Warning<
- "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 "
- "to align %5">, InGroup<Padded>, DefaultIgnore;
+ "padding %select{struct|interface|class}0 %1 with %2 "
+ "%select{byte|bit}3%select{|s}4 to align %5">,
+ InGroup<Padded>, DefaultIgnore;
def warn_padded_struct_anon_field : Warning<
- "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 "
- "to align anonymous bit-field">, InGroup<Padded>, DefaultIgnore;
+ "padding %select{struct|interface|class}0 %1 with %2 "
+ "%select{byte|bit}3%select{|s}4 to align anonymous bit-field">,
+ InGroup<Padded>, DefaultIgnore;
def warn_padded_struct_size : Warning<
"padding size of %0 with %1 %select{byte|bit}2%select{|s}3 "
"to alignment boundary">, InGroup<Padded>, DefaultIgnore;
@@ -3244,7 +3334,7 @@ def err_typecheck_invalid_restrict_not_pointer_noarg : Error<
def err_typecheck_invalid_restrict_invalid_pointee : Error<
"pointer to function type %0 may not be 'restrict' qualified">;
def ext_typecheck_zero_array_size : Extension<
- "zero size arrays are an extension">;
+ "zero size arrays are an extension">, InGroup<ZeroLengthArray>;
def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in C++">;
def warn_typecheck_zero_static_array_size : Warning<
@@ -3354,7 +3444,7 @@ def warn_anon_bitfield_width_exceeds_type_size : Warning<
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
- InGroup<DiagGroup<"missing-braces">>, DefaultIgnore;
+ InGroup<MissingBraces>, DefaultIgnore;
def err_missing_braces : Error<
"cannot omit braces around initialization of subobject when using direct "
"list-initialization">;
@@ -3472,14 +3562,16 @@ def ext_flexible_array_in_array : Extension<
def err_flexible_array_init : Error<
"initialization of flexible array member is not allowed">;
def ext_flexible_array_empty_aggregate_ms : Extension<
- "flexible array member %0 in otherwise empty %select{struct|class}1 "
- "is a Microsoft extension">, InGroup<Microsoft>;
+ "flexible array member %0 in otherwise empty "
+ "%select{struct|interface|union|class|enum}1 is a Microsoft extension">,
+ InGroup<Microsoft>;
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|class}1 "
- "is a GNU extension">, InGroup<GNU>;
+ "flexible array member %0 in otherwise empty "
+ "%select{struct|interface|union|class|enum}1 is a GNU extension">,
+ InGroup<GNU>;
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
@@ -3497,7 +3589,7 @@ def err_arc_weak_unavailable_assign : Error<
"assignment of a weak-unavailable object to a __weak object">;
def err_arc_weak_unavailable_property : Error<
"synthesis of a weak-unavailable property is disallowed "
- "because it requires synthesis of an ivar of the __weak object">;
+ "because it requires synthesis of an instance variable of the __weak object">;
def err_arc_convesion_of_weak_unavailable : Error<
"%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to"
" a __weak object of type %2">;
@@ -3527,6 +3619,9 @@ 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">;
+def warn_arc_strong_pointer_objc_pointer : Warning<
+ "method parameter of type %0 with no explicit ownership">,
+ InGroup<DiagGroup<"explicit-ownership-type">>, DefaultIgnore;
} // end "ARC Restrictions" category
@@ -3549,11 +3644,6 @@ def err_typecheck_arc_assign_self_class_method : Error<
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables can't be modified in ARC by default; "
"declare the variable __strong to allow this">;
-def warn_arc_non_pod_class_with_object_member : Warning<
- "%0 cannot be shared between ARC and non-ARC "
- "code; add a copy constructor, a copy assignment operator, and a destructor "
- "to make it ABI-compatible">, InGroup<AutomaticReferenceCountingABI>,
- DefaultIgnore;
def warn_arc_retained_assign : Warning<
"assigning retained object to %select{weak|unsafe_unretained}0 "
"%select{property|variable}1"
@@ -3563,19 +3653,10 @@ def warn_arc_retained_property_assign : Warning<
"assigning retained object to unsafe property"
"; object will be released after assignment">,
InGroup<ARCUnsafeRetainedAssign>;
-def warn_arc_trivial_member_function_with_object_member : Warning<
- "%0 cannot be shared between ARC and non-ARC "
- "code; add a non-trivial %select{copy constructor|copy assignment operator|"
- "destructor}1 to make it ABI-compatible">,
- InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
def err_arc_new_array_without_ownership : Error<
"'new' cannot allocate an array of %0 with no explicit ownership">;
-def warn_err_new_delete_object_array : Warning<
- "%select{allocating|destroying}0 an array of %1; this array must not "
- "%select{be deleted in|have been allocated from}0 non-ARC code">,
- InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
def err_arc_autoreleasing_var : Error<
- "%select{__block variables|global variables|fields|ivars}0 cannot have "
+ "%select{__block variables|global variables|fields|instance variables}0 cannot have "
"__autoreleasing ownership">;
def err_arc_autoreleasing_capture : Error<
"cannot capture __autoreleasing variable in a "
@@ -3632,10 +3713,10 @@ def warn_arc_object_memaccess : Warning<
let CategoryName = "ARC and @properties" in {
def err_arc_strong_property_ownership : Error<
- "existing ivar %1 for strong property %0 may not be "
+ "existing instance variable %1 for strong property %0 may not be "
"%select{|__unsafe_unretained||__weak}2">;
def err_arc_assign_property_ownership : Error<
- "existing ivar %1 for property %0 with %select{unsafe_unretained| assign}2 "
+ "existing instance variable %1 for property %0 with %select{unsafe_unretained| assign}2 "
"attribute must be __unsafe_unretained">;
def err_arc_inconsistent_property_ownership : Error<
"%select{|unsafe_unretained|strong|weak}1 property %0 may not also be "
@@ -3766,16 +3847,14 @@ def warn_precedence_bitwise_rel : Warning<
InGroup<Parentheses>;
def note_precedence_bitwise_first : Note<
"place parentheses around the %0 expression to evaluate it first">;
-def note_precedence_bitwise_silence : Note<
- "place parentheses around the %0 expression to silence this warning">;
+def note_precedence_silence : Note<
+ "place parentheses around the '%0' expression to silence this warning">;
def warn_precedence_conditional : Warning<
"operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">,
InGroup<Parentheses>;
def note_precedence_conditional_first : Note<
"place parentheses around the '?:' expression to evaluate it first">;
-def note_precedence_conditional_silence : Note<
- "place parentheses around the '%0' expression to silence this warning">;
def warn_logical_instead_of_bitwise : Warning<
"use of logical '%0' with constant operand">,
@@ -3787,13 +3866,13 @@ def note_logical_instead_of_bitwise_remove_constant : Note<
def warn_bitwise_and_in_bitwise_or : Warning<
"'&' within '|'">, InGroup<BitwiseOpParentheses>;
-def note_bitwise_and_in_bitwise_or_silence : Note<
- "place parentheses around the '&' expression to silence this warning">;
def warn_logical_and_in_logical_or : Warning<
"'&&' within '||'">, InGroup<LogicalOpParentheses>;
-def note_logical_and_in_logical_or_silence : Note<
- "place parentheses around the '&&' expression to silence this warning">;
+
+def warn_addition_in_bitshift : Warning<
+ "operator '%0' has lower precedence than '%1'; "
+ "'%1' will be evaluated first">, InGroup<ShiftOpParentheses>;
def warn_self_assignment : Warning<
"explicitly assigning a variable of type %0 to itself">,
@@ -3896,6 +3975,8 @@ def ext_out_of_line_declaration : ExtWarn<
"out-of-line declaration of a member must be a definition">,
InGroup<OutOfLineDeclaration>, DefaultError;
def warn_member_extra_qualification : Warning<
+ "extra qualification on member %0">, InGroup<Microsoft>;
+def err_member_extra_qualification : Error<
"extra qualification on member %0">;
def err_member_qualification : Error<
"non-friend class member %0 cannot have a qualified name">;
@@ -4013,7 +4094,8 @@ def ext_typecheck_comparison_of_pointer_integer : ExtWarn<
def err_typecheck_comparison_of_pointer_integer : Error<
"comparison between pointer and integer (%0 and %1)">;
def ext_typecheck_comparison_of_distinct_pointers : ExtWarn<
- "comparison of distinct pointer types%diff{ ($ and $)|}0,1">;
+ "comparison of distinct pointer types%diff{ ($ and $)|}0,1">,
+ InGroup<CompareDistinctPointerType>;
def ext_typecheck_cond_incompatible_operands : ExtWarn<
"incompatible operand types (%0 and %1)">;
def err_cond_voidptr_arc : Error <
@@ -4023,7 +4105,7 @@ def err_typecheck_comparison_of_distinct_pointers : Error<
"comparison of distinct pointer types%diff{ ($ and $)|}0,1">;
def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
"comparison of distinct pointer types (%0 and %1) uses non-standard "
- "composite pointer type %2">;
+ "composite pointer type %2">, InGroup<CompareDistinctPointerType>;
def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
def err_stmtexpr_file_scope : Error<
"statement expression not allowed at file scope">;
@@ -4033,6 +4115,9 @@ def warn_mixed_sign_comparison : Warning<
def warn_lunsigned_always_true_comparison : Warning<
"comparison of unsigned%select{| enum}2 expression %0 is always %1">,
InGroup<TautologicalCompare>;
+def warn_out_of_range_compare : Warning<
+ "comparison of constant %0 with expression of type %1 is always "
+ "%select{false|true}2">, InGroup<TautologicalOutOfRangeCompare>;
def warn_runsigned_always_true_comparison : Warning<
"comparison of %0 unsigned%select{| enum}2 expression is always %1">,
InGroup<TautologicalCompare>;
@@ -4166,7 +4251,7 @@ def err_nogetter_property_incdec : Error<
def error_no_subobject_property_setting : Error<
"expression is not assignable">;
def err_qualified_objc_access : Error<
- "%select{property|ivar}0 access cannot be qualified with '%1'">;
+ "%select{property|instance variable}0 access cannot be qualified with '%1'">;
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;
@@ -4562,7 +4647,7 @@ def err_invalid_declarator_global_scope : Error<
def err_invalid_declarator_in_function : Error<
"definition or redeclaration of %0 not allowed inside a function">;
def err_not_tag_in_scope : Error<
- "no %select{struct|union|class|enum}0 named %1 in %2">;
+ "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">;
@@ -4885,6 +4970,8 @@ def note_callee_decl : Note<
"%0 declared here">;
def note_defined_here : Note<"%0 defined here">;
+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<
@@ -4898,6 +4985,9 @@ def err_atomic_builtin_pointer_size : Error<
def err_atomic_op_needs_atomic : Error<
"first 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 "
+ "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)">;
@@ -4960,7 +5050,9 @@ def err_typecheck_cast_to_incomplete : Error<
"cast to incomplete type %0">;
def ext_typecheck_cast_nonscalar : Extension<
"C99 forbids casting nonscalar type %0 to the same type">;
-def ext_typecheck_cast_to_union : Extension<"C99 forbids casts to union type">;
+def ext_typecheck_cast_to_union : Extension<
+ "cast to union type is a GNU extension">,
+ InGroup<GNU>;
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<
@@ -4968,6 +5060,9 @@ def err_cast_pointer_from_non_pointer_int : Error<
def warn_cast_pointer_from_sel : Warning<
"cast of type %0 to %1 is deprecated; use sel_getName instead">,
InGroup<SelTypeCast>;
+def warn_bad_function_cast : Warning<
+ "cast from function call of type %0 to non-matching type %1">,
+ InGroup<BadFunctionCast>, DefaultIgnore;
def err_cast_pointer_to_non_pointer_int : Error<
"pointer cannot be cast to type %0">;
def err_typecheck_expect_scalar_operand : Error<
@@ -5045,19 +5140,21 @@ let CategoryName = "Inline Assembly Issue" in {
"unsupported inline asm: input with type "
"%diff{$ matching output with type $|}0,1">;
def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
- def warn_asm_label_on_auto_decl : Warning<
- "ignored asm label '%0' on automatic variable">;
+ def err_asm_empty : Error<"__asm used with no assembly instructions">;
def err_invalid_asm_cast_lvalue : Error<
"invalid use of a cast in a inline asm context requiring an l-value: "
"remove the cast or build with -fheinous-gnu-extensions">;
+ def err_inline_ms_asm_parsing : Error<"%0">;
+ def warn_asm_label_on_auto_decl : Warning<
+ "ignored asm label '%0' on automatic variable">;
def warn_invalid_asm_cast_lvalue : Warning<
- "invalid use of a cast in a inline asm context requiring an l-value: "
+ "invalid use of a cast in an inline asm context requiring an l-value: "
"accepted due to -fheinous-gnu-extensions, but clang may remove support "
"for this in the future">;
-
- def warn_unsupported_msasm : ExtWarn<
- "MS-style inline assembly is not supported">, InGroup<Microsoft>;
+ def warn_asm_mismatched_size_modifier : Warning<
+ "the size being stored is truncated, use a modifier to specify the size">,
+ InGroup<ASMOperandWidths>;
}
let CategoryName = "Semantic Issue" in {
@@ -5122,7 +5219,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">;
+ "folding it to a constant is a GNU extension">, InGroup<GNU>;
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
@@ -5178,6 +5275,8 @@ def err_static_data_member_not_allowed_in_local_class : Error<
def err_base_clause_on_union : Error<"unions cannot have base classes">;
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_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">;
@@ -5340,6 +5439,10 @@ 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 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 "
+ "specification">, InGroup<DiagGroup<"implicit-exception-spec-mismatch">>;
def warn_ptr_arith_precedes_bounds : Warning<
"the pointer decremented by %0 refers before the beginning of the array">,
@@ -5373,6 +5476,10 @@ def warn_scanf_nonzero_width : Warning<
def warn_printf_conversion_argument_type_mismatch : Warning<
"format specifies type %0 but the argument has type %1">,
InGroup<Format>;
+def warn_format_argument_needs_cast : Warning<
+ "values of type '%0' should not be used as format arguments; add an explicit "
+ "cast to %1 instead">,
+ InGroup<Format>;
def warn_printf_positional_arg_exceeds_data_args : Warning <
"data argument position '%0' exceeds the number of data arguments (%1)">,
InGroup<Format>;
@@ -5397,7 +5504,8 @@ def warn_format_string_is_wide_literal : Warning<
def warn_printf_format_string_contains_null_char : Warning<
"format string contains '\\0' within the string body">, InGroup<Format>;
def warn_printf_asterisk_missing_arg : Warning<
- "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">;
+ "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">,
+ InGroup<Format>;
def warn_printf_asterisk_wrong_type : Warning<
"field %select{width|precision}0 should have type %1, but argument has type %2">,
InGroup<Format>;
@@ -5425,6 +5533,7 @@ def warn_scanf_scanlist_incomplete : Warning<
"no closing ']' for '%%[' in scanf format string">,
InGroup<Format>;
def note_format_string_defined : Note<"format string is defined here">;
+def note_format_fix_specifier : Note<"did you mean to use '%0'?">;
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
def warn_null_arg : Warning<
@@ -5588,7 +5697,7 @@ def warn_unannotated_fallthrough_per_function : Warning<
"unannotated fall-through between switch labels in partly-annotated "
"function">, InGroup<ImplicitFallthroughPerFunction>, DefaultIgnore;
def note_insert_fallthrough_fixit : Note<
- "insert '[[clang::fallthrough]];' to silence this warning">;
+ "insert '%0;' to silence this warning">;
def note_insert_break_fixit : Note<
"insert 'break;' to avoid fall-through">;
def err_fallthrough_attr_wrong_target : Error<
@@ -5824,7 +5933,7 @@ def err_typecheck_member_reference_ivar_suggest : Error<
def err_property_not_found_suggest : Error<
"property %0 not found on object of type %1; did you mean %2?">;
def err_ivar_access_using_property_syntax_suggest : Error<
- "property %0 not found on object of type %1; did you mean to access ivar %2?">;
+ "property %0 not found on object of type %1; did you mean to access instance variable %2?">;
def err_property_found_suggest : Error<
"property %0 found on object of type %1; did you mean to access "
"it with the \".\" operator?">;
@@ -5911,7 +6020,7 @@ def err_module_private_local : Error<
"%select{local variable|parameter|typedef}0 %1 cannot be declared "
"__module_private__">;
def err_module_private_local_class : Error<
- "local %select{struct|union|class|enum}0 cannot be declared "
+ "local %select{struct|interface|union|class|enum}0 cannot be declared "
"__module_private__">;
def err_module_private_definition : Error<
"definition of %0 must be imported before it is required">;
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index a440e806d735..e9df09d114db 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -25,9 +25,13 @@ def err_fe_pch_file_modified : Error<
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
-def warn_pch_target_triple : Error<
- "PCH file was compiled for the target '%0' but the current translation "
- "unit is being compiled for target '%1'">;
+def err_pch_targetopt_mismatch : Error<
+ "PCH file was compiled for the %0 '%1' but the current translation "
+ "unit is being compiled for target '%2'">;
+def err_pch_targetopt_feature_mismatch : Error<
+ "%select{AST file|current translation unit}0 was compiled with the target "
+ "feature'%1' but the %select{current translation unit is|AST file was}0 "
+ "not">;
def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
"PCH file but is currently %select{disabled|enabled}2">;
def err_pch_langopt_value_mismatch : Error<
@@ -41,21 +45,24 @@ def warn_pch_different_branch : Error<
"PCH file built from a different branch (%0) than the compiler (%1)">;
def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
-def warn_cmdline_conflicting_macro_def : Error<
- "definition of the macro '%0' conflicts with the definition used to "
- "build the precompiled header">;
-def note_pch_macro_defined_as : Note<
- "definition of macro '%0' in the precompiled header">;
-def warn_cmdline_missing_macro_defs : Warning<
- "macro definitions used to build the precompiled header are missing">;
-def note_using_macro_def_from_pch : Note<
- "using this macro definition from precompiled header">;
-def warn_macro_name_used_in_pch : Error<
- "definition of macro %0 conflicts with an identifier used in the "
- "precompiled header">;
-def warn_pch_compiler_options_mismatch : Error<
- "compiler options used when building the precompiled header differ from "
- "the options used when using the precompiled header">;
+
+
+def err_pch_macro_def_undef : Error<
+ "macro '%0' was %select{defined|undef'd}1 in the precompiled header but "
+ "%select{undef'd|defined}1 on the command line">;
+def err_pch_macro_def_conflict : Error<
+ "definition of macro '%0' differs between the precompiled header ('%1') "
+ "and the command line ('%2')">;
+def err_pch_include_opt_missing : Error<
+ "precompiled header depends on '%select{-include|-imacros}0 %1' option "
+ "that is missing from the command line">;
+def err_pch_include_opt_conflict : Error<
+ "precompiled header option '%select{-include|-imacros}0 %1' conflicts with "
+ "corresponding option '%select{-include|-imacros}0 %2' on command line">;
+def err_pch_undef : Error<
+ "%select{command line contains|precompiled header was built with}0 "
+ "'-undef' but %select{precompiled header was not built with it|"
+ "it is not present on the command line}0">;
def err_not_a_pch_file : Error<
"'%0' does not appear to be a precompiled header file">, DefaultFatal;
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index b00f2b782709..b2f578da7b49 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -103,6 +103,10 @@ public:
bool operator<(const FileEntry &RHS) const {
return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
}
+
+ /// \brief Check whether the file is a named pipe (and thus can't be opened by
+ /// the native FileManager methods).
+ bool isNamedPipe() const;
};
/// \brief Implements support for file system lookup, file system caching,
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index dc6acdaa91ae..76242ec0a56d 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -21,7 +21,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <string>
@@ -54,6 +53,7 @@ class IdentifierInfo {
// are for builtins.
unsigned ObjCOrBuiltinID :11;
bool HasMacro : 1; // True if there is a #define for this.
+ bool HadMacro : 1; // True if there was a #define for this.
bool IsExtension : 1; // True if identifier is a lang extension.
bool IsCXX11CompatKeyword : 1; // True if identifier is a keyword in C++11.
bool IsPoisoned : 1; // True if identifier is poisoned.
@@ -70,13 +70,13 @@ class IdentifierInfo {
// stored externally.
bool IsModulesImport : 1; // True if this is the 'import' contextual
// keyword.
- // 1 bit left in 32-bit word.
-
+ // 32-bit word is filled.
+
void *FETokenInfo; // Managed by the language front-end.
llvm::StringMapEntry<IdentifierInfo*> *Entry;
- IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE.
- void operator=(const IdentifierInfo&); // NONASSIGNABLE.
+ IdentifierInfo(const IdentifierInfo&) LLVM_DELETED_FUNCTION;
+ void operator=(const IdentifierInfo&) LLVM_DELETED_FUNCTION;
friend class IdentifierTable;
@@ -133,10 +133,21 @@ public:
if (HasMacro == Val) return;
HasMacro = Val;
- if (Val)
+ if (Val) {
NeedsHandleIdentifier = 1;
- else
+ HadMacro = true;
+ } else {
RecomputeNeedsHandleIdentifier();
+ }
+ }
+ /// \brief Returns true if this identifier was \#defined to some value at any
+ /// moment. In this case there should be an entry for the identifier in the
+ /// macro history table in Preprocessor.
+ bool hadMacroDefinition() const {
+ return HadMacro;
+ }
+ void setHadMacroDefinition(bool Val) {
+ HadMacro = Val;
}
/// getTokenID - If this is a source-language token (e.g. 'for'), this API
@@ -346,8 +357,8 @@ public:
/// actual functionality.
class IdentifierIterator {
private:
- IdentifierIterator(const IdentifierIterator&); // Do not implement
- IdentifierIterator &operator=(const IdentifierIterator&); // Do not implement
+ IdentifierIterator(const IdentifierIterator &) LLVM_DELETED_FUNCTION;
+ void operator=(const IdentifierIterator &) LLVM_DELETED_FUNCTION;
protected:
IdentifierIterator() { }
@@ -695,8 +706,8 @@ public:
/// multi-keyword caching.
class SelectorTable {
void *Impl; // Actually a SelectorTableImpl
- SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
- void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
+ SelectorTable(const SelectorTable &) LLVM_DELETED_FUNCTION;
+ void operator=(const SelectorTable &) LLVM_DELETED_FUNCTION;
public:
SelectorTable();
~SelectorTable();
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index fab17a2fe56e..dbc08c7dca1f 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -48,15 +48,19 @@ LANGOPT(MicrosoftMode , 1, 0, "Microsoft compatibility mode")
LANGOPT(Borland , 1, 0, "Borland extensions")
LANGOPT(CPlusPlus , 1, 0, "C++")
LANGOPT(CPlusPlus0x , 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,
"Objective-C auto-synthesized properties")
+BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0,
+ "Encoding extended block type signature")
BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1,
"Objective-C related result type inference")
LANGOPT(Trigraphs , 1, 0,"trigraphs")
-LANGOPT(BCPLComment , 1, 0, "BCPL-style '//' comments")
+LANGOPT(LineComment , 1, 0, "'//' comments")
LANGOPT(Bool , 1, 0, "bool, true, and false keywords")
+LANGOPT(WChar , 1, CPlusPlus, "wchar_t keyword")
BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers")
BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions")
@@ -115,7 +119,6 @@ LANGOPT(CUDA , 1, 0, "CUDA")
LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
-BENIGN_LANGOPT(CatchUndefined , 1, 0, "catching undefined behavior at run time")
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")
BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables")
@@ -125,8 +128,6 @@ BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type")
BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and subscripting support")
-BENIGN_LANGOPT(AddressSanitizer , 1, 0, "AddressSanitizer enabled")
-BENIGN_LANGOPT(ThreadSanitizer , 1, 0, "ThreadSanitizer enabled")
BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
@@ -135,7 +136,7 @@ LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
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(ObjCRuntimeHasWeak , 1, 0, "__weak support in the ARC runtime")
+LANGOPT(ObjCARCWeak , 1, 0, "__weak support in the ARC runtime")
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
LANGOPT(MRTD , 1, 0, "-mrtd calling convention")
@@ -162,6 +163,17 @@ VALUE_LANGOPT(MSCVersion, 32, 0,
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
+BENIGN_LANGOPT(EmitMicrosoftInlineAsm , 1, 0,
+ "Enable emission of MS-style inline assembly.")
+
+
+BENIGN_LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
+
+/// Runtime sanitizers.
+#define SANITIZER(NAME, ID) \
+BENIGN_LANGOPT(Sanitize##ID, 1, 0, NAME " sanitizer")
+#include "clang/Basic/Sanitizers.def"
+
#undef LANGOPT
#undef VALUE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index c8027f47028f..b6b088c1f701 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -21,6 +21,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SetVector.h"
#include <string>
#include <utility>
#include <vector>
@@ -63,11 +64,21 @@ private:
/// \brief A mapping from the submodule name to the index into the
/// \c SubModules vector at which that submodule resides.
llvm::StringMap<unsigned> SubModuleIndex;
+
+ /// \brief The AST file if this is a top-level module which has a
+ /// corresponding serialized AST file, or null otherwise.
+ const FileEntry *ASTFile;
public:
/// \brief The headers that are part of this module.
llvm::SmallVector<const FileEntry *, 2> Headers;
+ /// \brief The headers that are explicitly excluded from this module.
+ llvm::SmallVector<const FileEntry *, 2> ExcludedHeaders;
+
+ /// \brief The top-level headers associated with this module.
+ llvm::SmallSetVector<const FileEntry *, 2> TopHeaders;
+
/// \brief The set of language features required to use this module.
///
/// If any of these features is not present, the \c IsAvailable bit
@@ -158,7 +169,7 @@ public:
/// \brief Construct a top-level module.
explicit Module(StringRef Name, SourceLocation DefinitionLoc,
bool IsFramework)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), Umbrella(),
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0),Umbrella(),ASTFile(0),
IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
IsExplicit(false), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
@@ -227,7 +238,18 @@ public:
StringRef getTopLevelModuleName() const {
return getTopLevelModule()->Name;
}
-
+
+ /// \brief The serialized AST file for this module, if one was created.
+ const FileEntry *getASTFile() const {
+ return getTopLevelModule()->ASTFile;
+ }
+
+ /// \brief Set the serialized AST file for the top-level module of this module.
+ void setASTFile(const FileEntry *File) {
+ assert((getASTFile() == 0 || getASTFile() == File) && "file path changed");
+ getTopLevelModule()->ASTFile = File;
+ }
+
/// \brief Retrieve the directory for which this module serves as the
/// umbrella.
const DirectoryEntry *getUmbrellaDir() const;
@@ -271,6 +293,10 @@ public:
submodule_iterator submodule_end() { return SubModules.end(); }
submodule_const_iterator submodule_end() const { return SubModules.end(); }
+ static StringRef getModuleInputBufferName() {
+ return "<module-includes>";
+ }
+
/// \brief Print the module map for this module to the given stream.
///
void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index b24fe7cd9159..d543b7671549 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -126,12 +126,25 @@ public:
return !isGNUFamily();
}
+ /// \brief Does this runtime allow ARC at all?
+ bool allowsARC() const {
+ switch (getKind()) {
+ case FragileMacOSX: return false;
+ case MacOSX: return true;
+ case iOS: return true;
+ case GCC: return false;
+ case GNUstep: return true;
+ case ObjFW: return true;
+ }
+ llvm_unreachable("bad kind");
+ }
+
/// \brief Does this runtime natively provide the ARC entrypoints?
///
/// ARC cannot be directly supported on a platform that does not provide
/// these entrypoints, although it may be supportable via a stub
/// library.
- bool hasARC() const {
+ bool hasNativeARC() const {
switch (getKind()) {
case FragileMacOSX: return false;
case MacOSX: return getVersion() >= VersionTuple(10, 7);
@@ -139,16 +152,35 @@ public:
case GCC: return false;
case GNUstep: return getVersion() >= VersionTuple(1, 6);
- case ObjFW: return false; // XXX: this will change soon
+ case ObjFW: return true;
}
llvm_unreachable("bad kind");
}
+ /// \brief Does this runtime supports optimized setter entrypoints?
+ bool hasOptimizedSetter() const {
+ switch (getKind()) {
+ case MacOSX:
+ return getVersion() >= VersionTuple(10, 8);
+ case iOS:
+ return (getVersion() >= VersionTuple(6));
+
+ default:
+ return false;
+ }
+ }
+
+ /// Does this runtime allow the use of __weak?
+ bool allowsWeak() const {
+ return hasNativeWeak();
+ }
+
/// \brief Does this runtime natively provide ARC-compliant 'weak'
/// entrypoints?
- bool hasWeak() const {
- // Right now, this is always equivalent to the ARC decision.
- return hasARC();
+ bool hasNativeWeak() const {
+ // Right now, this is always equivalent to whether the runtime
+ // natively supports ARC decision.
+ return hasNativeARC();
}
/// \brief Does this runtime directly support the subscripting methods?
@@ -158,7 +190,7 @@ public:
switch (getKind()) {
case FragileMacOSX: return false;
case MacOSX: return getVersion() >= VersionTuple(10, 8);
- case iOS: return false;
+ case iOS: return getVersion() >= VersionTuple(6);
// This is really a lie, because some implementations and versions
// of the runtime do not support ARC. Probably -fgnu-runtime
@@ -226,6 +258,7 @@ public:
}
llvm_unreachable("bad kind");
}
+
/// \brief Does this runtime use zero-cost exceptions?
bool hasUnwindExceptions() const {
switch (getKind()) {
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
index 79273fcc798d..cc9ca9f2ec37 100644
--- a/include/clang/Basic/OnDiskHashTable.h
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -65,8 +65,7 @@ inline void Emit64(raw_ostream& Out, uint64_t V) {
inline void Pad(raw_ostream& Out, unsigned A) {
Offset off = (Offset) Out.tell();
- uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off;
- for (; n ; --n)
+ for (uint32_t n = llvm::OffsetToAlignment(off, A); n; --n)
Emit8(Out, 0);
}
@@ -102,7 +101,7 @@ inline uint64_t ReadUnalignedLE64(const unsigned char *&Data) {
inline uint32_t ReadLE32(const unsigned char *&Data) {
// Hosts that directly support little-endian 32-bit loads can just
// use them. Big-endian hosts need a bswap.
- uint32_t V = *((uint32_t*)Data);
+ uint32_t V = *((const uint32_t*)Data);
if (llvm::sys::isBigEndianHost())
V = llvm::ByteSwap_32(V);
Data += 4;
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
new file mode 100644
index 000000000000..085ca16eae1a
--- /dev/null
+++ b/include/clang/Basic/Sanitizers.def
@@ -0,0 +1,69 @@
+//===--- Sanitizers.def - Runtime sanitizer options -------------*- 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 options for specifying which runtime sanitizers to
+// enable. Users of this file must define the SANITIZER macro to make use of
+// this information. Users of this file can also define the SANITIZER_GROUP
+// macro to get information on options which refer to sets of sanitizers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER
+#error "Define SANITIZER prior to including this file!"
+#endif
+
+// SANITIZER(NAME, ID)
+
+// The first value is the name of the sanitizer as a string. The sanitizer can
+// be enabled by specifying -fsanitize=NAME.
+
+// The second value is an identifier which can be used to refer to the
+// sanitizer.
+
+
+// SANITIZER_GROUP(NAME, ID, ALIAS)
+
+// The first two values have the same semantics as the corresponding SANITIZER
+// values. The third value is an expression ORing together the IDs of individual
+// sanitizers in this group.
+
+#ifndef SANITIZER_GROUP
+#define SANITIZER_GROUP(NAME, ID, ALIAS)
+#endif
+
+
+// AddressSanitizer
+SANITIZER("address", Address)
+
+// ThreadSanitizer
+SANITIZER("thread", Thread)
+
+// UndefinedBehaviorSanitizer
+SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
+SANITIZER("divide-by-zero", DivideByZero)
+SANITIZER("shift", Shift)
+SANITIZER("unreachable", Unreachable)
+SANITIZER("return", Return)
+SANITIZER("vla-bound", VLABound)
+SANITIZER("alignment", Alignment)
+SANITIZER("null", Null)
+SANITIZER("vptr", Vptr)
+SANITIZER("object-size", ObjectSize)
+SANITIZER("float-cast-overflow", FloatCastOverflow)
+
+// -fsanitize=undefined (and its alias -fcatch-undefined-behavior). This should
+// include all the sanitizers which have low overhead, no ABI or address space
+// layout implications, and only catch undefined behavior.
+SANITIZER_GROUP("undefined", Undefined,
+ SignedIntegerOverflow | DivideByZero | Shift | Unreachable |
+ Return | VLABound | Alignment | Null | Vptr | ObjectSize |
+ FloatCastOverflow)
+
+#undef SANITIZER
+#undef SANITIZER_GROUP
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index d6bba385633d..cfcf468772ef 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -21,6 +21,7 @@
#include <utility>
#include <functional>
#include <cassert>
+#include <string>
namespace llvm {
class MemoryBuffer;
@@ -171,6 +172,7 @@ public:
}
void print(raw_ostream &OS, const SourceManager &SM) const;
+ LLVM_ATTRIBUTE_USED std::string printToString(const SourceManager &SM) const;
void dump(const SourceManager &SM) const;
};
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 32268d789d14..db6bfd2ad3dd 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -62,7 +62,6 @@ class LangOptions;
class ASTWriter;
class ASTReader;
-/// \namespace
/// \brief Public enums and private classes that are part of the
/// SourceManager implementation.
///
@@ -221,7 +220,7 @@ namespace SrcMgr {
private:
// Disable assignments.
- ContentCache &operator=(const ContentCache& RHS);
+ ContentCache &operator=(const ContentCache& RHS) LLVM_DELETED_FUNCTION;
};
/// \brief Information about a FileID, basically just the logical file
@@ -647,8 +646,8 @@ class SourceManager : public RefCountedBase<SourceManager> {
mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
// SourceManager doesn't support copy construction.
- explicit SourceManager(const SourceManager&);
- void operator=(const SourceManager&);
+ explicit SourceManager(const SourceManager&) LLVM_DELETED_FUNCTION;
+ void operator=(const SourceManager&) LLVM_DELETED_FUNCTION;
public:
SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
bool UserFilesAreVolatile = false);
@@ -675,9 +674,10 @@ public:
///
/// One example of when this would be used is when the main source is read
/// from STDIN.
- FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
+ FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
+ SrcMgr::CharacteristicKind Kind = SrcMgr::C_User) {
assert(MainFileID.isInvalid() && "MainFileID already set!");
- MainFileID = createFileIDForMemBuffer(Buffer);
+ MainFileID = createFileIDForMemBuffer(Buffer, Kind);
return MainFileID;
}
@@ -734,10 +734,11 @@ public:
/// This does no caching of the buffer and takes ownership of the
/// MemoryBuffer, so only pass a MemoryBuffer to this once.
FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
+ SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
return createFileID(createMemBufferContentCache(Buffer), IncludeLoc,
- SrcMgr::C_User, LoadedID, LoadedOffset);
+ FileCharacter, LoadedID, LoadedOffset);
}
/// \brief Return a new SourceLocation that encodes the
@@ -1557,7 +1558,11 @@ private:
getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
unsigned Offset) const;
void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const;
-
+ void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache,
+ FileID FID,
+ SourceLocation SpellLoc,
+ SourceLocation ExpansionLoc,
+ unsigned ExpansionLength) const;
friend class ASTReader;
friend class ASTWriter;
};
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 96cada10571e..c82b8cb91887 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -53,6 +53,7 @@ namespace clang {
TST_union,
TST_struct,
TST_class, // C++ class type
+ TST_interface, // C++ (Microsoft-specific) __interface type
TST_typename, // Typedef, C++ class-name or enum name, etc.
TST_typeofType,
TST_typeofExpr,
@@ -174,6 +175,20 @@ namespace clang {
ICIS_CopyInit, ///< Copy initialization.
ICIS_ListInit ///< Direct list-initialization.
};
+
+ /// \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_AAPCS, // __attribute__((pcs("aapcs")))
+ CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp")))
+ CC_PnaclCall // __attribute__((pnaclcall))
+ };
+
} // end namespace clang
#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 47738af2907f..8f6a1c9f9890 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -28,11 +28,10 @@ def SwitchCase : Stmt<1>;
def CaseStmt : DStmt<SwitchCase>;
def DefaultStmt : DStmt<SwitchCase>;
-// GNU Extensions
-def AsmStmt : Stmt;
-
-// MS Extensions
-def MSAsmStmt : Stmt;
+// Asm statements
+def AsmStmt : Stmt<1>;
+def GCCAsmStmt : DStmt<AsmStmt>;
+def MSAsmStmt : DStmt<AsmStmt>;
// Obj-C statements
def ObjCAtTryStmt : Stmt;
@@ -132,6 +131,7 @@ def PackExpansionExpr : DStmt<Expr>;
def SizeOfPackExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
+def FunctionParmPackExpr : DStmt<Expr>;
def MaterializeTemporaryExpr : DStmt<Expr>;
def LambdaExpr : DStmt<Expr>;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 54d49e6fa559..2d26783e3875 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -23,7 +23,9 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/DataTypes.h"
#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Basic/Specifiers.h"
#include <cassert>
#include <vector>
#include <string>
@@ -38,7 +40,6 @@ class LangOptions;
class MacroBuilder;
class SourceLocation;
class SourceManager;
-class TargetOptions;
namespace Builtin { struct Info; }
@@ -61,6 +62,7 @@ enum TargetCXXABI {
/// \brief Exposes information about the current target.
///
class TargetInfo : public RefCountedBase<TargetInfo> {
+ llvm::IntrusiveRefCntPtr<TargetOptions> TargetOpts;
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
@@ -111,6 +113,16 @@ public:
virtual ~TargetInfo();
+ /// \brief Retrieve the target options.
+ TargetOptions &getTargetOpts() const {
+ assert(TargetOpts && "Missing target options");
+ return *TargetOpts;
+ }
+
+ void setTargetOpts(TargetOptions &TargetOpts) {
+ this->TargetOpts = &TargetOpts;
+ }
+
///===---- Target Data Type Query Methods -------------------------------===//
enum IntType {
NoInt = 0,
@@ -150,12 +162,18 @@ public:
/// __builtin_va_list as defined by the x86-64 ABI:
/// http://www.x86-64.org/documentation/abi.pdf
- X86_64ABIBuiltinVaList
+ X86_64ABIBuiltinVaList,
+
+ /// __builtin_va_list as defined by ARM AAPCS ABI
+ /// http://infocenter.arm.com
+ // /help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
+ AAPCSABIBuiltinVaList
};
protected:
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
- WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType;
+ WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType,
+ ProcessIDType;
/// \brief Whether Objective-C's built-in boolean type should be signed char.
///
@@ -196,7 +214,7 @@ public:
IntType getChar32Type() const { return Char32Type; }
IntType getInt64Type() const { return Int64Type; }
IntType getSigAtomicType() const { return SigAtomicType; }
-
+ IntType getProcessIDType() const { return ProcessIDType; }
/// \brief Return the width (in bits) of the specified integer type enum.
///
@@ -500,6 +518,11 @@ public:
bool validateInputConstraint(ConstraintInfo *OutputConstraints,
unsigned NumOutputs,
ConstraintInfo &info) const;
+ virtual bool validateConstraintModifier(StringRef /*Constraint*/,
+ const char /*Modifier*/,
+ unsigned /*Size*/) const {
+ return true;
+ }
bool resolveSymbolicName(const char *&Name,
ConstraintInfo *OutputConstraints,
unsigned NumOutputs, unsigned &Index) const;
@@ -712,6 +735,34 @@ public:
bool isBigEndian() const { return BigEndian; }
+ /// \brief Gets the default calling convention for the given target and
+ /// declaration context.
+ virtual CallingConv getDefaultCallingConv() const {
+ // Not all targets will specify an explicit calling convention that we can
+ // express. This will always do the right thing, even though it's not
+ // an explicit calling convention.
+ return CC_Default;
+ }
+
+ enum CallingConvCheckResult {
+ CCCR_OK,
+ CCCR_Warning
+ };
+
+ /// \brief Determines whether a given calling convention is valid for the
+ /// target. A calling convention can either be accepted, produce a warning
+ /// and be substituted with the default calling convention, or (someday)
+ /// produce an error (such as using thiscall on a non-instance function).
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ switch (CC) {
+ default:
+ return CCCR_Warning;
+ case CC_C:
+ case CC_Default:
+ return CCCR_OK;
+ }
+ }
+
protected:
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
return PointerWidth;
diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h
index 15ececd1df5d..d6deb0244d9f 100644
--- a/include/clang/Basic/TargetOptions.h
+++ b/include/clang/Basic/TargetOptions.h
@@ -15,13 +15,14 @@
#ifndef LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
#define LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <string>
#include <vector>
namespace clang {
/// \brief Options for controlling the target.
-class TargetOptions {
+class TargetOptions : public RefCountedBase<TargetOptions> {
public:
/// If given, the name of the target triple to compile for. If not given the
/// target will be selected to match the host.
@@ -40,6 +41,9 @@ public:
/// If given, the version string of the linker in use.
std::string LinkerVersion;
+ /// \brief The list of target specific features to enable or disable, as written on the command line.
+ std::vector<std::string> FeaturesAsWritten;
+
/// The list of target specific features to enable or disable -- this should
/// be a list of strings starting with by '+' or '-'.
std::vector<std::string> Features;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index fc031914a8d0..25e8d5a635c7 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -217,6 +217,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
// KEYALTIVEC - This is a keyword in AltiVec
// KEYBORLAND - This is a keyword if Borland extensions are enabled
// BOOLSUPPORT - This is a keyword if 'bool' is a built-in type
+// WCHARSUPPORT - This is a keyword if 'wchar_t' is a built-in type
//
KEYWORD(auto , KEYALL)
KEYWORD(break , KEYALL)
@@ -295,7 +296,7 @@ KEYWORD(typename , KEYCXX)
KEYWORD(typeid , KEYCXX)
KEYWORD(using , KEYCXX)
KEYWORD(virtual , KEYCXX)
-KEYWORD(wchar_t , KEYCXX)
+KEYWORD(wchar_t , WCHARSUPPORT)
// C++ 2.5p2: Alternative Representations.
CXX_KEYWORD_OPERATOR(and , ampamp)
@@ -364,6 +365,7 @@ 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
@@ -505,6 +507,7 @@ KEYWORD(__if_not_exists , KEYMS)
KEYWORD(__single_inheritance , KEYMS)
KEYWORD(__multiple_inheritance , KEYMS)
KEYWORD(__virtual_inheritance , KEYMS)
+KEYWORD(__interface , KEYMS)
ALIAS("__int8" , char , KEYMS)
ALIAS("__int16" , short , KEYMS)
ALIAS("__int32" , int , KEYMS)
@@ -518,7 +521,6 @@ ALIAS("_thiscall" , __thiscall , KEYMS)
ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND)
ALIAS("_inline" , inline , KEYMS)
ALIAS("_declspec" , __declspec , KEYMS)
-ALIAS("__interface" , struct , KEYMS)
// Borland Extensions which should be disabled in strict conformance mode.
ALIAS("_pascal" , __pascal , KEYBORLAND)
@@ -600,6 +602,41 @@ ANNOTATION(pragma_pack)
// handles them.
ANNOTATION(pragma_parser_crash)
+// Annotation for #pragma ms_struct...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_msstruct)
+
+// Annotation for #pragma align...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_align)
+
+// Annotation for #pragma weak id
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_weak)
+
+// Annotation for #pragma weak id = id
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_weakalias)
+
+// Annotation for #pragma redefine_extname...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_redefine_extname)
+
+// Annotation for #pragma STDC FP_CONTRACT...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_fp_contract)
+
+// Annotation for #pragma OPENCL EXTENSION...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_opencl_extension)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index 478add8db5db..e850971e34fa 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -63,6 +63,31 @@ const char *getTokenName(enum TokenKind Kind);
/// Preprocessor::getSpelling().
const char *getTokenSimpleSpelling(enum TokenKind Kind);
+/// \brief Return true if this is a raw identifier or an identifier kind.
+inline bool isAnyIdentifier(TokenKind K) {
+ return (K == tok::identifier) || (K == tok::raw_identifier);
+}
+
+/// \brief Return true if this is a "literal" kind, like a numeric
+/// constant, string, etc.
+inline bool isLiteral(TokenKind K) {
+ return (K == tok::numeric_constant) || (K == tok::char_constant) ||
+ (K == tok::wide_char_constant) || (K == tok::utf16_char_constant) ||
+ (K == tok::utf32_char_constant) || (K == tok::string_literal) ||
+ (K == tok::wide_string_literal) || (K == tok::utf8_string_literal) ||
+ (K == tok::utf16_string_literal) || (K == tok::utf32_string_literal) ||
+ (K == tok::angle_string_literal);
+}
+
+/// \brief Return true if this is any of tok::annot_* kinds.
+inline bool isAnnotation(TokenKind K) {
+#define ANNOTATION(NAME) \
+ if (K == tok::annot_##NAME) \
+ return true;
+#include "clang/Basic/TokenKinds.def"
+ return false;
+}
+
} // end namespace tok
} // end namespace clang
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 0a5a8643a36e..882b52d489ec 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -41,6 +41,7 @@ namespace clang {
UTT_IsFunction,
UTT_IsFundamental,
UTT_IsIntegral,
+ UTT_IsInterfaceClass,
UTT_IsLiteral,
UTT_IsLvalueReference,
UTT_IsMemberFunctionPointer,
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 451d56292363..3373e017decb 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -379,8 +379,8 @@ def VORR : Inst<"vorr", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>;
def VEOR : Inst<"veor", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>;
def VBIC : Inst<"vbic", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>;
def VORN : Inst<"vorn", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>;
-def VBSL : Inst<"vbsl", "dudd",
- "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs", OP_SEL>;
+def VBSL : SInst<"vbsl", "dudd",
+ "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs">;
////////////////////////////////////////////////////////////////////////////////
// E.3.30 Transposition operations
@@ -394,3 +394,7 @@ def VREINTERPRET
: Inst<"vreinterpret", "dd",
"csilUcUsUiUlhfPcPsQcQsQiQlQUcQUsQUiQUlQhQfQPcQPs", OP_REINT>;
+////////////////////////////////////////////////////////////////////////////////
+// Vector fused multiply-add operations
+
+def VFMA : SInst<"vfma", "dddd", "fQf">;
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index 7fa589feebf8..912ef01a018c 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -30,7 +30,7 @@ private:
bool OwnsVMContext;
protected:
- /// Create a new code generation action. If the optional \arg _VMContext
+ /// Create a new code generation action. If the optional \p _VMContext
/// parameter is supplied, the action uses it without taking ownership,
/// otherwise it creates a fresh LLVM context and takes ownership.
CodeGenAction(unsigned _Act, llvm::LLVMContext *_VMContext = 0);
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 6e317a0726b5..4057e48f69a4 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -90,8 +90,6 @@ public:
iterator end() { return Inputs.end(); }
const_iterator begin() const { return Inputs.begin(); }
const_iterator end() const { return Inputs.end(); }
-
- static bool classof(const Action *) { return true; }
};
class InputAction : public Action {
@@ -105,7 +103,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == InputClass;
}
- static bool classof(const InputAction *) { return true; }
};
class BindArchAction : public Action {
@@ -122,7 +119,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == BindArchClass;
}
- static bool classof(const BindArchAction *) { return true; }
};
class JobAction : public Action {
@@ -136,7 +132,6 @@ public:
return (A->getKind() >= JobClassFirst &&
A->getKind() <= JobClassLast);
}
- static bool classof(const JobAction *) { return true; }
};
class PreprocessJobAction : public JobAction {
@@ -147,7 +142,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == PreprocessJobClass;
}
- static bool classof(const PreprocessJobAction *) { return true; }
};
class PrecompileJobAction : public JobAction {
@@ -158,7 +152,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == PrecompileJobClass;
}
- static bool classof(const PrecompileJobAction *) { return true; }
};
class AnalyzeJobAction : public JobAction {
@@ -169,7 +162,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == AnalyzeJobClass;
}
- static bool classof(const AnalyzeJobAction *) { return true; }
};
class MigrateJobAction : public JobAction {
@@ -180,7 +172,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == MigrateJobClass;
}
- static bool classof(const MigrateJobAction *) { return true; }
};
class CompileJobAction : public JobAction {
@@ -191,7 +182,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == CompileJobClass;
}
- static bool classof(const CompileJobAction *) { return true; }
};
class AssembleJobAction : public JobAction {
@@ -202,7 +192,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == AssembleJobClass;
}
- static bool classof(const AssembleJobAction *) { return true; }
};
class LinkJobAction : public JobAction {
@@ -213,7 +202,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == LinkJobClass;
}
- static bool classof(const LinkJobAction *) { return true; }
};
class LipoJobAction : public JobAction {
@@ -224,7 +212,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == LipoJobClass;
}
- static bool classof(const LipoJobAction *) { return true; }
};
class DsymutilJobAction : public JobAction {
@@ -235,7 +222,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == DsymutilJobClass;
}
- static bool classof(const DsymutilJobAction *) { return true; }
};
class VerifyJobAction : public JobAction {
@@ -245,7 +231,6 @@ public:
static bool classof(const Action *A) {
return A->getKind() == VerifyJobClass;
}
- static bool classof(const VerifyJobAction *) { return true; }
};
} // end namespace driver
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
index e466cc323173..3b3829a634a0 100644
--- a/include/clang/Driver/Arg.h
+++ b/include/clang/Driver/Arg.h
@@ -15,6 +15,8 @@
#ifndef CLANG_DRIVER_ARG_H_
#define CLANG_DRIVER_ARG_H_
+#include "clang/Driver/Option.h"
+
#include "Util.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -23,7 +25,6 @@
namespace clang {
namespace driver {
class ArgList;
- class Option;
/// \brief A concrete instance of a particular driver option.
///
@@ -33,17 +34,20 @@ namespace driver {
/// ArgList to provide efficient iteration over all instances of a
/// particular option.
class Arg {
- Arg(const Arg &); // DO NOT IMPLEMENT
- void operator=(const Arg &); // DO NOT IMPLEMENT
+ 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;
+ 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;
@@ -60,14 +64,16 @@ namespace driver {
SmallVector<const char *, 2> Values;
public:
- Arg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0);
- Arg(const Option *Opt, unsigned Index,
+ 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, unsigned Index,
+ Arg(const Option Opt, StringRef Spelling, unsigned Index,
const char *Value0, const char *Value1, const Arg *BaseArg = 0);
~Arg();
- const Option &getOption() const { return *Opt; }
+ const Option getOption() const { return Opt; }
+ StringRef getSpelling() const { return Spelling; }
unsigned getIndex() const { return Index; }
/// \brief Return the base argument which generated this arg.
@@ -90,7 +96,7 @@ namespace driver {
void claim() const { getBaseArg().Claimed = true; }
unsigned getNumValues() const { return Values.size(); }
- const char *getValue(const ArgList &Args, unsigned N=0) const {
+ const char *getValue(unsigned N = 0) const {
return Values[N];
}
@@ -115,8 +121,6 @@ namespace driver {
/// when rendered as a input (e.g., Xlinker).
void renderAsInput(const ArgList &Args, ArgStringList &Output) const;
- static bool classof(const Arg *) { return true; }
-
void dump() const;
/// \brief Return a formatted version of the argument and
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index b7e490ccf7ca..72ed7bf58604 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -11,6 +11,7 @@
#define CLANG_DRIVER_ARGLIST_H_
#include "clang/Basic/LLVM.h"
+#include "clang/Driver/Option.h"
#include "clang/Driver/OptSpecifier.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
@@ -94,8 +95,8 @@ namespace driver {
/// and to iterate over groups of arguments.
class ArgList {
private:
- ArgList(const ArgList &); // DO NOT IMPLEMENT
- void operator=(const ArgList &); // DO NOT IMPLEMENT
+ ArgList(const ArgList &) LLVM_DELETED_FUNCTION;
+ void operator=(const ArgList &) LLVM_DELETED_FUNCTION;
public:
typedef SmallVector<Arg*, 16> arglist_type;
@@ -117,7 +118,7 @@ namespace driver {
/// @name Arg Access
/// @{
- /// append - Append \arg A to the arg list.
+ /// append - Append \p A to the arg list.
void append(Arg *A);
arglist_type &getArgs() { return Args; }
@@ -153,16 +154,16 @@ namespace driver {
/// @name Arg Removal
/// @{
- /// eraseArg - Remove any option matching \arg Id.
+ /// eraseArg - Remove any option matching \p Id.
void eraseArg(OptSpecifier Id);
/// @}
/// @name Arg Access
/// @{
- /// hasArg - Does the arg list contain any option matching \arg Id.
+ /// hasArg - Does the arg list contain any option matching \p Id.
///
- /// \arg Claim Whether the argument should be claimed, if it exists.
+ /// \p Claim Whether the argument should be claimed, if it exists.
bool hasArgNoClaim(OptSpecifier Id) const {
return getLastArgNoClaim(Id) != 0;
}
@@ -176,9 +177,9 @@ namespace driver {
return getLastArg(Id0, Id1, Id2) != 0;
}
- /// getLastArg - Return the last argument matching \arg Id, or null.
+ /// getLastArg - Return the last argument matching \p Id, or null.
///
- /// \arg Claim Whether the argument should be claimed, if it exists.
+ /// \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;
@@ -196,7 +197,7 @@ namespace driver {
OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5,
OptSpecifier Id6, OptSpecifier Id7) const;
- /// getArgString - Return the input argument string at \arg Index.
+ /// 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,
@@ -233,15 +234,13 @@ namespace driver {
/// @name Translation Utilities
/// @{
- /// hasFlag - Given an option \arg Pos and its negative form \arg
- /// Neg, return true if the option is present, false if the
- /// negation is present, and \arg Default if neither option is
- /// given. If both the option and its negation are present, the
- /// last one wins.
+ /// 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;
- /// AddLastArg - Render only the last argument match \arg Id0, if
- /// present.
+ /// AddLastArg - Render only the last argument match \p Id0, if present.
void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const;
/// AddAllArgs - Render all arguments matching the given ids.
@@ -286,8 +285,8 @@ namespace driver {
}
const char *MakeArgString(const Twine &Str) const;
- /// \brief Create an arg string for (\arg LHS + \arg RHS), reusing the
- /// string at \arg Index if possible.
+ /// \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;
@@ -347,7 +346,7 @@ namespace driver {
mutable arglist_type SynthesizedArgs;
public:
- /// Construct a new derived arg list from \arg BaseArgs.
+ /// Construct a new derived arg list from \p BaseArgs.
DerivedArgList(const InputArgList &BaseArgs);
~DerivedArgList();
@@ -374,55 +373,54 @@ namespace driver {
virtual const char *MakeArgString(StringRef Str) const;
- /// AddFlagArg - Construct a new FlagArg for the given option \arg Id and
+ /// 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) {
+ void AddFlagArg(const Arg *BaseArg, const Option Opt) {
append(MakeFlagArg(BaseArg, Opt));
}
/// AddPositionalArg - Construct a new Positional arg for the given option
- /// \arg Id, with the provided \arg Value and append it to the argument
+ /// \p Id, with the provided \p Value and append it to the argument
/// list.
- void AddPositionalArg(const Arg *BaseArg, const Option *Opt,
+ 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
- /// \arg Id, with the provided \arg Value and append it to the argument
+ /// \p Id, with the provided \p Value and append it to the argument
/// list.
- void AddSeparateArg(const Arg *BaseArg, const Option *Opt,
+ 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 \arg
- /// Id, with the provided \arg Value and append it to the argument list.
- void AddJoinedArg(const Arg *BaseArg, const Option *Opt,
+ /// 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
- /// \arg Id.
- Arg *MakeFlagArg(const Arg *BaseArg, const Option *Opt) const;
+ /// 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 \arg Id, with the provided \arg Value.
- Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt,
+ /// 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 \arg Id, with the provided \arg Value.
- Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt,
+ /// 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 \arg Id, with the provided \arg Value.
- Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt,
+ /// given option \p Id, with the provided \p Value.
+ Arg *MakeJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const;
/// @}
diff --git a/include/clang/Driver/CC1AsOptions.h b/include/clang/Driver/CC1AsOptions.h
index 05082132cee4..420a10138cba 100644
--- a/include/clang/Driver/CC1AsOptions.h
+++ b/include/clang/Driver/CC1AsOptions.h
@@ -17,11 +17,13 @@ namespace driver {
namespace cc1asoptions {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) OPT_##ID,
#include "clang/Driver/CC1AsOptions.inc"
LastOption
#undef OPTION
+#undef PREFIX
};
}
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index 37ba6027e207..9fd855a9ce9f 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -18,22 +18,22 @@ include "OptParser.td"
// Target Options
//===----------------------------------------------------------------------===//
-def triple : Separate<"-triple">,
+def triple : Separate<["-"], "triple">,
HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">;
-def target_cpu : Separate<"-target-cpu">,
+def target_cpu : Separate<["-"], "target-cpu">,
HelpText<"Target a specific cpu type">;
-def target_feature : Separate<"-target-feature">,
+def target_feature : Separate<["-"], "target-feature">,
HelpText<"Target specific attributes">;
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
-def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">,
+def I : JoinedOrSeparate<["-"], "I">, MetaVarName<"<directory>">,
HelpText<"Add directory to include search path">;
-def n : Flag<"-n">,
+def n : Flag<["-"], "n">,
HelpText<"Don't automatically start assembly file with a text section">;
-def L : Flag<"-L">,
+def L : Flag<["-"], "L">,
HelpText<"Save temporary labels in the symbol table. "
"Note this may change .s semantics, it should almost never be used "
"on compiler generated code!">;
@@ -42,50 +42,49 @@ def L : Flag<"-L">,
// Frontend Options
//===----------------------------------------------------------------------===//
-def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">;
+def o : Separate<["-"], "o">, MetaVarName<"<path>">,
+ HelpText<"Specify output file">;
-def filetype : Separate<"-filetype">,
+def filetype : Separate<["-"], "filetype">,
HelpText<"Specify the output file type ('asm', 'null', or 'obj')">;
-def help : Flag<"-help">,
+def help : Flag<["-", "--"], "help">,
HelpText<"Print this help text">;
-def _help : Flag<"--help">, Alias<help>;
-def version : Flag<"-version">,
+def version : Flag<["-", "--"], "version">,
HelpText<"Print the assembler version">;
-def _version : Flag<"--version">, Alias<version>;
-def v : Flag<"-v">, Alias<version>;
+def v : Flag<["-"], "v">, Alias<version>;
// Generic forwarding to LLVM options. This should only be used for debugging
// and experimental features.
-def mllvm : Separate<"-mllvm">,
+def mllvm : Separate<["-"], "mllvm">,
HelpText<"Additional arguments to forward to LLVM's option processing">;
//===----------------------------------------------------------------------===//
// Transliterate Options
//===----------------------------------------------------------------------===//
-def output_asm_variant : Separate<"-output-asm-variant">,
+def output_asm_variant : Separate<["-"], "output-asm-variant">,
HelpText<"Select the asm variant index to use for output">;
-def show_encoding : Flag<"-show-encoding">,
+def show_encoding : Flag<["-"], "show-encoding">,
HelpText<"Show instruction encoding information in transliterate mode">;
-def show_inst : Flag<"-show-inst">,
+def show_inst : Flag<["-"], "show-inst">,
HelpText<"Show internal instruction representation in transliterate mode">;
//===----------------------------------------------------------------------===//
// Assemble Options
//===----------------------------------------------------------------------===//
-def relax_all : Flag<"-relax-all">,
+def relax_all : Flag<["-"], "relax-all">,
HelpText<"Relax all fixups (for performance testing)">;
-def no_exec_stack : Flag<"--noexecstack">,
+def no_exec_stack : Flag<["--"], "noexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
-def fatal_warnings : Flag<"--fatal-warnings">,
+def fatal_warnings : Flag<["--"], "fatal-warnings">,
HelpText<"Consider warnings as errors">;
-def g : Flag<"-g">, HelpText<"Generate source level debug information">;
+def g : Flag<["-"], "g">, HelpText<"Generate source level debug information">;
-def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
+def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 6e4d7f2d31d5..3ff25494ff53 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -11,235 +11,238 @@
//
//===----------------------------------------------------------------------===//
-let Flags = [CC1Option] in {
+let Flags = [CC1Option, NoDriverOption] in {
//===----------------------------------------------------------------------===//
// Target Options
//===----------------------------------------------------------------------===//
-def cxx_abi : Separate<"-cxx-abi">,
+def cxx_abi : Separate<["-"], "cxx-abi">,
HelpText<"Target a particular C++ ABI type">;
-def target_abi : Separate<"-target-abi">,
+def target_abi : Separate<["-"], "target-abi">,
HelpText<"Target a particular ABI type">;
-def target_cpu : Separate<"-target-cpu">,
+def target_cpu : Separate<["-"], "target-cpu">,
HelpText<"Target a specific cpu type">;
-def target_feature : Separate<"-target-feature">,
+def target_feature : Separate<["-"], "target-feature">,
HelpText<"Target specific attributes">;
-def target_linker_version : Separate<"-target-linker-version">,
+def target_linker_version : Separate<["-"], "target-linker-version">,
HelpText<"Target linker version">;
-def triple : Separate<"-triple">,
+def triple : Separate<["-"], "triple">,
HelpText<"Specify target triple (e.g. i686-apple-darwin9)">;
-def triple_EQ : Joined<"-triple=">, Alias<triple>;
+def triple_EQ : Joined<["-"], "triple=">, Alias<triple>;
//===----------------------------------------------------------------------===//
// Analyzer Options
//===----------------------------------------------------------------------===//
-def analysis_UnoptimizedCFG : Flag<"-unoptimized-cfg">,
+def analysis_UnoptimizedCFG : Flag<["-"], "unoptimized-cfg">,
HelpText<"Generate unoptimized CFGs for all analyses">;
-def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">,
+def analysis_CFGAddImplicitDtors : Flag<["-"], "cfg-add-implicit-dtors">,
HelpText<"Add C++ implicit destructors to CFGs for all analyses">;
-def analyzer_store : Separate<"-analyzer-store">,
+def analyzer_store : Separate<["-"], "analyzer-store">,
HelpText<"Source Code Analysis - Abstract Memory Store Models">;
-def analyzer_store_EQ : Joined<"-analyzer-store=">, Alias<analyzer_store>;
+def analyzer_store_EQ : Joined<["-"], "analyzer-store=">, Alias<analyzer_store>;
-def analyzer_constraints : Separate<"-analyzer-constraints">,
+def analyzer_constraints : Separate<["-"], "analyzer-constraints">,
HelpText<"Source Code Analysis - Symbolic Constraint Engines">;
-def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">,
+def analyzer_constraints_EQ : Joined<["-"], "analyzer-constraints=">,
Alias<analyzer_constraints>;
-def analyzer_output : Separate<"-analyzer-output">,
+def analyzer_output : Separate<["-"], "analyzer-output">,
HelpText<"Source Code Analysis - Output Options">;
-def analyzer_output_EQ : Joined<"-analyzer-output=">,
+def analyzer_output_EQ : Joined<["-"], "analyzer-output=">,
Alias<analyzer_output>;
-def analyzer_purge : Separate<"-analyzer-purge">,
+def analyzer_purge : Separate<["-"], "analyzer-purge">,
HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">;
-def analyzer_purge_EQ : Joined<"-analyzer-purge=">, Alias<analyzer_purge>;
+def analyzer_purge_EQ : Joined<["-"], "analyzer-purge=">, Alias<analyzer_purge>;
-def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">,
+def analyzer_opt_analyze_headers : Flag<["-"], "analyzer-opt-analyze-headers">,
HelpText<"Force the static analyzer to analyze functions defined in header files">;
-def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">,
+def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-nested-blocks">,
HelpText<"Analyze the definitions of blocks in addition to functions">;
-def analyzer_display_progress : Flag<"-analyzer-display-progress">,
+def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">,
HelpText<"Emit verbose output about the analyzer's progress">;
-def analyze_function : Separate<"-analyze-function">,
+def analyze_function : Separate<["-"], "analyze-function">,
HelpText<"Run analysis on specific function">;
-def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>;
-def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">,
+def analyze_function_EQ : Joined<["-"], "analyze-function=">, Alias<analyze_function>;
+def analyzer_eagerly_assume : Flag<["-"], "analyzer-eagerly-assume">,
HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">;
-def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">,
- HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">;
-def trim_egraph : Flag<"-trim-egraph">,
+def trim_egraph : Flag<["-"], "trim-egraph">,
HelpText<"Only show error-related paths in the analysis graph">;
-def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">,
+def analyzer_viz_egraph_graphviz : Flag<["-"], "analyzer-viz-egraph-graphviz">,
HelpText<"Display exploded graph using GraphViz">;
-def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">,
+def analyzer_viz_egraph_ubigraph : Flag<["-"], "analyzer-viz-egraph-ubigraph">,
HelpText<"Display exploded graph using Ubigraph">;
-def analyzer_inline_max_stack_depth : Separate<"-analyzer-inline-max-stack-depth">,
+def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack-depth">,
HelpText<"Bound on stack depth while inlining (4 by default)">;
-def analyzer_inline_max_stack_depth_EQ : Joined<"-analyzer-inline-max-stack-depth=">,
+def analyzer_inline_max_stack_depth_EQ : Joined<["-"], "analyzer-inline-max-stack-depth=">,
Alias<analyzer_inline_max_stack_depth>;
-def analyzer_inline_max_function_size : Separate<"-analyzer-inline-max-function-size">,
+def analyzer_inline_max_function_size : Separate<["-"], "analyzer-inline-max-function-size">,
HelpText<"Bound on the number of basic blocks in an inlined function (200 by default)">;
-def analyzer_inline_max_function_size_EQ : Joined<"-analyzer-inline-max-function-size=">,
+def analyzer_inline_max_function_size_EQ : Joined<["-"], "analyzer-inline-max-function-size=">,
Alias<analyzer_inline_max_function_size>;
-def analyzer_ipa : Separate<"-analyzer-ipa">,
+def analyzer_ipa : Separate<["-"], "analyzer-ipa">,
HelpText<"Specify the inter-procedural analysis mode">;
-def analyzer_ipa_EQ : Joined<"-analyzer-ipa=">, Alias<analyzer_ipa>;
+def analyzer_ipa_EQ : Joined<["-"], "analyzer-ipa=">, Alias<analyzer_ipa>;
-def analyzer_inlining_mode : Separate<"-analyzer-inlining-mode">,
+def analyzer_inlining_mode : Separate<["-"], "analyzer-inlining-mode">,
HelpText<"Specify the function selection heuristic used during inlining">;
-def analyzer_inlining_mode_EQ : Joined<"-analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>;
+def analyzer_inlining_mode_EQ : Joined<["-"], "analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>;
-def analyzer_disable_retry_exhausted : Flag<"-analyzer-disable-retry-exhausted">,
+def analyzer_disable_retry_exhausted : Flag<["-"], "analyzer-disable-retry-exhausted">,
HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">;
-def analyzer_max_nodes : Separate<"-analyzer-max-nodes">,
+def analyzer_max_nodes : Separate<["-"], "analyzer-max-nodes">,
HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">;
-def analyzer_max_loop : Separate<"-analyzer-max-loop">,
+def analyzer_max_loop : Separate<["-"], "analyzer-max-loop">,
HelpText<"The maximum number of times the analyzer will go through a loop">;
-def analyzer_stats : Flag<"-analyzer-stats">,
+def analyzer_stats : Flag<["-"], "analyzer-stats">,
HelpText<"Print internal analyzer statistics.">;
-def analyzer_checker : Separate<"-analyzer-checker">,
+def analyzer_checker : Separate<["-"], "analyzer-checker">,
HelpText<"Choose analyzer checkers to enable">;
-def analyzer_checker_EQ : Joined<"-analyzer-checker=">,
+def analyzer_checker_EQ : Joined<["-"], "analyzer-checker=">,
Alias<analyzer_checker>;
-def analyzer_disable_checker : Separate<"-analyzer-disable-checker">,
+def analyzer_disable_checker : Separate<["-"], "analyzer-disable-checker">,
HelpText<"Choose analyzer checkers to disable">;
-def analyzer_disable_checker_EQ : Joined<"-analyzer-disable-checker=">,
+def analyzer_disable_checker_EQ : Joined<["-"], "analyzer-disable-checker=">,
Alias<analyzer_disable_checker>;
-def analyzer_checker_help : Flag<"-analyzer-checker-help">,
+def analyzer_checker_help : Flag<["-"], "analyzer-checker-help">,
HelpText<"Display the list of analyzer checkers that are available">;
+def analyzer_config : Separate<["-"], "analyzer-config">,
+ HelpText<"Choose analyzer options to enable">;
+
//===----------------------------------------------------------------------===//
// Migrator Options
//===----------------------------------------------------------------------===//
-def migrator_no_nsalloc_error : Flag<"-no-ns-alloc-error">,
+def migrator_no_nsalloc_error : Flag<["-"], "no-ns-alloc-error">,
HelpText<"Do not error on use of NSAllocateCollectable/NSReallocateCollectable">;
-def migrator_no_finalize_removal : Flag<"-no-finalize-removal">,
+def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">,
HelpText<"Do not remove finalize method in gc mode">;
//===----------------------------------------------------------------------===//
// CodeGen Options
//===----------------------------------------------------------------------===//
-def disable_llvm_optzns : Flag<"-disable-llvm-optzns">,
+def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">,
HelpText<"Don't run LLVM optimization passes">;
-def disable_llvm_verifier : Flag<"-disable-llvm-verifier">,
+def disable_llvm_verifier : Flag<["-"], "disable-llvm-verifier">,
HelpText<"Don't run the LLVM IR verifier pass">;
-def disable_red_zone : Flag<"-disable-red-zone">,
+def disable_red_zone : Flag<["-"], "disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
-def fdebug_compilation_dir : Separate<"-fdebug-compilation-dir">,
+def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
HelpText<"The compilation directory to embed in the debug info.">;
-def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
+def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
-def fforbid_guard_variables : Flag<"-fforbid-guard-variables">,
+def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
+ HelpText<"Turn on column location information.">;
+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">,
+def no_implicit_float : Flag<["-"], "no-implicit-float">,
HelpText<"Don't generate implicit floating point instructions">;
-def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">,
+def fdump_vtable_layouts : Flag<["-"], "fdump-vtable-layouts">,
HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">;
-def femit_coverage_notes : Flag<"-femit-coverage-notes">,
+def femit_coverage_notes : Flag<["-"], "femit-coverage-notes">,
HelpText<"Emit a gcov coverage notes file when compiling.">;
-def femit_coverage_data: Flag<"-femit-coverage-data">,
+def femit_coverage_data: Flag<["-"], "femit-coverage-data">,
HelpText<"Instrument the program to emit gcov coverage data when run.">;
-def coverage_file : Separate<"-coverage-file">,
+def coverage_file : Separate<["-"], "coverage-file">,
HelpText<"Emit coverage data to this filename. The extension will be replaced.">;
-def coverage_file_EQ : Joined<"-coverage-file=">, Alias<coverage_file>;
-def fuse_register_sized_bitfield_access: Flag<"-fuse-register-sized-bitfield-access">,
+def coverage_file_EQ : Joined<["-"], "coverage-file=">, Alias<coverage_file>;
+def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">,
HelpText<"Use register sized accesses to bit-fields, when possible.">;
-def relaxed_aliasing : Flag<"-relaxed-aliasing">,
+def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
-def masm_verbose : Flag<"-masm-verbose">,
+def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
-def mcode_model : Separate<"-mcode-model">,
+def mcode_model : Separate<["-"], "mcode-model">,
HelpText<"The code model to use">;
-def mdebug_pass : Separate<"-mdebug-pass">,
+def mdebug_pass : Separate<["-"], "mdebug-pass">,
HelpText<"Enable additional debug output">;
-def mdisable_fp_elim : Flag<"-mdisable-fp-elim">,
+def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">,
HelpText<"Disable frame pointer elimination optimization">;
-def mdisable_tail_calls : Flag<"-mdisable-tail-calls">,
+def mdisable_tail_calls : Flag<["-"], "mdisable-tail-calls">,
HelpText<"Disable tail call optimization, keeping the call stack accurate">;
-def menable_no_infinities : Flag<"-menable-no-infs">,
+def menable_no_infinities : Flag<["-"], "menable-no-infs">,
HelpText<"Allow optimization to assume there are no infinities.">;
-def menable_no_nans : Flag<"-menable-no-nans">,
+def menable_no_nans : Flag<["-"], "menable-no-nans">,
HelpText<"Allow optimization to assume there are no NaNs.">;
-def menable_unsafe_fp_math : Flag<"-menable-unsafe-fp-math">,
+def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">,
HelpText<"Allow unsafe floating-point math optimizations which may decrease "
"precision">;
-def mfloat_abi : Separate<"-mfloat-abi">,
+def mfloat_abi : Separate<["-"], "mfloat-abi">,
HelpText<"The float ABI to use">;
-def mlimit_float_precision : Separate<"-mlimit-float-precision">,
+def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">,
HelpText<"Limit float precision to the given value">;
-def mno_exec_stack : Flag<"-mnoexecstack">,
+def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
-def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">,
+def mno_zero_initialized_in_bss : Flag<["-"], "mno-zero-initialized-in-bss">,
HelpText<"Do not put zero initialized data in the BSS">;
-def backend_option : Separate<"-backend-option">,
+def backend_option : Separate<["-"], "backend-option">,
HelpText<"Additional arguments to forward to LLVM backend (during code gen)">;
-def mregparm : Separate<"-mregparm">,
+def mregparm : Separate<["-"], "mregparm">,
HelpText<"Limit the number of registers available for integer arguments">;
-def msave_temp_labels : Flag<"-msave-temp-labels">,
+def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
HelpText<"(integrated-as) Save temporary labels">;
-def mrelocation_model : Separate<"-mrelocation-model">,
+def mrelocation_model : Separate<["-"], "mrelocation-model">,
HelpText<"The relocation model to use">;
-def munwind_tables : Flag<"-munwind-tables">,
+def munwind_tables : Flag<["-"], "munwind-tables">,
HelpText<"Generate unwinding tables for all functions">;
-def fuse_init_array : Flag<"-fuse-init-array">,
+def fuse_init_array : Flag<["-"], "fuse-init-array">,
HelpText<"Use .init_array instead of .ctors">;
-def mconstructor_aliases : Flag<"-mconstructor-aliases">,
+def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">,
HelpText<"Emit complete constructors and destructors as aliases when possible">;
-def mlink_bitcode_file : Separate<"-mlink-bitcode-file">,
+def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">,
HelpText<"Link the given bitcode file before performing optimizations.">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
//===----------------------------------------------------------------------===//
-def sys_header_deps : Flag<"-sys-header-deps">,
+def sys_header_deps : Flag<["-"], "sys-header-deps">,
HelpText<"Include system headers in dependency output">;
-def header_include_file : Separate<"-header-include-file">,
+def header_include_file : Separate<["-"], "header-include-file">,
HelpText<"Filename (or -) to write header include output to">;
//===----------------------------------------------------------------------===//
// Diagnostic Options
//===----------------------------------------------------------------------===//
-def dump_build_information : Separate<"-dump-build-information">,
+def dump_build_information : Separate<["-"], "dump-build-information">,
MetaVarName<"<filename>">,
HelpText<"output a dump of some build information to a file">;
-def diagnostic_log_file : Separate<"-diagnostic-log-file">,
+def diagnostic_log_file : Separate<["-"], "diagnostic-log-file">,
HelpText<"Filename (or -) to log diagnostics to">;
-def diagnostic_serialized_file : Separate<"-serialize-diagnostic-file">,
+def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
MetaVarName<"<filename>">,
HelpText<"File for serializing diagnostics in a binary format">;
-def fdiagnostics_format : Separate<"-fdiagnostics-format">,
+def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
HelpText<"Change diagnostic formatting to match IDE and command line tools">;
-def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">,
+def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
HelpText<"Print diagnostic category">;
-def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
+def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">,
HelpText<"Set the tab stop distance.">;
-def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
+def ferror_limit : Separate<["-"], "ferror-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
-def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"<N>">,
+def fmacro_backtrace_limit : Separate<["-"], "fmacro-backtrace-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">;
-def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">,
+def ftemplate_backtrace_limit : Separate<["-"], "ftemplate-backtrace-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
-def fconstexpr_backtrace_limit : Separate<"-fconstexpr-backtrace-limit">, MetaVarName<"<N>">,
+def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
-def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
+def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
-def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">,
+def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
HelpText<"Silence ObjC rewriting warnings">;
//===----------------------------------------------------------------------===//
@@ -248,43 +251,43 @@ def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">,
// This isn't normally used, it is just here so we can parse a
// CompilerInvocation out of a driver-derived argument vector.
-def cc1 : Flag<"-cc1">;
+def cc1 : Flag<["-"], "cc1">;
-def ast_merge : Separate<"-ast-merge">,
+def ast_merge : Separate<["-"], "ast-merge">,
MetaVarName<"<ast file>">,
HelpText<"Merge the given AST file into the translation unit being compiled.">;
-def code_completion_at : Separate<"-code-completion-at">,
+def code_completion_at : Separate<["-"], "code-completion-at">,
MetaVarName<"<file>:<line>:<column>">,
HelpText<"Dump code-completion information at a location">;
-def remap_file : Separate<"-remap-file">,
+def remap_file : Separate<["-"], "remap-file">,
MetaVarName<"<from>;<to>">,
HelpText<"Replace the contents of the <from> file with the contents of the <to> file">;
-def code_completion_at_EQ : Joined<"-code-completion-at=">,
+def code_completion_at_EQ : Joined<["-"], "code-completion-at=">,
Alias<code_completion_at>;
-def code_completion_macros : Flag<"-code-completion-macros">,
+def code_completion_macros : Flag<["-"], "code-completion-macros">,
HelpText<"Include macros in code-completion results">;
-def code_completion_patterns : Flag<"-code-completion-patterns">,
+def code_completion_patterns : Flag<["-"], "code-completion-patterns">,
HelpText<"Include code patterns in code-completion results">;
-def no_code_completion_globals : Flag<"-no-code-completion-globals">,
+def no_code_completion_globals : Flag<["-"], "no-code-completion-globals">,
HelpText<"Do not include global declarations in code-completion results.">;
-def code_completion_brief_comments : Flag<"-code-completion-brief-comments">,
+def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments">,
HelpText<"Include brief documentation comments in code-completion results.">;
-def disable_free : Flag<"-disable-free">,
+def disable_free : Flag<["-"], "disable-free">,
HelpText<"Disable freeing of memory on exit">;
-def load : Separate<"-load">, MetaVarName<"<dsopath>">,
+def load : Separate<["-"], "load">, MetaVarName<"<dsopath>">,
HelpText<"Load the named plugin (dynamic shared object)">;
-def plugin : Separate<"-plugin">, MetaVarName<"<name>">,
+def plugin : Separate<["-"], "plugin">, MetaVarName<"<name>">,
HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">;
-def plugin_arg : JoinedAndSeparate<"-plugin-arg-">,
+def plugin_arg : JoinedAndSeparate<["-"], "plugin-arg-">,
MetaVarName<"<name> <arg>">,
HelpText<"Pass <arg> to plugin <name>">;
-def add_plugin : Separate<"-add-plugin">, MetaVarName<"<name>">,
+def add_plugin : Separate<["-"], "add-plugin">, MetaVarName<"<name>">,
HelpText<"Use the named plugin action in addition to the default action">;
-def resource_dir : Separate<"-resource-dir">,
+def resource_dir : Separate<["-"], "resource-dir">,
HelpText<"The directory which holds the compiler resource files">;
-def version : Flag<"-version">,
+def version : Flag<["-"], "version">,
HelpText<"Print the compiler version">;
-def ast_dump_filter : Separate<"-ast-dump-filter">,
+def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
MetaVarName<"<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"
@@ -292,191 +295,197 @@ def ast_dump_filter : Separate<"-ast-dump-filter">,
let Group = Action_Group in {
-def Eonly : Flag<"-Eonly">,
+def Eonly : Flag<["-"], "Eonly">,
HelpText<"Just run preprocessor, no output (for timings)">;
-def dump_raw_tokens : Flag<"-dump-raw-tokens">,
+def dump_raw_tokens : Flag<["-"], "dump-raw-tokens">,
HelpText<"Lex file in raw mode and dump raw tokens">;
-def analyze : Flag<"-analyze">,
+def analyze : Flag<["-"], "analyze">,
HelpText<"Run static analysis engine">;
-def dump_tokens : Flag<"-dump-tokens">,
+def dump_tokens : Flag<["-"], "dump-tokens">,
HelpText<"Run preprocessor, dump internal rep of tokens">;
-def init_only : Flag<"-init-only">,
+def init_only : Flag<["-"], "init-only">,
HelpText<"Only execute frontend initialization">;
-def fixit : Flag<"-fixit">,
+def fixit : Flag<["-"], "fixit">,
HelpText<"Apply fix-it advice to the input source">;
-def fixit_EQ : Joined<"-fixit=">,
+def fixit_EQ : Joined<["-"], "fixit=">,
HelpText<"Apply fix-it advice creating a file with the given suffix">;
-def print_preamble : Flag<"-print-preamble">,
+def print_preamble : Flag<["-"], "print-preamble">,
HelpText<"Print the \"preamble\" of a file, which is a candidate for implicit"
" precompiled headers.">;
-def emit_html : Flag<"-emit-html">,
+def emit_html : Flag<["-"], "emit-html">,
HelpText<"Output input source as HTML">;
-def ast_print : Flag<"-ast-print">,
+def ast_print : Flag<["-"], "ast-print">,
HelpText<"Build ASTs and then pretty-print them">;
-def ast_list : Flag<"-ast-list">,
+def ast_list : Flag<["-"], "ast-list">,
HelpText<"Build ASTs and print the list of declaration node qualified names">;
-def ast_dump : Flag<"-ast-dump">,
+def ast_dump : Flag<["-"], "ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
-def ast_dump_xml : Flag<"-ast-dump-xml">,
+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">,
+def ast_view : Flag<["-"], "ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
-def print_decl_contexts : Flag<"-print-decl-contexts">,
+def print_decl_contexts : Flag<["-"], "print-decl-contexts">,
HelpText<"Print DeclContexts and their Decls">;
-def emit_module : Flag<"-emit-module">,
+def emit_module : Flag<["-"], "emit-module">,
HelpText<"Generate pre-compiled module file from a module map">;
-def emit_pth : Flag<"-emit-pth">,
+def emit_pth : Flag<["-"], "emit-pth">,
HelpText<"Generate pre-tokenized header file">;
-def emit_pch : Flag<"-emit-pch">,
+def emit_pch : Flag<["-"], "emit-pch">,
HelpText<"Generate pre-compiled header file">;
-def emit_llvm_bc : Flag<"-emit-llvm-bc">,
+def emit_llvm_bc : Flag<["-"], "emit-llvm-bc">,
HelpText<"Build ASTs then convert to LLVM, emit .bc file">;
-def emit_llvm_only : Flag<"-emit-llvm-only">,
+def emit_llvm_only : Flag<["-"], "emit-llvm-only">,
HelpText<"Build ASTs and convert to LLVM, discarding output">;
-def emit_codegen_only : Flag<"-emit-codegen-only">,
+def emit_codegen_only : Flag<["-"], "emit-codegen-only">,
HelpText<"Generate machine code, but discard output">;
-def emit_obj : Flag<"-emit-obj">,
+def emit_obj : Flag<["-"], "emit-obj">,
HelpText<"Emit native object files">;
-def rewrite_test : Flag<"-rewrite-test">,
+def rewrite_test : Flag<["-"], "rewrite-test">,
HelpText<"Rewriter playground">;
-def rewrite_macros : Flag<"-rewrite-macros">,
+def rewrite_macros : Flag<["-"], "rewrite-macros">,
HelpText<"Expand macros without full preprocessing">;
-def migrate : Flag<"-migrate">,
+def migrate : Flag<["-"], "migrate">,
HelpText<"Migrate source code">;
}
-def mt_migrate_directory : Separate<"-mt-migrate-directory">,
+def mt_migrate_directory : Separate<["-"], "mt-migrate-directory">,
HelpText<"Directory for temporary files produced during ARC or ObjC migration">;
-def arcmt_check : Flag<"-arcmt-check">,
+def arcmt_check : Flag<["-"], "arcmt-check">,
HelpText<"Check for ARC migration issues that need manual handling">;
-def arcmt_modify : Flag<"-arcmt-modify">,
+def arcmt_modify : Flag<["-"], "arcmt-modify">,
HelpText<"Apply modifications to files to conform to ARC">;
-def arcmt_migrate : Flag<"-arcmt-migrate">,
+def arcmt_migrate : Flag<["-"], "arcmt-migrate">,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def relocatable_pch : Flag<"-relocatable-pch">,
+def relocatable_pch : Flag<["-", "--"], "relocatable-pch">,
HelpText<"Whether to build a relocatable precompiled header">;
-def print_stats : Flag<"-print-stats">,
+def print_stats : Flag<["-"], "print-stats">,
HelpText<"Print performance metrics and statistics">;
-def fdump_record_layouts : Flag<"-fdump-record-layouts">,
+def fdump_record_layouts : Flag<["-"], "fdump-record-layouts">,
HelpText<"Dump record layout information">;
-def fdump_record_layouts_simple : Flag<"-fdump-record-layouts-simple">,
+def fdump_record_layouts_simple : Flag<["-"], "fdump-record-layouts-simple">,
HelpText<"Dump record layout information in a simple form used for testing">;
-def fix_what_you_can : Flag<"-fix-what-you-can">,
+def fix_what_you_can : Flag<["-"], "fix-what-you-can">,
HelpText<"Apply fix-it advice even in the presence of unfixable errors">;
-def fix_only_warnings : Flag<"-fix-only-warnings">,
+def fix_only_warnings : Flag<["-"], "fix-only-warnings">,
HelpText<"Apply fix-it advice only for warnings, not errors">;
-def fixit_recompile : Flag<"-fixit-recompile">,
+def fixit_recompile : Flag<["-"], "fixit-recompile">,
HelpText<"Apply fix-it changes and recompile">;
-def fixit_to_temp : Flag<"-fixit-to-temporary">,
+def fixit_to_temp : Flag<["-"], "fixit-to-temporary">,
HelpText<"Apply fix-it changes to temporary files">;
-def foverride_record_layout_EQ : Joined<"-foverride-record-layout=">,
+def foverride_record_layout_EQ : Joined<["-"], "foverride-record-layout=">,
HelpText<"Override record layouts with those in the given file">;
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
-def fblocks_runtime_optional : Flag<"-fblocks-runtime-optional">,
+def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">,
HelpText<"Weakly link in the blocks runtime">;
-def fsjlj_exceptions : Flag<"-fsjlj-exceptions">,
+def fsjlj_exceptions : Flag<["-"], "fsjlj-exceptions">,
HelpText<"Use SjLj style exceptions">;
-def fhidden_weak_vtables : Flag<"-fhidden-weak-vtables">,
+def fhidden_weak_vtables : Flag<["-"], "fhidden-weak-vtables">,
HelpText<"Generate weak vtables and RTTI with hidden visibility">;
-def main_file_name : Separate<"-main-file-name">,
+def main_file_name : Separate<["-"], "main-file-name">,
HelpText<"Main file name to use for debug info">;
-def fno_signed_char : Flag<"-fno-signed-char">,
+def fno_signed_char : Flag<["-"], "fno-signed-char">,
HelpText<"Char is unsigned">;
-def fconstant_string_class : Separate<"-fconstant-string-class">,
+def fno_wchar : Flag<["-"], "fno-wchar">,
+ HelpText<"Disable C++ builtin type wchar_t">;
+def fconstant_string_class : Separate<["-"], "fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
-def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">,
+def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">,
HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
-def fobjc_runtime_has_weak : Flag<"-fobjc-runtime-has-weak">,
+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=">,
+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">,
+def fobjc_default_synthesize_properties : Flag<["-"], "fobjc-default-synthesize-properties">,
HelpText<"enable the default synthesis of Objective-C properties">;
-def pic_level : Separate<"-pic-level">,
+def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">,
+ HelpText<"enable extended encoding of block type signature">;
+def pic_level : Separate<["-"], "pic-level">,
HelpText<"Value for __PIC__">;
-def pie_level : Separate<"-pie-level">,
+def pie_level : Separate<["-"], "pie-level">,
HelpText<"Value for __PIE__">;
-def fno_validate_pch : Flag<"-fno-validate-pch">,
+def fno_validate_pch : Flag<["-"], "fno-validate-pch">,
HelpText<"Disable validation of precompiled headers">;
-def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">,
+def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">,
HelpText<"Dump declarations that are deserialized from PCH, for testing">;
-def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">,
+def error_on_deserialized_pch_decl : Separate<["-"], "error-on-deserialized-decl">,
HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">;
-def error_on_deserialized_pch_decl_EQ : Joined<"-error-on-deserialized-decl=">,
+def error_on_deserialized_pch_decl_EQ : Joined<["-"], "error-on-deserialized-decl=">,
Alias<error_on_deserialized_pch_decl>;
-def static_define : Flag<"-static-define">,
+def static_define : Flag<["-"], "static-define">,
HelpText<"Should __STATIC__ be defined">;
-def stack_protector : Separate<"-stack-protector">,
+def stack_protector : Separate<["-"], "stack-protector">,
HelpText<"Enable stack protectors">;
-def fvisibility : Separate<"-fvisibility">,
+def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">,
+ HelpText<"Lower bound for a buffer to be considered for stack protection">;
+def fvisibility : Separate<["-"], "fvisibility">,
HelpText<"Default symbol visibility">;
-def ftemplate_depth : Separate<"-ftemplate-depth">,
+def ftemplate_depth : Separate<["-"], "ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
-def fconstexpr_depth : Separate<"-fconstexpr-depth">,
+def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">,
HelpText<"Maximum depth of recursive constexpr function calls">;
-def fconst_strings : Flag<"-fconst-strings">,
+def fconst_strings : Flag<["-"], "fconst-strings">,
HelpText<"Use a const qualified type for string literals in C and ObjC">;
-def fno_const_strings : Flag<"-fno-const-strings">,
+def fno_const_strings : Flag<["-"], "fno-const-strings">,
HelpText<"Don't use a const qualified type for string literals in C and ObjC">;
-def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">,
+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">,
+def ffake_address_space_map : Flag<["-"], "ffake-address-space-map">,
HelpText<"Use a fake address space map; OpenCL testing purposes only">;
-def funknown_anytype : Flag<"-funknown-anytype">,
+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">,
+def fdebugger_support : Flag<["-"], "fdebugger-support">,
HelpText<"Enable special debugger support behavior">;
-def fdebugger_cast_result_to_id : Flag<"-fdebugger-cast-result-to-id">,
+def fdebugger_cast_result_to_id : Flag<["-"], "fdebugger-cast-result-to-id">,
HelpText<"Enable casting unknown expression results to id">;
-def fdebugger_objc_literal : Flag<"-fdebugger-objc-literal">,
+def fdebugger_objc_literal : Flag<["-"], "fdebugger-objc-literal">,
HelpText<"Enable special debugger support for Objective-C subscripting and literals">;
-def fdeprecated_macro : Flag<"-fdeprecated-macro">,
+def fdeprecated_macro : Flag<["-"], "fdeprecated-macro">,
HelpText<"Defines the __DEPRECATED macro">;
-def fno_deprecated_macro : Flag<"-fno-deprecated-macro">,
+def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">,
HelpText<"Undefines the __DEPRECATED macro">;
//===----------------------------------------------------------------------===//
// Header Search Options
//===----------------------------------------------------------------------===//
-def nostdsysteminc : Flag<"-nostdsysteminc">,
+def nostdsysteminc : Flag<["-"], "nostdsysteminc">,
HelpText<"Disable standard system #include directories">;
-def fmodule_name : Joined<"-fmodule-name=">,
+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">,
+def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">,
HelpText<"Disable the module hash">;
-def c_isystem : JoinedOrSeparate<"-c-isystem">, MetaVarName<"<directory>">,
+def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to the C SYSTEM include search path">;
-def objc_isystem : JoinedOrSeparate<"-objc-isystem">,
+def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the ObjC SYSTEM include search path">;
-def objcxx_isystem : JoinedOrSeparate<"-objcxx-isystem">,
+def objcxx_isystem : JoinedOrSeparate<["-"], "objcxx-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the ObjC++ SYSTEM include search path">;
-def internal_isystem : JoinedOrSeparate<"-internal-isystem">,
+def internal_isystem : JoinedOrSeparate<["-"], "internal-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the internal system include search path; these "
"are assumed to not be user-provided and are used to model system "
"and standard headers' paths.">;
-def internal_externc_isystem : JoinedOrSeparate<"-internal-externc-isystem">,
+def internal_externc_isystem : JoinedOrSeparate<["-"], "internal-externc-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the internal system include search path with "
"implicit extern \"C\" semantics; these are assumed to not be "
"user-provided and are used to model system and standard headers' "
"paths.">;
-def isystem_prefix : JoinedOrSeparate<"-isystem-prefix">,
+def isystem_prefix : JoinedOrSeparate<["-"], "isystem-prefix">,
MetaVarName<"<prefix>">,
HelpText<"Treat all #include paths starting with <prefix> as including a "
"system header.">;
-def ino_system_prefix : JoinedOrSeparate<"-ino-system-prefix">,
+def ino_system_prefix : JoinedOrSeparate<["-"], "ino-system-prefix">,
MetaVarName<"<prefix>">,
HelpText<"Treat all #include paths starting with <prefix> as not including a "
"system header.">;
@@ -485,42 +494,42 @@ def ino_system_prefix : JoinedOrSeparate<"-ino-system-prefix">,
// Preprocessor Options
//===----------------------------------------------------------------------===//
-def include_pth : Separate<"-include-pth">, MetaVarName<"<file>">,
+def include_pth : Separate<["-"], "include-pth">, MetaVarName<"<file>">,
HelpText<"Include file before parsing">;
-def chain_include : Separate<"-chain-include">, MetaVarName<"<file>">,
+def chain_include : Separate<["-"], "chain-include">, MetaVarName<"<file>">,
HelpText<"Include and chain a header file after turning it into PCH">;
-def preamble_bytes_EQ : Joined<"-preamble-bytes=">,
+def preamble_bytes_EQ : Joined<["-"], "preamble-bytes=">,
HelpText<"Assume that the precompiled header is a precompiled preamble "
"covering the first N bytes of the main file">;
-def token_cache : Separate<"-token-cache">, MetaVarName<"<path>">,
+def token_cache : Separate<["-"], "token-cache">, MetaVarName<"<path>">,
HelpText<"Use specified token cache file">;
-def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
+def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
//===----------------------------------------------------------------------===//
// OpenCL Options
//===----------------------------------------------------------------------===//
-def cl_opt_disable : Flag<"-cl-opt-disable">,
+def cl_opt_disable : Flag<["-"], "cl-opt-disable">,
HelpText<"OpenCL only. This option disables all optimizations. The default is optimizations are enabled.">;
-def cl_single_precision_constant : Flag<"-cl-single-precision-constant">,
+def cl_single_precision_constant : Flag<["-"], "cl-single-precision-constant">,
HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">;
-def cl_finite_math_only : Flag<"-cl-finite-math-only">,
+def cl_finite_math_only : Flag<["-"], "cl-finite-math-only">,
HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">;
-def cl_unsafe_math_optimizations : Flag<"-cl-unsafe-math-optimizations">,
+def cl_unsafe_math_optimizations : Flag<["-"], "cl-unsafe-math-optimizations">,
HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">;
-def cl_fast_relaxed_math : Flag<"-cl-fast-relaxed-math">,
+def cl_fast_relaxed_math : Flag<["-"], "cl-fast-relaxed-math">,
HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__">;
-def cl_mad_enable : Flag<"-cl-mad-enable">,
+def cl_mad_enable : Flag<["-"], "cl-mad-enable">,
HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">;
-def cl_std_EQ : Joined<"-cl-std=">,
+def cl_std_EQ : Joined<["-"], "cl-std=">,
HelpText<"OpenCL language standard to compile for">;
//===----------------------------------------------------------------------===//
// CUDA Options
//===----------------------------------------------------------------------===//
-def fcuda_is_device : Flag<"-fcuda-is-device">,
+def fcuda_is_device : Flag<["-"], "fcuda-is-device">,
HelpText<"Generate code for CUDA device">;
} // let Flags = [CC1Option]
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 7a10d567354b..5f63aa768857 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -98,8 +98,7 @@ public:
StringRef getSysRoot() const;
/// getArgsForToolChain - Return the derived argument list for the
- /// tool chain \arg TC (or the default tool chain, if TC is not
- /// specified).
+ /// 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,
@@ -142,6 +141,14 @@ public:
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 609505597a70..b752ce6a349a 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -146,28 +146,11 @@ private:
/// jobs.
unsigned CheckInputsExist : 1;
- /// Use the clang compiler where possible.
- unsigned CCCUseClang : 1;
-
- /// Use clang for handling C++ and Objective-C++ inputs.
- unsigned CCCUseClangCXX : 1;
-
- /// Use clang as a preprocessor (clang's preprocessor will still be
- /// used where an integrated CPP would).
- unsigned CCCUseClangCPP : 1;
-
- /// \brief Force use of clang frontend.
- unsigned ForcedClangUse : 1;
-
public:
/// Use lazy precompiled headers for PCH support.
unsigned CCCUsePCH : 1;
private:
- /// Only use clang for the given architectures (only used when
- /// non-empty).
- std::set<llvm::Triple::ArchType> CCCClangArchs;
-
/// Certain options suppress the 'no input files' warning.
bool SuppressMissingInputWarning : 1;
@@ -232,9 +215,6 @@ public:
InstalledDir = Value;
}
- bool shouldForceClangUse() const { return ForcedClangUse; }
- void setForcedClangUse(bool V = true) { ForcedClangUse = V; }
-
/// @}
/// @name Primary Functionality
/// @{
@@ -287,7 +267,7 @@ public:
/// BuildJobs - Bind actions to concrete tools and translate
/// arguments to form the list of jobs to run.
///
- /// \arg C - The compilation that is being built.
+ /// \param C - The compilation that is being built.
void BuildJobs(Compilation &C) const;
/// ExecuteCompilation - Execute the compilation according to the command line
@@ -323,26 +303,21 @@ public:
/// PrintVersion - Print the driver version.
void PrintVersion(const Compilation &C, raw_ostream &OS) const;
- /// GetFilePath - Lookup \arg Name in the list of file search paths.
+ /// GetFilePath - Lookup \p Name in the list of file search paths.
///
- /// \arg TC - The tool chain for additional information on
+ /// \param TC - The tool chain for additional information on
/// directories to search.
//
// FIXME: This should be in CompilationInfo.
std::string GetFilePath(const char *Name, const ToolChain &TC) const;
- /// GetProgramPath - Lookup \arg Name in the list of program search
- /// paths.
+ /// GetProgramPath - Lookup \p Name in the list of program search paths.
///
- /// \arg TC - The provided tool chain for additional information on
+ /// \param TC - The provided tool chain for additional information on
/// directories to search.
- ///
- /// \arg WantFile - False when searching for an executable file, otherwise
- /// true. Defaults to false.
//
// FIXME: This should be in CompilationInfo.
- std::string GetProgramPath(const char *Name, const ToolChain &TC,
- bool WantFile = false) const;
+ std::string GetProgramPath(const char *Name, const ToolChain &TC) const;
/// HandleImmediateArgs - Handle any arguments which should be
/// treated before building actions or binding tools.
@@ -352,14 +327,14 @@ public:
bool HandleImmediateArgs(const Compilation &C);
/// ConstructAction - Construct the appropriate action to do for
- /// \arg Phase on the \arg Input, taking in to account arguments
+ /// \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 *Input) const;
/// BuildJobsForAction - Construct the jobs to perform for the
- /// action \arg A.
+ /// action \p A.
void BuildJobsForAction(Compilation &C,
const Action *A,
const ToolChain *TC,
@@ -369,7 +344,7 @@ public:
InputInfo &Result) const;
/// GetNamedOutputPath - Return the name to use for the output of
- /// the action \arg JA. The result is appended to the compilation's
+ /// the action \p JA. The result is appended to the compilation's
/// list of temporary or result files, as appropriate.
///
/// \param C - The compilation.
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index c94886dc26c1..84f5ee19173d 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -39,8 +39,6 @@ public:
/// addCommand - Append a command to the current job, which must be
/// either a piped job or a job list.
void addCommand(Command *C);
-
- static bool classof(const Job *) { return true; }
};
/// Command - An executable path/name and argument vector to
@@ -78,7 +76,6 @@ public:
static bool classof(const Job *J) {
return J->getKind() == CommandClass;
}
- static bool classof(const Command *) { return true; }
};
/// JobList - A sequence of jobs to perform.
@@ -113,7 +110,6 @@ public:
static bool classof(const Job *J) {
return J->getKind() == JobListClass;
}
- static bool classof(const JobList *) { return true; }
};
} // end namespace driver
diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td
index 9e6d5b9118e8..d16a2a779324 100644
--- a/include/clang/Driver/OptParser.td
+++ b/include/clang/Driver/OptParser.td
@@ -88,6 +88,9 @@ 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> {
@@ -99,8 +102,9 @@ class OptionGroup<string name> {
// Define the option class.
-class Option<string name, OptionKind kind> {
+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.
@@ -114,15 +118,22 @@ class Option<string name, OptionKind kind> {
// Helpers for defining options.
-class Flag<string name> : Option<name, KIND_FLAG>;
-class Joined<string name> : Option<name, KIND_JOINED>;
-class Separate<string name> : Option<name, KIND_SEPARATE>;
-class CommaJoined<string name> : Option<name, KIND_COMMAJOINED>;
-class MultiArg<string name, int numargs> : Option<name, KIND_MULTIARG> {
+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<string name> : Option<name, KIND_JOINED_OR_SEPARATE>;
-class JoinedAndSeparate<string name> : Option<name, KIND_JOINED_AND_SEPARATE>;
+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.
@@ -137,5 +148,5 @@ class MetaVarName<string name> { string MetaVarName = name; }
// 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>;
+def INPUT : Option<[], "<input>", KIND_INPUT>, Flags<[DriverOption,CC1Option]>;
+def UNKNOWN : Option<[], "<unknown>", KIND_UNKNOWN>;
diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h
index 27bd11985a67..53d83a0f38aa 100644
--- a/include/clang/Driver/OptTable.h
+++ b/include/clang/Driver/OptTable.h
@@ -12,24 +12,10 @@
#include "clang/Basic/LLVM.h"
#include "clang/Driver/OptSpecifier.h"
+#include "llvm/ADT/StringSet.h"
namespace clang {
namespace driver {
-namespace options {
- enum DriverFlag {
- DriverOption = (1 << 0),
- HelpHidden = (1 << 1),
- LinkerInput = (1 << 2),
- NoArgumentUnused = (1 << 3),
- NoForward = (1 << 4),
- RenderAsInput = (1 << 5),
- RenderJoined = (1 << 6),
- RenderSeparate = (1 << 7),
- Unsupported = (1 << 8),
- CC1Option = (1 << 9)
- };
-}
-
class Arg;
class ArgList;
class InputArgList;
@@ -46,9 +32,13 @@ namespace options {
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;
@@ -61,19 +51,18 @@ namespace options {
const Info *OptionInfos;
unsigned NumOptionInfos;
- /// \brief The lazily constructed options table, indexed by option::ID - 1.
- mutable Option **Options;
-
- /// \brief Prebound input option instance.
- const Option *TheInputOption;
-
- /// \brief Prebound unknown option instance.
- const Option *TheUnknownOption;
+ 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();
@@ -81,8 +70,6 @@ namespace options {
return OptionInfos[id - 1];
}
- Option *CreateOption(unsigned id) const;
-
protected:
OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos);
public:
@@ -95,17 +82,7 @@ namespace options {
/// if necessary.
///
/// \return The option, or null for the INVALID option id.
- const Option *getOption(OptSpecifier Opt) const {
- unsigned id = Opt.getID();
- if (id == 0)
- return 0;
-
- assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
- Option *&Entry = Options[id - 1];
- if (!Entry)
- Entry = CreateOption(id);
- return Entry;
- }
+ const Option getOption(OptSpecifier Opt) const;
/// \brief Lookup the name of the given option.
const char *getOptionName(OptSpecifier id) const {
@@ -122,11 +99,6 @@ namespace options {
return getInfo(id).GroupID;
}
- /// \brief Should the help for the given option be hidden by default.
- bool isOptionHelpHidden(OptSpecifier id) const {
- return getInfo(id).Flags & options::HelpHidden;
- }
-
/// \brief Get the help text to use to describe this option.
const char *getOptionHelpText(OptSpecifier id) const {
return getInfo(id).HelpText;
@@ -176,9 +148,12 @@ namespace options {
/// \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 ShowHidden - Whether help-hidden arguments should be shown.
+ /// \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, bool ShowHidden = false) const;
+ const char *Title, unsigned short FlagsToInclude = 0,
+ unsigned short FlagsToExclude = 0) const;
};
}
}
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
index e6c4e12e0d1b..c3db773cd922 100644
--- a/include/clang/Driver/Option.h
+++ b/include/clang/Driver/Option.h
@@ -10,15 +10,36 @@
#ifndef CLANG_DRIVER_OPTION_H_
#define CLANG_DRIVER_OPTION_H_
-#include "clang/Driver/OptSpecifier.h"
+#include "clang/Driver/OptTable.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
class Arg;
class ArgList;
- class OptionGroup;
+
+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.
@@ -53,100 +74,104 @@ namespace driver {
RenderValuesStyle
};
- private:
- OptionClass Kind;
-
- /// The option ID.
- OptSpecifier ID;
-
- /// The option name.
- StringRef Name;
-
- /// Group this option is a member of, if any.
- const OptionGroup *Group;
-
- /// Option that this is an alias for, if any.
- const Option *Alias;
-
- /// Unsupported options will be rejected.
- bool Unsupported : 1;
-
- /// Treat this option like a linker input?
- bool LinkerInput : 1;
-
- /// When rendering as an input, don't render the option.
+ protected:
+ const OptTable::Info *Info;
+ const OptTable *Owner;
- // FIXME: We should ditch the render/renderAsInput distinction.
- bool NoOptAsInput : 1;
+ public:
+ Option(const OptTable::Info *Info, const OptTable *Owner);
+ ~Option();
- /// The style to using when rendering arguments parsed by this option.
- unsigned RenderStyle : 2;
+ bool isValid() const {
+ return Info != 0;
+ }
- /// This option is only consumed by the driver.
- bool DriverOption : 1;
+ unsigned getID() const {
+ assert(Info && "Must have a valid info!");
+ return Info->ID;
+ }
- /// This option should not report argument unused errors.
- bool NoArgumentUnused : 1;
+ OptionClass getKind() const {
+ assert(Info && "Must have a valid info!");
+ return OptionClass(Info->Kind);
+ }
- /// This option should not be implicitly forwarded.
- bool NoForward : 1;
+ /// \brief Get the name of this option without any prefix.
+ StringRef getName() const {
+ assert(Info && "Must have a valid info!");
+ return Info->Name;
+ }
- /// CC1Option - This option should be accepted by clang -cc1.
- bool CC1Option : 1;
+ const Option getGroup() const {
+ assert(Info && "Must have a valid info!");
+ assert(Owner && "Must have a valid owner!");
+ return Owner->getOption(Info->GroupID);
+ }
- protected:
- Option(OptionClass Kind, OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias);
- public:
- virtual ~Option();
+ const Option getAlias() const {
+ assert(Info && "Must have a valid info!");
+ assert(Owner && "Must have a valid owner!");
+ return Owner->getOption(Info->AliasID);
+ }
- unsigned getID() const { return ID.getID(); }
- OptionClass getKind() const { return Kind; }
- StringRef getName() const { return Name; }
- const OptionGroup *getGroup() const { return Group; }
- const Option *getAlias() const { return Alias; }
+ /// \brief Get the default prefix for this option.
+ StringRef getPrefix() const {
+ const char *Prefix = *Info->Prefixes;
+ return Prefix ? Prefix : StringRef();
+ }
- bool isUnsupported() const { return Unsupported; }
- void setUnsupported(bool Value) { Unsupported = Value; }
+ /// \brief Get the name of this option with the default prefix.
+ std::string getPrefixedName() const {
+ std::string Ret = getPrefix();
+ Ret += getName();
+ return Ret;
+ }
- bool isLinkerInput() const { return LinkerInput; }
- void setLinkerInput(bool Value) { LinkerInput = Value; }
+ unsigned getNumArgs() const { return Info->Param; }
- bool hasNoOptAsInput() const { return NoOptAsInput; }
- void setNoOptAsInput(bool Value) { NoOptAsInput = Value; }
+ bool hasNoOptAsInput() const { return Info->Flags & options::RenderAsInput;}
RenderStyleKind getRenderStyle() const {
- return RenderStyleKind(RenderStyle);
+ 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!");
}
- void setRenderStyle(RenderStyleKind Value) { RenderStyle = Value; }
-
- bool isDriverOption() const { return DriverOption; }
- void setDriverOption(bool Value) { DriverOption = Value; }
- bool hasNoArgumentUnused() const { return NoArgumentUnused; }
- void setNoArgumentUnused(bool Value) { NoArgumentUnused = Value; }
-
- bool hasNoForward() const { return NoForward; }
- void setNoForward(bool Value) { NoForward = Value; }
-
- bool isCC1Option() const { return CC1Option; }
- void setIsCC1Option(bool Value) { CC1Option = Value; }
-
- bool hasForwardToGCC() const {
- return !NoForward && !DriverOption && !LinkerInput;
+ /// 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 {
- if (Alias) return Alias->getUnaliasedOption();
- return this;
+ 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();
+ return getUnaliasedOption().getName();
}
/// matches - Predicate for whether this option is part of the
@@ -164,158 +189,13 @@ namespace driver {
/// 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).
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const = 0;
+ ///
+ /// \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;
-
- static bool classof(const Option *) { return true; }
- };
-
- /// OptionGroup - A set of options which are can be handled uniformly
- /// by the driver.
- class OptionGroup : public Option {
- public:
- OptionGroup(OptSpecifier ID, const char *Name, const OptionGroup *Group);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::GroupClass;
- }
- static bool classof(const OptionGroup *) { return true; }
- };
-
- // Dummy option classes.
-
- /// InputOption - Dummy option class for representing driver inputs.
- class InputOption : public Option {
- public:
- InputOption(OptSpecifier ID);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::InputClass;
- }
- static bool classof(const InputOption *) { return true; }
- };
-
- /// UnknownOption - Dummy option class for represent unknown arguments.
- class UnknownOption : public Option {
- public:
- UnknownOption(OptSpecifier ID);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::UnknownClass;
- }
- static bool classof(const UnknownOption *) { return true; }
- };
-
- // Normal options.
-
- class FlagOption : public Option {
- public:
- FlagOption(OptSpecifier ID, const char *Name, const OptionGroup *Group,
- const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::FlagClass;
- }
- static bool classof(const FlagOption *) { return true; }
- };
-
- class JoinedOption : public Option {
- public:
- JoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group,
- const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::JoinedClass;
- }
- static bool classof(const JoinedOption *) { return true; }
- };
-
- class SeparateOption : public Option {
- public:
- SeparateOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::SeparateClass;
- }
- static bool classof(const SeparateOption *) { return true; }
- };
-
- class CommaJoinedOption : public Option {
- public:
- CommaJoinedOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::CommaJoinedClass;
- }
- static bool classof(const CommaJoinedOption *) { return true; }
- };
-
- // FIXME: Fold MultiArgOption into SeparateOption?
-
- /// MultiArgOption - An option which takes multiple arguments (these
- /// are always separate arguments).
- class MultiArgOption : public Option {
- unsigned NumArgs;
-
- public:
- MultiArgOption(OptSpecifier ID, const char *Name, const OptionGroup *Group,
- const Option *Alias, unsigned NumArgs);
-
- unsigned getNumArgs() const { return NumArgs; }
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::MultiArgClass;
- }
- static bool classof(const MultiArgOption *) { return true; }
- };
-
- /// JoinedOrSeparateOption - An option which either literally
- /// prefixes its (non-empty) value, or is follwed by a value.
- class JoinedOrSeparateOption : public Option {
- public:
- JoinedOrSeparateOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::JoinedOrSeparateClass;
- }
- static bool classof(const JoinedOrSeparateOption *) { return true; }
- };
-
- /// JoinedAndSeparateOption - An option which literally prefixes its
- /// value and is followed by another value.
- class JoinedAndSeparateOption : public Option {
- public:
- JoinedAndSeparateOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias);
-
- virtual Arg *accept(const ArgList &Args, unsigned &Index) const;
-
- static bool classof(const Option *O) {
- return O->getKind() == Option::JoinedAndSeparateClass;
- }
- static bool classof(const JoinedAndSeparateOption *) { return true; }
};
} // end namespace driver
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index ac312cdfd4d2..6c114e252d3c 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -17,11 +17,13 @@ namespace driver {
namespace options {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) OPT_##ID,
#include "clang/Driver/Options.inc"
LastOption
#undef OPTION
+#undef PREFIX
};
}
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index c7698a28f910..77ba17a2b4c7 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1,4 +1,4 @@
-//===--- DriverOptions.td - Options for clang -----------------------------===//
+//===--- Options.td - Options for clang -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -41,6 +41,8 @@ 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 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>;
@@ -82,1092 +84,1071 @@ 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,
+def ccc_cxx : Flag<["-"], "ccc-cxx">, CCCDriverOpt,
HelpText<"Act as a C++ driver">;
-def ccc_echo : Flag<"-ccc-echo">, CCCDriverOpt,
+def ccc_echo : Flag<["-"], "ccc-echo">, CCCDriverOpt,
HelpText<"Echo commands before running them">;
-def ccc_gcc_name : Separate<"-ccc-gcc-name">, CCCDriverOpt,
+def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, CCCDriverOpt,
HelpText<"Name for native GCC compiler">,
MetaVarName<"<gcc-path>">;
-def ccc_clang_cxx : Flag<"-ccc-clang-cxx">, CCCDriverOpt,
- HelpText<"Enable the clang compiler for C++">;
-def ccc_no_clang_cxx : Flag<"-ccc-no-clang-cxx">, CCCDriverOpt,
- HelpText<"Disable the clang compiler for C++">;
-def ccc_no_clang : Flag<"-ccc-no-clang">, CCCDriverOpt,
- HelpText<"Disable the clang compiler">;
-def ccc_no_clang_cpp : Flag<"-ccc-no-clang-cpp">, CCCDriverOpt,
- HelpText<"Disable the clang preprocessor">;
-def ccc_clang_archs : Separate<"-ccc-clang-archs">, CCCDriverOpt,
+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">, CCCDriverOpt,
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">, CCCDriverOpt,
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,
+def ccc_install_dir : Separate<["-"], "ccc-install-dir">, CCCDebugOpt,
HelpText<"Simulate installation in the given directory">;
-def ccc_print_options : Flag<"-ccc-print-options">, CCCDebugOpt,
+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">, CCCDebugOpt,
HelpText<"Dump list of actions to perform">;
-def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt,
+def ccc_print_bindings : Flag<["-"], "ccc-print-bindings">, CCCDebugOpt,
HelpText<"Show bindings of tools to actions">;
-def ccc_arcmt_check : Flag<"-ccc-arcmt-check">, CCCDriverOpt,
+def ccc_arcmt_check : Flag<["-"], "ccc-arcmt-check">, CCCDriverOpt,
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">, CCCDriverOpt,
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_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,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
+def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output">,
HelpText<"Output path for the plist report">, Flags<[CC1Option]>;
-def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
+def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
HelpText<"Emit ARC errors even if the migrator can fix them">,
Flags<[CC1Option]>;
-def _migrate : Flag<"--migrate">, Flags<[DriverOption]>,
+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">, CCCDriverOpt,
HelpText<"Apply modifications and produces temporary files to migrate to "
"modern ObjC syntax">;
-def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">, Flags<[CC1Option]>,
+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]>,
+def objcmt_migrate_subscripting : Flag<["-"], "objcmt-migrate-subscripting">, Flags<[CC1Option]>,
HelpText<"Enable migration to modern ObjC subscripting">;
// Make sure all other -ccc- options are rejected.
-def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
+def ccc_ : Joined<["-"], "ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
// Standard Options
-def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>,
+def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption]>,
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 B : JoinedOrSeparate<"-B">;
-def CC : Flag<"-CC">, Flags<[CC1Option]>;
-def C : Flag<"-C">, Flags<[CC1Option]>;
-def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
-def E : Flag<"-E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
+def _DASH_DASH : Flag<["--"], "">, Flags<[DriverOption]>;
+def A : JoinedOrSeparate<["-"], "A">;
+def B : JoinedOrSeparate<["-"], "B">;
+def CC : Flag<["-"], "CC">, Flags<[CC1Option]>;
+def C : Flag<["-"], "C">, Flags<[CC1Option]>;
+def D : JoinedOrSeparate<["-"], "D">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run the preprocessor">;
-def F : JoinedOrSeparate<"-F">, Flags<[RenderJoined,CC1Option]>,
+def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
HelpText<"Add directory to framework include search path">;
-def G : Separate<"-G">, Flags<[DriverOption]>;
-def H : Flag<"-H">, Flags<[CC1Option]>,
+def G : Separate<["-"], "G">, Flags<[DriverOption]>;
+def H : Flag<["-"], "H">, Flags<[CC1Option]>,
HelpText<"Show header includes and nesting depth">;
-def I_ : Flag<"-I-">, Group<I_Group>;
-def I : JoinedOrSeparate<"-I">, Group<I_Group>, Flags<[CC1Option]>,
+def I_ : Flag<["-"], "I-">, Group<I_Group>;
+def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to include search path">;
-def L : JoinedOrSeparate<"-L">, Flags<[RenderJoined]>;
-def MD : Flag<"-MD">, Group<M_Group>;
-def MF : JoinedOrSeparate<"-MF">, Group<M_Group>;
-def MG : Flag<"-MG">, Group<M_Group>, Flags<[CC1Option]>,
+def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>;
+def MD : Flag<["-"], "MD">, Group<M_Group>;
+def MF : JoinedOrSeparate<["-"], "MF">, Group<M_Group>;
+def MG : Flag<["-"], "MG">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Add missing headers to dependency list">;
-def MMD : Flag<"-MMD">, Group<M_Group>;
-def MM : Flag<"-MM">, Group<M_Group>;
-def MP : Flag<"-MP">, Group<M_Group>, Flags<[CC1Option]>,
+def MMD : Flag<["-"], "MMD">, Group<M_Group>;
+def MM : Flag<["-"], "MM">, Group<M_Group>;
+def MP : Flag<["-"], "MP">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Create phony target for each dependency (other than main file)">;
-def MQ : JoinedOrSeparate<"-MQ">, Group<M_Group>, Flags<[CC1Option]>,
+def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Specify target to quote for dependency">;
-def MT : JoinedOrSeparate<"-MT">, Group<M_Group>, Flags<[CC1Option]>,
+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 ObjCXX : Flag<"-ObjC++">, Flags<[DriverOption]>,
+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 ObjCXX : Flag<["-"], "ObjC++">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C++ inputs">;
-def ObjC : Flag<"-ObjC">, Flags<[DriverOption]>,
+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 P : Flag<"-P">, Flags<[CC1Option]>,
+def O : Joined<["-"], "O">, 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 Qn : Flag<["-"], "Qn">;
+def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption]>,
HelpText<"Don't emit warning for unused driver arguments">;
-def Q : Flag<"-Q">;
-def R : Flag<"-R">;
-def S : Flag<"-S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
+def Q : Flag<["-"], "Q">;
+def R : Flag<["-"], "R">;
+def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run preprocess and compilation steps">;
-def Tbss : JoinedOrSeparate<"-Tbss">, Group<T_Group>;
-def Tdata : JoinedOrSeparate<"-Tdata">, Group<T_Group>;
-def Ttext : JoinedOrSeparate<"-Ttext">, Group<T_Group>;
-def T : JoinedOrSeparate<"-T">, Group<T_Group>;
-def U : JoinedOrSeparate<"-U">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
-def V : JoinedOrSeparate<"-V">, Flags<[DriverOption, Unsupported]>;
-def Wa_COMMA : CommaJoined<"-Wa,">,
+def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
+def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>;
+def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>;
+def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>;
+def U : JoinedOrSeparate<["-"], "U">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def V : JoinedOrSeparate<["-"], "V">, Flags<[DriverOption, Unsupported]>;
+def Wa_COMMA : CommaJoined<["-"], "Wa,">,
HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
MetaVarName<"<arg>">;
-def Wall : Flag<"-Wall">, Group<W_Group>, Flags<[CC1Option]>;
-def Wdeprecated : Flag<"-Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>;
-def Wno_deprecated : Flag<"-Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>;
-def Wextra : Flag<"-Wextra">, Group<W_Group>, Flags<[CC1Option]>;
-def Wl_COMMA : CommaJoined<"-Wl,">, Flags<[LinkerInput, RenderAsInput]>,
+def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option]>;
+def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>;
+def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>;
+def Wextra : Flag<["-"], "Wextra">, Group<W_Group>, Flags<[CC1Option]>;
+def Wl_COMMA : CommaJoined<["-"], "Wl,">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass the comma separated arguments in <arg> to the linker">,
MetaVarName<"<arg>">;
-def Wno_nonportable_cfstrings : Joined<"-Wno-nonportable-cfstrings">, Group<W_Group>,
+def Wno_nonportable_cfstrings : Joined<["-"], "Wno-nonportable-cfstrings">, Group<W_Group>,
Flags<[CC1Option]>;
-def Wnonportable_cfstrings : Joined<"-Wnonportable-cfstrings">, Group<W_Group>,
+def Wnonportable_cfstrings : Joined<["-"], "Wnonportable-cfstrings">, Group<W_Group>,
Flags<[CC1Option]>;
-def Wp_COMMA : CommaJoined<"-Wp,">,
+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 Xanalyzer : Separate<"-Xanalyzer">,
+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]>,
+ MetaVarName<"<warning>">, HelpText<"Enable the specified warning">;
+def Xanalyzer : Separate<["-"], "Xanalyzer">,
HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
-def Xarch__ : JoinedAndSeparate<"-Xarch_">, Flags<[DriverOption]>;
-def Xassembler : Separate<"-Xassembler">,
+def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[DriverOption]>;
+def Xassembler : Separate<["-"], "Xassembler">,
HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">;
-def Xclang : Separate<"-Xclang">,
+def Xclang : Separate<["-"], "Xclang">,
HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">,
Flags<[NoForward]>;
-def Xlinker : Separate<"-Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
+def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">;
-def Xpreprocessor : Separate<"-Xpreprocessor">,
+def Xpreprocessor : Separate<["-"], "Xpreprocessor">,
HelpText<"Pass <arg> to the preprocessor">, MetaVarName<"<arg>">;
-def X_Flag : Flag<"-X">;
-def X_Joined : Joined<"-X">;
-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 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 bind__at__load : Flag<"-bind_at_load">;
-def bundle__loader : Separate<"-bundle_loader">;
-def bundle : Flag<"-bundle">;
-def b : JoinedOrSeparate<"-b">, Flags<[Unsupported]>;
-def cl_kernel_arg_info : Flag<"-cl-kernel-arg-info">, Flags<[CC1Option]>, Group<opencl_Group>,
+def X_Flag : Flag<["-"], "X">;
+def X_Joined : Joined<["-"], "X">;
+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 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 bind__at__load : Flag<["-"], "bind_at_load">;
+def bundle__loader : Separate<["-"], "bundle_loader">;
+def bundle : Flag<["-"], "bundle">;
+def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>;
+def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">, Flags<[CC1Option]>, Group<opencl_Group>,
HelpText<"OpenCL only. This option allows the compiler to store information about the arguments of a kernel(s)"> ;
-def client__name : JoinedOrSeparate<"-client_name">;
-def combine : Flag<"-combine">, Flags<[DriverOption, Unsupported]>;
-def compatibility__version : JoinedOrSeparate<"-compatibility_version">;
-def coverage : Flag<"-coverage">;
-def cpp_precomp : Flag<"-cpp-precomp">, Group<clang_ignored_f_Group>;
-def current__version : JoinedOrSeparate<"-current_version">;
-def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, Group<clang_i_Group>,
+def client__name : JoinedOrSeparate<["-"], "client_name">;
+def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>;
+def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">;
+def coverage : Flag<["-", "--"], "coverage">;
+def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
+def current__version : JoinedOrSeparate<["-"], "current_version">;
+def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">, Flags<[CC1Option]>,
MetaVarName<"<directory>">;
-def c : Flag<"-c">, Flags<[DriverOption]>,
+def c : Flag<["-"], "c">, Flags<[DriverOption]>,
HelpText<"Only run preprocess, compile, and assemble steps">;
-def dA : Flag<"-dA">, Group<d_Group>;
-def dD : Flag<"-dD">, Group<d_Group>, Flags<[CC1Option]>,
+def dA : Flag<["-"], "dA">, Group<d_Group>;
+def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>,
HelpText<"Print macro definitions in -E mode in addition to normal output">;
-def dM : Flag<"-dM">, Group<d_Group>, Flags<[CC1Option]>,
+def dM : Flag<["-"], "dM">, Group<d_Group>, Flags<[CC1Option]>,
HelpText<"Print macro definitions in -E mode instead of normal output">;
-def dead__strip : Flag<"-dead_strip">;
-def dependency_file : Separate<"-dependency-file">, Flags<[CC1Option]>,
+def dead__strip : Flag<["-"], "dead_strip">;
+def dependency_file : Separate<["-"], "dependency-file">, Flags<[CC1Option]>,
HelpText<"Filename (or -) to write dependency output to">;
-def dependency_dot : Separate<"-dependency-dot">, Flags<[CC1Option]>,
+def dependency_dot : Separate<["-"], "dependency-dot">, Flags<[CC1Option]>,
HelpText<"Filename to write DOT-formatted header dependencies to">;
-def dumpmachine : Flag<"-dumpmachine">;
-def dumpspecs : Flag<"-dumpspecs">, Flags<[Unsupported]>;
-def dumpversion : Flag<"-dumpversion">;
-def dylib__file : Separate<"-dylib_file">;
-def dylinker__install__name : JoinedOrSeparate<"-dylinker_install_name">;
-def dylinker : Flag<"-dylinker">;
-def dynamiclib : Flag<"-dynamiclib">;
-def dynamic : Flag<"-dynamic">, Flags<[NoArgumentUnused]>;
-def d_Flag : Flag<"-d">, Group<d_Group>;
-def d_Joined : Joined<"-d">, Group<d_Group>;
-def emit_ast : Flag<"-emit-ast">,
+def dumpmachine : Flag<["-"], "dumpmachine">;
+def dumpspecs : Flag<["-"], "dumpspecs">, Flags<[Unsupported]>;
+def dumpversion : Flag<["-"], "dumpversion">;
+def dylib__file : Separate<["-"], "dylib_file">;
+def dylinker__install__name : JoinedOrSeparate<["-"], "dylinker_install_name">;
+def dylinker : Flag<["-"], "dylinker">;
+def dynamiclib : Flag<["-"], "dynamiclib">;
+def dynamic : Flag<["-"], "dynamic">, Flags<[NoArgumentUnused]>;
+def d_Flag : Flag<["-"], "d">, Group<d_Group>;
+def d_Joined : Joined<["-"], "d">, Group<d_Group>;
+def emit_ast : Flag<["-"], "emit-ast">,
HelpText<"Emit Clang AST files for source inputs">;
-def emit_llvm : Flag<"-emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
+def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the LLVM representation for assembler and object files">;
-def exported__symbols__list : Separate<"-exported_symbols_list">;
-def e : JoinedOrSeparate<"-e">;
-def fPIC : Flag<"-fPIC">, Group<f_Group>;
-def fno_PIC : Flag<"-fno-PIC">, Group<f_Group>;
-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]>,
+def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
+def e : JoinedOrSeparate<["-"], "e">;
+def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;
+def fno_PIC : Flag<["-"], "fno-PIC">, Group<f_Group>;
+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 fapple_kext : Flag<"-fapple-kext">, 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]>,
+def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Apple gcc-compatible #pragma pack handling">;
-def faddress_sanitizer : Flag<"-faddress-sanitizer">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Enable AddressSanitizer instrumentation (memory error detection)">;
-def fno_address_sanitizer : Flag<"-fno-address-sanitizer">, Group<f_Group>, Flags<[CC1Option]>;
-def fthread_sanitizer : Flag<"-fthread-sanitizer">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Enable ThreadSanitizer instrumentation (race detection)">;
-def fno_thread_sanitizer : Flag<"-fno-thread-sanitizer">, Group<f_Group>, Flags<[CC1Option]>;
-def fasm : Flag<"-fasm">, Group<f_Group>;
+def faddress_sanitizer : Flag<["-"], "faddress-sanitizer">, Group<f_Group>;
+def fno_address_sanitizer : Flag<["-"], "fno-address-sanitizer">, Group<f_Group>;
+def fthread_sanitizer : Flag<["-"], "fthread-sanitizer">, Group<f_Group>;
+def fno_thread_sanitizer : Flag<["-"], "fno-thread-sanitizer">, Group<f_Group>;
+def fasm : Flag<["-"], "fasm">, Group<f_Group>;
-def fasm_blocks : Flag<"-fasm-blocks">, Group<f_Group>;
-def fno_asm_blocks : Flag<"-fno-asm-blocks">, Group<f_Group>;
+def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>;
+def fno_asm_blocks : Flag<["-"], "fno-asm-blocks">, Group<f_Group>;
-def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>;
-def fastcp : Flag<"-fastcp">, Group<f_Group>;
-def fastf : Flag<"-fastf">, Group<f_Group>;
-def fast : Flag<"-fast">, Group<f_Group>;
-def fasynchronous_unwind_tables : Flag<"-fasynchronous-unwind-tables">, Group<f_Group>;
-def fblocks : Flag<"-fblocks">, Group<f_Group>, Flags<[CC1Option]>,
+def fassume_sane_operator_new : Flag<["-"], "fassume-sane-operator-new">, Group<f_Group>;
+def fastcp : Flag<["-"], "fastcp">, Group<f_Group>;
+def fastf : Flag<["-"], "fastf">, Group<f_Group>;
+def fast : Flag<["-"], "fast">, Group<f_Group>;
+def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>;
+def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the 'blocks' language feature">;
-def fbootclasspath_EQ : Joined<"-fbootclasspath=">, Group<f_Group>;
-def fborland_extensions : Flag<"-fborland-extensions">, Group<f_Group>, Flags<[CC1Option]>,
+def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group<f_Group>;
+def fborland_extensions : Flag<["-"], "fborland-extensions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Accept non-standard constructs supported by the Borland compiler">;
-def fbounds_checking : Flag<"-fbounds-checking">, Group<f_Group>,
- HelpText<"Enable run-time bounds checks.">;
-def fbounds_checking_EQ : Joined<"-fbounds-checking=">, Flags<[CC1Option]>,
+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">, Flags<[CC1Option]>,
- Group<f_Group>, HelpText<"Generate runtime checks for undefined behavior.">;
-def fclasspath_EQ : Joined<"-fclasspath=">, Group<f_Group>;
-def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, Group<f_Group>, Flags<[CC1Option]>,
+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>;
+def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
+def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use colors in diagnostics">;
-def fcommon : Flag<"-fcommon">, Group<f_Group>;
-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_backtrace_limit_EQ : Joined<"-fconstexpr-backtrace-limit=">,
+def fcommon : Flag<["-"], "fcommon">, Group<f_Group>;
+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_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>,
+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 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>;
-def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_clang_Group>,
+def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>, Flags<[NoForward]>;
+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>;
+def fdiagnostics_parseable_fixits : Flag<["-"], "fdiagnostics-parseable-fixits">, Group<f_clang_Group>,
Flags<[CC1Option]>, HelpText<"Print fix-its in machine parseable form">;
-def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">,
+def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-source-range-info">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Print source range spans in numeric form">;
-def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>,
+def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">;
-def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">, Group<f_Group>,
+def fdiagnostics_show_name : Flag<["-"], "fdiagnostics-show-name">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Print diagnostic name">;
-def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">,
+def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">,
Group<f_Group>, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">;
-def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>;
-def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>;
-def fdiagnostics_show_template_tree : Flag<"-fdiagnostics-show-template-tree">,
+def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, Group<f_clang_Group>;
+def fdiagnostics_show_category_EQ : Joined<["-"], "fdiagnostics-show-category=">, Group<f_clang_Group>;
+def fdiagnostics_show_template_tree : Flag<["-"], "fdiagnostics-show-template-tree">,
Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Print a template comparison tree for differing templates">;
-def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>,
+def fdollars_in_identifiers : Flag<["-"], "fdollars-in-identifiers">, Group<f_Group>,
HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>;
-def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>;
-def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, Group<f_Group>, Flags<[CC1Option]>;
-def fdwarf_directory_asm : Flag<"-fdwarf-directory-asm">, Group<f_Group>;
-def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, Group<f_Group>, Flags<[CC1Option]>;
-def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>;
-def fno_elide_type : Flag<"-fno-elide-type">, Group<f_Group>,
+def fdwarf2_cfi_asm : Flag<["-"], "fdwarf2-cfi-asm">, Group<f_Group>;
+def fno_dwarf2_cfi_asm : Flag<["-"], "fno-dwarf2-cfi-asm">, Group<f_Group>, Flags<[CC1Option]>;
+def fdwarf_directory_asm : Flag<["-"], "fdwarf-directory-asm">, Group<f_Group>;
+def fno_dwarf_directory_asm : Flag<["-"], "fno-dwarf-directory-asm">, Group<f_Group>, Flags<[CC1Option]>;
+def felide_constructors : Flag<["-"], "felide-constructors">, Group<f_Group>;
+def fno_elide_type : Flag<["-"], "fno-elide-type">, Group<f_Group>,
Flags<[CC1Option]>,
HelpText<"Do not elide types when printing diagnostics">;
-def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>;
-def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
+def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
+def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Emit all declarations, even if unused">;
-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]>,
+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 fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
-def fhosted : Flag<"-fhosted">, Group<f_Group>;
-def ffast_math : Flag<"-ffast-math">, Group<f_Group>, Flags<[CC1Option]>,
+def fextdirs_EQ : Joined<["-"], "fextdirs=">, Group<f_Group>;
+def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
+def ffast_math : Flag<["-"], "ffast-math">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on "
"optimizations, but provides a preprocessor macro __FAST_MATH__ the "
- "same as GCC's -ffast-math flag.">;
-def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>, Flags<[CC1Option]>,
+ "same as GCC's -ffast-math flag">;
+def fno_fast_math : Flag<["-"], "fno-fast-math">, Group<f_Group>;
+def fmath_errno : Flag<["-"], "fmath-errno">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Require math functions to indicate errors by setting errno">;
-def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
-def fsignaling_math : Flag<"-fsignaling-math">, Group<f_Group>;
-def fno_signaling_math : Flag<"-fno-signaling-math">, Group<f_Group>;
-def funsafe_math_optimizations : Flag<"-funsafe-math-optimizations">,
+def fno_math_errno : Flag<["-"], "fno-math-errno">, 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>">,
+ HelpText<"Enable runtime instrumentation for bug detection: "
+ "address (memory errors) | thread (race detection) | "
+ "undefined (miscellaneous undefined behavior)">;
+def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>;
+def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
-def fno_unsafe_math_optimizations : Flag<"-fno-unsafe-math-optimizations">,
+def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
Group<f_Group>;
-def fassociative_math : Flag<"-fassociative-math">, Group<f_Group>;
-def fno_associative_math : Flag<"-fno-associative-math">, Group<f_Group>;
-def freciprocal_math : Flag<"-freciprocal-math">, Group<f_Group>;
-def fno_reciprocal_math : Flag<"-fno-reciprocal-math">, Group<f_Group>;
-def ffinite_math_only : Flag<"-ffinite-math-only">, Group<f_Group>, Flags<[CC1Option]>;
-def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<f_Group>;
-def fsigned_zeros : Flag<"-fsigned-zeros">, Group<f_Group>;
-def fno_signed_zeros : Flag<"-fno-signed-zeros">, Group<f_Group>;
-def fhonor_nans : Flag<"-fhonor-nans">, Group<f_Group>;
-def fno_honor_nans : Flag<"-fno-honor-nans">, Group<f_Group>;
-def fhonor_infinities : Flag<"-fhonor-infinities">, Group<f_Group>;
-def fno_honor_infinities : Flag<"-fno-honor-infinities">, Group<f_Group>;
+def fassociative_math : Flag<["-"], "fassociative-math">, Group<f_Group>;
+def fno_associative_math : Flag<["-"], "fno-associative-math">, Group<f_Group>;
+def freciprocal_math : Flag<["-"], "freciprocal-math">, Group<f_Group>;
+def fno_reciprocal_math : Flag<["-"], "fno-reciprocal-math">, Group<f_Group>;
+def ffinite_math_only : Flag<["-"], "ffinite-math-only">, Group<f_Group>, Flags<[CC1Option]>;
+def fno_finite_math_only : Flag<["-"], "fno-finite-math-only">, Group<f_Group>;
+def fsigned_zeros : Flag<["-"], "fsigned-zeros">, Group<f_Group>;
+def fno_signed_zeros : Flag<["-"], "fno-signed-zeros">, Group<f_Group>;
+def fhonor_nans : Flag<["-"], "fhonor-nans">, Group<f_Group>;
+def fno_honor_nans : Flag<["-"], "fno-honor-nans">, Group<f_Group>;
+def fhonor_infinities : Flag<["-"], "fhonor-infinities">, Group<f_Group>;
+def fno_honor_infinities : Flag<["-"], "fno-honor-infinities">, Group<f_Group>;
// Sic. This option was misspelled originally.
-def fhonor_infinites : Flag<"-fhonor-infinites">, Alias<fhonor_infinities>;
-def fno_honor_infinites : Flag<"-fno-honor-infinites">, Alias<fno_honor_infinities>;
-def ftrapping_math : Flag<"-ftrapping-math">, Group<f_Group>;
-def fno_trapping_math : Flag<"-fno-trapping-math">, Group<f_Group>;
-def ffp_contract : Joined<"-ffp-contract=">, Group<f_Group>,
+def fhonor_infinites : Flag<["-"], "fhonor-infinites">, Alias<fhonor_infinities>;
+def fno_honor_infinites : Flag<["-"], "fno-honor-infinites">, Alias<fno_honor_infinities>;
+def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>;
+def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>;
+def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
" | on (according to FP_CONTRACT pragma, default) | off (never fuse)">;
-def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>;
-def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>;
+def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
+def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
-def frewrite_includes : Flag<"-frewrite-includes">, Group<f_Group>,
+def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>,
Flags<[CC1Option]>;
-def fno_rewrite_includes : Flag<"-fno-rewrite-includes">, Group<f_Group>;
+def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>;
-def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
+def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
-def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
+def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Allow GNU-extension keywords regardless of language standard">;
-def fgnu89_inline : Flag<"-fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,
+def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use the gnu89 inline semantics">;
-def fno_gnu89_inline : Flag<"-fno-gnu89-inline">, Group<f_Group>;
-def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>,
+def fno_gnu89_inline : Flag<["-"], "fno-gnu89-inline">, Group<f_Group>;
+def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>,
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
-def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">, Flags<[CC1Option]>;
-def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
-def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Alias<fapple_kext>;
-def finline_functions : Flag<"-finline-functions">, Group<clang_ignored_f_Group>;
-def finline : Flag<"-finline">, Group<clang_ignored_f_Group>;
-def finstrument_functions : Flag<"-finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>,
+def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">, Flags<[CC1Option]>;
+def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>;
+def findirect_virtual_calls : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>;
+def finline_functions : Flag<["-"], "finline-functions">, Group<clang_ignored_f_Group>;
+def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>;
+def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Generate calls to instrument function entry and exit">;
-def fkeep_inline_functions : Flag<"-fkeep-inline-functions">, Group<clang_ignored_f_Group>;
-def flat__namespace : Flag<"-flat_namespace">;
-def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>;
-def flimit_debug_info : Flag<"-flimit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
+def fkeep_inline_functions : Flag<["-"], "fkeep-inline-functions">, Group<clang_ignored_f_Group>;
+def flat__namespace : Flag<["-"], "flat_namespace">;
+def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
+def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
-def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>;
-def flto : Flag<"-flto">, Group<f_Group>;
-def fno_lto : Flag<"-fno-lto">, Group<f_Group>;
-def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">,
+def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
+def flto : Flag<["-"], "flto">, Group<f_Group>;
+def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>;
+def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">,
Group<f_Group>;
-def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
-def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
-def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>, Flags<[CC1Option]>,
+def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>;
+def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>;
+def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">;
-def fenable_experimental_ms_inline_asm : Flag<"-fenable-experimental-ms-inline-asm">, Group<f_Group>, Flags<[CC1Option]>,
+def fenable_experimental_ms_inline_asm : Flag<["-"], "fenable-experimental-ms-inline-asm">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable support for Microsoft style inine assembly">;
-def fms_compatibility : Flag<"-fms-compatibility">, Group<f_Group>, Flags<[CC1Option]>,
+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]>,
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>,
+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 fmodule_cache_path : Separate<"-fmodule-cache-path">, Group<i_Group>,
+def fmodule_cache_path : Separate<["-"], "fmodule-cache-path">, Group<i_Group>,
Flags<[NoForward,CC1Option]>, MetaVarName<"<directory>">,
HelpText<"Specify the module cache path">;
-def fmodules : Flag <"-fmodules">, Group<f_Group>, Flags<[NoForward,CC1Option]>,
+def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, Flags<[NoForward,CC1Option]>,
HelpText<"Enable the 'modules' language feature">;
-
-def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
-def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
-def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
-def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>;
-def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>, Flags<[CC1Option]>,
+def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
+
+def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
+def fmudflap : Flag<["-"], "fmudflap">, Group<f_Group>;
+def fnested_functions : Flag<["-"], "fnested-functions">, Group<f_Group>;
+def fnext_runtime : Flag<["-"], "fnext-runtime">, Group<f_Group>;
+def fno_access_control : Flag<["-"], "fno-access-control">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable C++ access control">;
-def fno_apple_pragma_pack : Flag<"-fno-apple-pragma-pack">, Group<f_Group>;
-def fno_asm : Flag<"-fno-asm">, Group<f_Group>;
-def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>;
-def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>,
+def fno_apple_pragma_pack : Flag<["-"], "fno-apple-pragma-pack">, Group<f_Group>;
+def fno_asm : Flag<["-"], "fno-asm">, Group<f_Group>;
+def fno_asynchronous_unwind_tables : Flag<["-"], "fno-asynchronous-unwind-tables">, Group<f_Group>;
+def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, Group<f_Group>,
HelpText<"Don't assume that C++'s global operator new can't alias any pointer">,
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]>,
+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_caret_diagnostics : Flag<"-fno-caret-diagnostics">, Group<f_Group>,
+def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<f_Group>,
Flags<[CC1Option]>;
-def fno_color_diagnostics : Flag<"-fno-color-diagnostics">, Group<f_Group>;
-def fno_common : Flag<"-fno-common">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_color_diagnostics : Flag<["-"], "fno-color-diagnostics">, Group<f_Group>;
+def fno_common : Flag<["-"], "fno-common">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Compile common globals like normal definitions">;
-def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, Group<f_Group>,
+def fno_constant_cfstrings : Flag<["-"], "fno-constant-cfstrings">, Group<f_Group>,
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_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, Group<f_Group>,
+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_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">,
+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">;
-def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, 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>,
+def fno_elide_constructors : Flag<["-"], "fno-elide-constructors">, Group<f_Group>,
HelpText<"Disable C++ copy constructor elision">, Flags<[CC1Option]>;
-def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
-def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
-def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>, Flags<[CC1Option]>;
-def fno_inline_functions : Flag<"-fno-inline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>;
-def fno_inline : Flag<"-fno-inline">, Group<f_clang_Group>, Flags<[CC1Option]>;
-def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
-def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>,
+def fno_eliminate_unused_debug_symbols : Flag<["-"], "fno-eliminate-unused-debug-symbols">, Group<f_Group>;
+def fno_exceptions : Flag<["-"], "fno-exceptions">, Group<f_Group>;
+def fno_gnu_keywords : Flag<["-"], "fno-gnu-keywords">, Group<f_Group>, Flags<[CC1Option]>;
+def fno_inline_functions : Flag<["-"], "fno-inline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>;
+def fno_inline : Flag<["-"], "fno-inline">, Group<f_clang_Group>, Flags<[CC1Option]>;
+def fno_keep_inline_functions : Flag<["-"], "fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
+def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
-def fno_limit_debug_info : Flag<"-fno-limit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
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_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>;
-def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>;
-def fno_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group<f_Group>;
-def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group<f_Group>;
-def fno_operator_names : Flag<"-fno-operator-names">, Group<f_Group>,
+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_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>;
+def fno_objc_exceptions: Flag<["-"], "fno-objc-exceptions">, Group<f_Group>;
+def fno_objc_legacy_dispatch : Flag<["-"], "fno-objc-legacy-dispatch">, Group<f_Group>;
+def fno_omit_frame_pointer : Flag<["-"], "fno-omit-frame-pointer">, Group<f_Group>;
+def fno_operator_names : Flag<["-"], "fno-operator-names">, Group<f_Group>,
HelpText<"Do not treat C++ operator name keywords as synonyms for operators">,
Flags<[CC1Option]>;
-def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group<f_Group>;
-def fno_rtti : Flag<"-fno-rtti">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_pascal_strings : Flag<["-"], "fno-pascal-strings">, Group<f_Group>;
+def fno_rtti : Flag<["-"], "fno-rtti">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Disable generation of rtti information">;
-def fno_short_enums : Flag<"-fno-short-enums">, Group<f_Group>;
-def fno_show_column : Flag<"-fno-show-column">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_short_enums : Flag<["-"], "fno-short-enums">, Group<f_Group>;
+def fno_show_column : Flag<["-"], "fno-show-column">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Do not include column number on diagnostics">;
-def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>,
+def fno_show_source_location : Flag<["-"], "fno-show-source-location">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Do not include source location information with diagnostics">;
-def fno_spell_checking : Flag<"-fno-spell-checking">, Group<f_Group>,
+def fno_spell_checking : Flag<["-"], "fno-spell-checking">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Disable spell-checking">;
-def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
-def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, 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>,
+def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>;
+def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, 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>,
Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">;
-def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Don't use __cxa_atexit for calling destructors">;
-def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
-def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
-def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>;
-def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
-def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>;
-def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
-def fobjc_arc : Flag<"-fobjc-arc">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group<f_Group>;
+def fno_unwind_tables : Flag<["-"], "fno-unwind-tables">, Group<f_Group>;
+def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group<f_Group>;
+def fno_working_directory : Flag<["-"], "fno-working-directory">, Group<f_Group>;
+def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>;
+def fno_zero_initialized_in_bss : Flag<["-"], "fno-zero-initialized-in-bss">, Group<f_Group>;
+def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Synthesize retain and release calls for Objective-C pointers">;
-def fno_objc_arc : Flag<"-fno-objc-arc">, Group<f_Group>;
-def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_objc_arc : Flag<["-"], "fno-objc-arc">, Group<f_Group>;
+def fobjc_arc_exceptions : Flag<["-"], "fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">;
-def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>;
-def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
-def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
-def fobjc_exceptions: Flag<"-fobjc-exceptions">, Group<f_Group>,
+def fno_objc_arc_exceptions : Flag<["-"], "fno-objc-arc-exceptions">, Group<f_Group>;
+def fobjc_atdefs : Flag<["-"], "fobjc-atdefs">, Group<clang_ignored_f_Group>;
+def fobjc_call_cxx_cdtors : Flag<["-"], "fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
+def fobjc_exceptions: Flag<["-"], "fobjc-exceptions">, Group<f_Group>,
HelpText<"Enable Objective-C exceptions">, Flags<[CC1Option]>;
-def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>, Flags<[CC1Option]>,
+def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use GC exclusively for Objective-C related memory management">;
-def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>, Flags<[CC1Option]>,
+def fobjc_gc : Flag<["-"], "fobjc-gc">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Objective-C garbage collection">;
-def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
-def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
-def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
+def fobjc_legacy_dispatch : Flag<["-"], "fobjc-legacy-dispatch">, Group<f_Group>;
+def fobjc_new_property : Flag<["-"], "fobjc-new-property">, Group<clang_ignored_f_Group>;
+def fobjc_infer_related_result_type : Flag<["-"], "fobjc-infer-related-result-type">,
Group<f_Group>;
-def fno_objc_infer_related_result_type : Flag<
- "-fno-objc-infer-related-result-type">, Group<f_Group>,
+def fno_objc_infer_related_result_type : Flag<["-"],
+ "fno-objc-infer-related-result-type">, Group<f_Group>,
HelpText<
"do not infer Objective-C related result type based on method family">,
Flags<[CC1Option]>;
-def fobjc_link_runtime: Flag<"-fobjc-link-runtime">, Group<f_Group>;
+def fobjc_link_runtime: Flag<["-"], "fobjc-link-runtime">, Group<f_Group>;
// Objective-C ABI options.
-def fobjc_runtime_EQ : Joined<"-fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option]>,
+def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Specify the target Objective-C runtime kind and version">;
-def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;
-def fobjc_nonfragile_abi_version_EQ : Joined<"-fobjc-nonfragile-abi-version=">, Group<f_Group>;
-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_abi_version_EQ : Joined<["-"], "fobjc-abi-version=">, Group<f_Group>;
+def fobjc_nonfragile_abi_version_EQ : Joined<["-"], "fobjc-nonfragile-abi-version=">, Group<f_Group>;
+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>;
-def fno_optimize_sibling_calls : Flag<"-fno-optimize-sibling-calls">, Group<f_Group>;
-def foptimize_sibling_calls : Flag<"-foptimize-sibling-calls">, Group<f_Group>;
-def force__cpusubtype__ALL : Flag<"-force_cpusubtype_ALL">;
-def force__flat__namespace : Flag<"-force_flat_namespace">;
-def force__load : Separate<"-force_load">;
-def foutput_class_dir_EQ : Joined<"-foutput-class-dir=">, Group<f_Group>;
-def fpack_struct : Flag<"-fpack-struct">, Group<f_Group>;
-def fno_pack_struct : Flag<"-fno-pack-struct">, Group<f_Group>;
-def fpack_struct_EQ : Joined<"-fpack-struct=">, Group<f_Group>, Flags<[CC1Option]>,
+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>;
+def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
+def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
+def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
+def force__flat__namespace : Flag<["-"], "force_flat_namespace">;
+def force__load : Separate<["-"], "force_load">;
+def foutput_class_dir_EQ : Joined<["-"], "foutput-class-dir=">, Group<f_Group>;
+def fpack_struct : Flag<["-"], "fpack-struct">, Group<f_Group>;
+def fno_pack_struct : Flag<["-"], "fno-pack-struct">, Group<f_Group>;
+def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Specify the default maximum struct packing alignment">;
-def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
+def fpascal_strings : Flag<["-"], "fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Recognize and construct Pascal-style string literals">;
-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>;
-def fpie : Flag<"-fpie">, Group<f_Group>;
-def fno_pie : Flag<"-fno-pie">, Group<f_Group>;
-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 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]>,
+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>;
+def fpie : Flag<["-"], "fpie">, Group<f_Group>;
+def fno_pie : Flag<["-"], "fno-pie">, Group<f_Group>;
+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 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]>,
HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">;
-def freorder_blocks : Flag<"-freorder-blocks">, Group<clang_ignored_f_Group>;
-def fshort_wchar : Flag<"-fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>,
+def freorder_blocks : Flag<["-"], "freorder-blocks">, Group<clang_ignored_f_Group>;
+def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Force wchar_t to be a short unsigned int">;
-def fshow_overloads_EQ : Joined<"-fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>,
+def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Which overload candidates to show when overload resolution fails: "
"best|all; defaults to all">;
-def fshow_column : Flag<"-fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
-def fshow_source_location : Flag<"-fshow-source-location">, Group<f_Group>;
-def fspell_checking : Flag<"-fspell-checking">, Group<f_Group>;
-def fsigned_bitfields : Flag<"-fsigned-bitfields">, Group<f_Group>;
-def fsigned_char : Flag<"-fsigned-char">, Group<f_Group>;
-def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>;
-def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
-def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<f_Group>;
-def fstrict_enums : Flag<"-fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
+def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
+def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
+def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
+def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
+def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
+def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>;
+def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>;
+def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>;
+def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable optimizations based on the strict definition of an enum's "
- "value range.">;
-def fstrict_overflow : Flag<"-fstrict-overflow">, Group<f_Group>;
-def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
-def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
-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=">,
+ "value range">;
+def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>;
+def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
+def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group<f_Group>;
+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 ftest_coverage : Flag<"-ftest-coverage">, Group<f_Group>;
-def Wlarge_by_value_copy_def : Flag<"-Wlarge-by-value-copy">,
+def ftest_coverage : Flag<["-"], "ftest-coverage">, Group<f_Group>;
+def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">,
HelpText<"Warn if a function definition returns or accepts an object larger "
- "in bytes that a given value">;
-def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">, Flags<[CC1Option]>;
+ "in bytes than a given value">, Flags<[HelpHidden]>;
+def Wlarge_by_value_copy_EQ : Joined<["-"], "Wlarge-by-value-copy=">, Flags<[CC1Option]>;
// Just silence warnings about -Wlarger-than, -Wframe-larger-than for now.
-def Wlarger_than : Separate<"-Wlarger-than">, Group<clang_ignored_f_Group>;
-def Wlarger_than_EQ : Joined<"-Wlarger-than=">, Alias<Wlarger_than>;
-def Wlarger_than_ : Joined<"-Wlarger-than-">, Alias<Wlarger_than>;
-def Wframe_larger_than : Separate<"-Wframe-larger-than">, Group<clang_ignored_f_Group>;
-def Wframe_larger_than_EQ : Joined<"-Wframe-larger-than=">, Alias<Wframe_larger_than>;
+def Wlarger_than : Separate<["-"], "Wlarger-than">, Group<clang_ignored_f_Group>;
+def Wlarger_than_EQ : Joined<["-"], "Wlarger-than=">, Alias<Wlarger_than>;
+def Wlarger_than_ : Joined<["-"], "Wlarger-than-">, Alias<Wlarger_than>;
+def Wframe_larger_than : Separate<["-"], "Wframe-larger-than">, Group<clang_ignored_f_Group>;
+def Wframe_larger_than_EQ : Joined<["-"], "Wframe-larger-than=">, Alias<Wframe_larger_than>;
-def fterminated_vtables : Flag<"-fterminated-vtables">, Alias<fapple_kext>;
-def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>;
-def ftime_report : Flag<"-ftime-report">, Group<f_Group>, Flags<[CC1Option]>;
-def ftlsmodel_EQ : Joined<"-ftls-model=">, Group<f_Group>, Flags<[CC1Option]>;
-def ftrapv : Flag<"-ftrapv">, Group<f_Group>, Flags<[CC1Option]>,
+def fterminated_vtables : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>;
+def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>;
+def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>;
+def ftlsmodel_EQ : Joined<["-"], "ftls-model=">, Group<f_Group>, Flags<[CC1Option]>;
+def ftrapv : Flag<["-"], "ftrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Trap on integer overflow">;
-def ftrapv_handler_EQ : Joined<"-ftrapv-handler=">, Group<f_Group>,
+def ftrapv_handler_EQ : Joined<["-"], "ftrapv-handler=">, Group<f_Group>,
MetaVarName<"<function name>">,
- HelpText<"Specify the function to be called on overflow.">;
-def ftrapv_handler : Separate<"-ftrapv-handler">, Group<f_Group>, Flags<[CC1Option]>;
-def ftrap_function_EQ : Joined<"-ftrap-function=">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Specify the function to be called on overflow">;
+def ftrapv_handler : Separate<["-"], "ftrapv-handler">, Group<f_Group>, Flags<[CC1Option]>;
+def ftrap_function_EQ : Joined<["-"], "ftrap-function=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Issue call to specified function rather than a trap instruction">;
-def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
-def funroll_loops : Flag<"-funroll-loops">, Group<f_Group>,
+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 funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
-def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>;
-def funwind_tables : Flag<"-funwind-tables">, Group<f_Group>;
-def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group<f_Group>;
-def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>;
-def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>;
-def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, Group<f_Group>,
+def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
+def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
+def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
+def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
+def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
+def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>;
+def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
HelpText<"Give inline C++ member functions default visibility by default">,
Flags<[CC1Option]>;
-def fwrapv : Flag<"-fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
+def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
-def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
+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>,
+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]>,
+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 g_Flag : Flag<"-g">, Group<g_Group>,
+def f : Joined<["-"], "f">, Group<f_Group>;
+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>,
+def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<g_Group>,
HelpText<"Emit debug line number tables only">, Flags<[CC1Option]>;
-def g0 : Flag<"-g0">, Group<g_Group>;
-def g1 : Flag<"-g1">, Group<g_Group>;
-def g2 : Flag<"-g2">, Group<g_Group>;
-def g3 : Flag<"-g3">, Group<g_Group>;
-def ggdb : Flag<"-ggdb">, Group<g_Group>;
-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 gfull : Flag<"-gfull">, Group<g_Group>;
-def gused : Flag<"-gused">, Group<g_Group>;
-def gstabs : Joined<"-gstabs">, Group<g_Group>, Flags<[Unsupported]>;
-def gcoff : Joined<"-gcoff">, Group<g_Group>, Flags<[Unsupported]>;
-def gxcoff : Joined<"-gxcoff">, Group<g_Group>, Flags<[Unsupported]>;
-def gvms : Joined<"-gvms">, Group<g_Group>, Flags<[Unsupported]>;
-def gtoggle : Flag<"-gtoggle">, Group<g_flags_Group>, Flags<[Unsupported]>;
-def grecord_gcc_switches : Flag<"-grecord-gcc-switches">, Group<g_flags_Group>;
-def gno_record_gcc_switches : Flag<"-gno-record-gcc-switches">,
+def g0 : Flag<["-"], "g0">, Group<g_Group>;
+def g1 : Flag<["-"], "g1">, Group<g_Group>;
+def g2 : Flag<["-"], "g2">, Group<g_Group>;
+def g3 : Flag<["-"], "g3">, Group<g_Group>;
+def ggdb : Flag<["-"], "ggdb">, Group<g_Group>;
+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 gfull : Flag<["-"], "gfull">, Group<g_Group>;
+def gused : Flag<["-"], "gused">, Group<g_Group>;
+def gstabs : Joined<["-"], "gstabs">, Group<g_Group>, Flags<[Unsupported]>;
+def gcoff : Joined<["-"], "gcoff">, Group<g_Group>, Flags<[Unsupported]>;
+def gxcoff : Joined<["-"], "gxcoff">, Group<g_Group>, Flags<[Unsupported]>;
+def gvms : Joined<["-"], "gvms">, Group<g_Group>, Flags<[Unsupported]>;
+def gtoggle : Flag<["-"], "gtoggle">, Group<g_flags_Group>, Flags<[Unsupported]>;
+def grecord_gcc_switches : Flag<["-"], "grecord-gcc-switches">, Group<g_flags_Group>;
+def gno_record_gcc_switches : Flag<["-"], "gno-record-gcc-switches">,
Group<g_flags_Group>;
-def gstrict_dwarf : Flag<"-gstrict-dwarf">, Group<g_flags_Group>;
-def gno_strict_dwarf : Flag<"-gno-strict-dwarf">, Group<g_flags_Group>;
-def headerpad__max__install__names : Joined<"-headerpad_max_install_names">;
-def help : Flag<"-help">, Flags<[CC1Option]>,
+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 headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
+def help : Flag<["-", "--"], "help">, Flags<[CC1Option]>,
HelpText<"Display available options">;
-def index_header_map : Flag<"-index-header-map">, Flags<[CC1Option]>,
+def index_header_map : Flag<["-"], "index-header-map">, Flags<[CC1Option]>,
HelpText<"Make the next included directory (-I or -F) an indexer header map">;
-def idirafter : JoinedOrSeparate<"-idirafter">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to AFTER include search path">;
-def iframework : Joined<"-iframework">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to SYSTEM framework search path">;
-def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def imacros : JoinedOrSeparate<["-", "--"], "imacros">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Include macros from file before parsing">, MetaVarName<"<file>">;
-def image__base : Separate<"-image_base">;
-def include_ : JoinedOrSeparate<"-include">, Group<clang_i_Group>, EnumName<"include">,
+def image__base : Separate<["-"], "image_base">;
+def include_ : JoinedOrSeparate<["-", "--"], "include">, Group<clang_i_Group>, EnumName<"include">,
MetaVarName<"<file>">, HelpText<"Include file before parsing">, Flags<[CC1Option]>;
-def include_pch : Separate<"-include-pch">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def include_pch : Separate<["-"], "include-pch">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Include precompiled header file">, MetaVarName<"<file>">;
-def init : Separate<"-init">;
-def install__name : Separate<"-install_name">;
-def integrated_as : Flag<"-integrated-as">, Flags<[DriverOption]>;
-def iprefix : JoinedOrSeparate<"-iprefix">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def init : Separate<["-"], "init">;
+def install__name : Separate<["-"], "install_name">;
+def integrated_as : Flag<["-"], "integrated-as">, Flags<[DriverOption]>;
+def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">, MetaVarName<"<dir>">;
-def iquote : JoinedOrSeparate<"-iquote">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def iquote : JoinedOrSeparate<["-"], "iquote">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to QUOTE include search path">, MetaVarName<"<directory>">;
-def isysroot : JoinedOrSeparate<"-isysroot">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def isysroot : JoinedOrSeparate<["-"], "isysroot">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Set the system root directory (usually /)">, MetaVarName<"<dir>">;
-def isystem : JoinedOrSeparate<"-isystem">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def isystem : JoinedOrSeparate<["-"], "isystem">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to SYSTEM include search path">, MetaVarName<"<directory>">;
-def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, Group<clang_i_Group>,
+def iwithprefixbefore : JoinedOrSeparate<["-"], "iwithprefixbefore">, Group<clang_i_Group>,
HelpText<"Set directory to include search path with prefix">, MetaVarName<"<dir>">,
Flags<[CC1Option]>;
-def iwithprefix : JoinedOrSeparate<"-iwithprefix">, Group<clang_i_Group>, Flags<[CC1Option]>,
+def iwithprefix : JoinedOrSeparate<["-"], "iwithprefix">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Set directory to SYSTEM include search path with prefix">, MetaVarName<"<dir>">;
-def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<clang_i_Group>,
+def iwithsysroot : JoinedOrSeparate<["-"], "iwithsysroot">, Group<clang_i_Group>,
HelpText<"Add directory to SYSTEM include search path, "
"absolute paths are relative to -isysroot">, MetaVarName<"<directory>">,
Flags<[CC1Option]>;
-def i : Joined<"-i">, Group<i_Group>;
-def keep__private__externs : Flag<"-keep_private_externs">;
-def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput, RenderJoined]>;
-def lazy__framework : Separate<"-lazy_framework">, Flags<[LinkerInput]>;
-def lazy__library : Separate<"-lazy_library">, Flags<[LinkerInput]>;
-def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
-def mqdsp6_compat : Flag<"-mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>,
+def i : Joined<["-"], "i">, Group<i_Group>;
+def keep__private__externs : Flag<["-"], "keep_private_externs">;
+def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>;
+def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
+def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
+def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption]>;
+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 mabi_EQ : Joined<"-mabi=">, Group<m_Group>;
-def march_EQ : Joined<"-march=">, Group<m_Group>;
-def maltivec : Flag<"-maltivec">, Alias<faltivec>;
-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 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 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 mllvm : Separate<"-mllvm">, Flags<[CC1Option]>,
+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 mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>;
+def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
+def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
+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 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 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 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>;
-def mms_bitfields : Flag<"-mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">;
-def mstackrealign : Flag<"-mstackrealign">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"Force realign the stack at entry to every function.">;
-def mstack_alignment : Joined<"-mstack-alignment=">, Group<m_Group>, Flags<[CC1Option]>,
+def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">, Group<m_Group>;
+def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
+ HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
+def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Option]>,
+ 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 mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>;
-def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>;
-def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>;
-def mno_constant_cfstrings : Flag<"-mno-constant-cfstrings">, Group<m_Group>;
-def mno_global_merge : Flag<"-mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>,
+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>;
+def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
+def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Disable merging of globals">;
-def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>;
-def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>;
-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>;
-def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>;
-def mno_stackrealign : Flag<"-mno-stackrealign">, Group<m_Group>;
-def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>;
-def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>;
-def mno_sse4a : Flag<"-mno-sse4a">, Group<m_x86_Features_Group>;
-def mno_sse4 : Flag<"-mno-sse4">, Group<m_x86_Features_Group>;
-def mno_sse4_1 : Flag<"-mno-sse4.1">, Group<m_x86_Features_Group>;
-def mno_sse4_2 : Flag<"-mno-sse4.2">, Group<m_x86_Features_Group>;
-def mno_sse : Flag<"-mno-sse">, Group<m_x86_Features_Group>;
-def mno_ssse3 : Flag<"-mno-ssse3">, Group<m_x86_Features_Group>;
-def mno_aes : Flag<"-mno-aes">, Group<m_x86_Features_Group>;
-def mno_avx : Flag<"-mno-avx">, Group<m_x86_Features_Group>;
-def mno_avx2 : Flag<"-mno-avx2">, Group<m_x86_Features_Group>;
-def mno_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_fma4 : Flag<"-mno-fma4">, Group<m_x86_Features_Group>;
-def mno_fma : Flag<"-mno-fma">, Group<m_x86_Features_Group>;
-def mno_xop : Flag<"-mno-xop">, Group<m_x86_Features_Group>;
+def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>;
+def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">, Group<m_Group>;
+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>;
+def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>;
+def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>;
+def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>;
+def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>;
+def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>;
+def mno_sse4 : Flag<["-"], "mno-sse4">, Group<m_x86_Features_Group>;
+def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>;
+def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>;
+def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>;
+def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>;
+def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>;
+def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>;
+def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>;
+def mno_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_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>;
+def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>;
+def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>;
+def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
+def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>;
-def mno_thumb : Flag<"-mno-thumb">, Group<m_Group>;
-def marm : Flag<"-marm">, Alias<mno_thumb>;
+def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_Group>;
+def marm : Flag<["-"], "marm">, Alias<mno_thumb>;
-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<f_Group>;
-def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, Group<f_Group>,
- HelpText<"Omit frame pointer setup for leaf functions.">, Flags<[CC1Option]>;
-def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>;
-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]>,
+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 mpascal_strings : Flag<["-"], "mpascal-strings">, Group<m_Group>;
+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]>,
HelpText<"(integrated-as) Relax all machine instructions">;
-def mrtd : Flag<"-mrtd">, Group<m_Group>, Flags<[CC1Option]>,
+def mrtd : Flag<["-"], "mrtd">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Make StdCall calling convention the default">;
-def msmall_data_threshold_EQ : Joined <"-msmall-data-threshold=">, Group<m_Group>;
-def msoft_float : Flag<"-msoft-float">, Group<m_Group>, Flags<[CC1Option]>,
+def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">, Group<m_Group>;
+def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use software floating point">;
-def mno_implicit_float : Flag<"-mno-implicit-float">, Group<m_Group>,
+def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
HelpText<"Don't generate implicit floating point instructions">;
-def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>;
-def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>;
-def msse4a : Flag<"-msse4a">, Group<m_x86_Features_Group>;
-def msse4 : Flag<"-msse4">, Group<m_x86_Features_Group>;
-def msse4_1 : Flag<"-msse4.1">, Group<m_x86_Features_Group>;
-def msse4_2 : Flag<"-msse4.2">, Group<m_x86_Features_Group>;
-def msse : Flag<"-msse">, Group<m_x86_Features_Group>;
-def mssse3 : Flag<"-mssse3">, Group<m_x86_Features_Group>;
-def maes : Flag<"-maes">, Group<m_x86_Features_Group>;
-def mavx : Flag<"-mavx">, Group<m_x86_Features_Group>;
-def mavx2 : Flag<"-mavx2">, Group<m_x86_Features_Group>;
-def 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 mfma4 : Flag<"-mfma4">, Group<m_x86_Features_Group>;
-def mfma : Flag<"-mfma">, Group<m_x86_Features_Group>;
-def mxop : Flag<"-mxop">, Group<m_x86_Features_Group>;
-def mips16 : Flag<"-mips16">, Group<m_Group>;
-def mno_mips16 : Flag<"-mno-mips16">, 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 mthumb : Flag<"-mthumb">, Group<m_Group>;
-def mtune_EQ : Joined<"-mtune=">, Group<m_Group>;
-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]>,
+def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
+def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>;
+def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>;
+def msse4 : Flag<["-"], "msse4">, Group<m_x86_Features_Group>;
+def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>;
+def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>;
+def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>;
+def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>;
+def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>;
+def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>;
+def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>;
+def 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 mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>;
+def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
+def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>;
+def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
+def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
+def mips16 : Flag<["-"], "mips16">, Group<m_Group>;
+def mno_mips16 : Flag<["-"], "mno-mips16">, 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 mips32 : Flag<["-"], "mips32">, Group<mips_CPUs_Group>,
+ HelpText<"Equivalent to -march=mips32">, Flags<[HelpHidden]>;
+def mips32r2 : Flag<["-"], "mips32r2">, Group<mips_CPUs_Group>,
+ HelpText<"Equivalent to -march=mips32r2">, Flags<[HelpHidden]>;
+def mips64 : Flag<["-"], "mips64">, Group<mips_CPUs_Group>,
+ HelpText<"Equivalent to -march=mips64">, Flags<[HelpHidden]>;
+def mips64r2 : Flag<["-"], "mips64r2">, Group<mips_CPUs_Group>,
+ HelpText<"Equivalent to -march=mips64r2">, Flags<[HelpHidden]>;
+def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
+def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>;
+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>;
-def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>;
-def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>;
-def no_pedantic : Flag<"-no-pedantic">, Group<pedantic_Group>;
-def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">;
-def nobuiltininc : Flag<"-nobuiltininc">, Flags<[CC1Option]>,
+def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>;
+def no_integrated_as : Flag<["-"], "no-integrated-as">, Flags<[DriverOption]>;
+def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>;
+def no_pedantic : Flag<["-", "--"], "no-pedantic">, Group<pedantic_Group>;
+def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">;
+def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>,
HelpText<"Disable builtin #include directories">;
-def nodefaultlibs : Flag<"-nodefaultlibs">;
-def nofixprebinding : Flag<"-nofixprebinding">;
-def nolibc : Flag<"-nolibc">;
-def nomultidefs : Flag<"-nomultidefs">;
-def noprebind : Flag<"-noprebind">;
-def noseglinkedit : Flag<"-noseglinkedit">;
-def nostartfiles : Flag<"-nostartfiles">;
-def nostdinc : Flag<"-nostdinc">;
-def nostdlibinc : Flag<"-nostdlibinc">;
-def nostdincxx : Flag<"-nostdinc++">, Flags<[CC1Option]>,
+def nodefaultlibs : Flag<["-"], "nodefaultlibs">;
+def nofixprebinding : Flag<["-"], "nofixprebinding">;
+def nolibc : Flag<["-"], "nolibc">;
+def nomultidefs : Flag<["-"], "nomultidefs">;
+def noprebind : Flag<["-"], "noprebind">;
+def noseglinkedit : Flag<["-"], "noseglinkedit">;
+def nostartfiles : Flag<["-"], "nostartfiles">;
+def nostdinc : Flag<["-"], "nostdinc">;
+def nostdlibinc : Flag<["-"], "nostdlibinc">;
+def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>,
HelpText<"Disable standard #include directories for the C++ standard library">;
-def nostdlib : Flag<"-nostdlib">;
-def object : Flag<"-object">;
-def o : JoinedOrSeparate<"-o">, Flags<[DriverOption, RenderAsInput, CC1Option]>,
+def nostdlib : Flag<["-"], "nostdlib">;
+def object : Flag<["-"], "object">;
+def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option]>,
HelpText<"Write output to <file>">, MetaVarName<"<file>">;
-def pagezero__size : JoinedOrSeparate<"-pagezero_size">;
-def pass_exit_codes : Flag<"-pass-exit-codes">, Flags<[Unsupported]>;
-def pedantic_errors : Flag<"-pedantic-errors">, Group<pedantic_Group>, Flags<[CC1Option]>;
-def pedantic : Flag<"-pedantic">, Group<pedantic_Group>, Flags<[CC1Option]>;
-def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">, Flags<[CC1Option]>;
-def pipe : Flag<"-pipe">,
+def pagezero__size : JoinedOrSeparate<["-"], "pagezero_size">;
+def pass_exit_codes : Flag<["-", "--"], "pass-exit-codes">, Flags<[Unsupported]>;
+def pedantic_errors : Flag<["-", "--"], "pedantic-errors">, Group<pedantic_Group>, Flags<[CC1Option]>;
+def pedantic : Flag<["-", "--"], "pedantic">, Group<pedantic_Group>, Flags<[CC1Option]>;
+def pg : Flag<["-"], "pg">, HelpText<"Enable mcount instrumentation">, Flags<[CC1Option]>;
+def pipe : Flag<["-", "--"], "pipe">,
HelpText<"Use pipes between commands, when possible">;
-def prebind__all__twolevel__modules : Flag<"-prebind_all_twolevel_modules">;
-def prebind : Flag<"-prebind">;
-def preload : Flag<"-preload">;
-def print_file_name_EQ : Joined<"-print-file-name=">,
+def prebind__all__twolevel__modules : Flag<["-"], "prebind_all_twolevel_modules">;
+def prebind : Flag<["-"], "prebind">;
+def preload : Flag<["-"], "preload">;
+def print_file_name_EQ : Joined<["-", "--"], "print-file-name=">,
HelpText<"Print the full library path of <file>">, MetaVarName<"<file>">;
-def print_ivar_layout : Flag<"-print-ivar-layout">, Flags<[CC1Option]>,
+def print_ivar_layout : Flag<["-"], "print-ivar-layout">, Flags<[CC1Option]>,
HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
-def print_libgcc_file_name : Flag<"-print-libgcc-file-name">,
+def print_libgcc_file_name : Flag<["-", "--"], "print-libgcc-file-name">,
HelpText<"Print the library path for \"libgcc.a\"">;
-def print_multi_directory : Flag<"-print-multi-directory">;
-def print_multi_lib : Flag<"-print-multi-lib">;
-def print_multi_os_directory : Flag<"-print-multi-os-directory">;
-def print_prog_name_EQ : Joined<"-print-prog-name=">,
+def print_multi_directory : Flag<["-", "--"], "print-multi-directory">;
+def print_multi_lib : Flag<["-", "--"], "print-multi-lib">;
+def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">;
+def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">,
HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">;
-def print_search_dirs : Flag<"-print-search-dirs">,
+def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
HelpText<"Print the paths used for finding libraries and programs">;
-def private__bundle : Flag<"-private_bundle">;
-def pthreads : Flag<"-pthreads">;
-def pthread : Flag<"-pthread">, Flags<[CC1Option]>,
+def private__bundle : Flag<["-"], "private_bundle">;
+def pthreads : Flag<["-"], "pthreads">;
+def pthread : Flag<["-"], "pthread">, Flags<[CC1Option]>,
HelpText<"Support POSIX threads in generated code">;
-def p : Flag<"-p">;
-def pie : Flag<"-pie">;
-def read__only__relocs : Separate<"-read_only_relocs">;
-def remap : Flag<"-remap">;
-def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption,CC1Option]>,
+def p : Flag<["-"], "p">;
+def pie : Flag<["-"], "pie">;
+def read__only__relocs : Separate<["-"], "read_only_relocs">;
+def remap : Flag<["-"], "remap">;
+def rewrite_objc : Flag<["-"], "rewrite-objc">, Flags<[DriverOption,CC1Option]>,
HelpText<"Rewrite Objective-C source to C++">, Group<Action_Group>;
-def rewrite_legacy_objc : Flag<"-rewrite-legacy-objc">, Flags<[DriverOption]>,
+def rewrite_legacy_objc : Flag<["-"], "rewrite-legacy-objc">, Flags<[DriverOption]>,
HelpText<"Rewrite Legacy Objective-C source to C++">;
-def rdynamic : Flag<"-rdynamic">;
-def rpath : Separate<"-rpath">, Flags<[LinkerInput]>;
-def rtlib_EQ : Joined<"-rtlib=">;
-def r : Flag<"-r">;
-def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>,
+def rdynamic : Flag<["-"], "rdynamic">;
+def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>;
+def rtlib_EQ : Joined<["-", "--"], "rtlib=">;
+def r : Flag<["-"], "r">;
+def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>,
HelpText<"Save intermediate compilation results">;
-def sectalign : MultiArg<"-sectalign", 3>;
-def sectcreate : MultiArg<"-sectcreate", 3>;
-def sectobjectsymbols : MultiArg<"-sectobjectsymbols", 2>;
-def sectorder : MultiArg<"-sectorder", 3>;
-def seg1addr : JoinedOrSeparate<"-seg1addr">;
-def seg__addr__table__filename : Separate<"-seg_addr_table_filename">;
-def seg__addr__table : Separate<"-seg_addr_table">;
-def segaddr : MultiArg<"-segaddr", 2>;
-def segcreate : MultiArg<"-segcreate", 3>;
-def seglinkedit : Flag<"-seglinkedit">;
-def segprot : MultiArg<"-segprot", 3>;
-def segs__read__only__addr : Separate<"-segs_read_only_addr">;
-def segs__read__write__addr : Separate<"-segs_read_write_addr">;
-def segs__read__ : Joined<"-segs_read_">;
-def shared_libgcc : Flag<"-shared-libgcc">;
-def shared : Flag<"-shared">;
-def single__module : Flag<"-single_module">;
-def specs_EQ : Joined<"-specs=">;
-def specs : Separate<"-specs">, Flags<[Unsupported]>;
-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>,
+def sectalign : MultiArg<["-"], "sectalign", 3>;
+def sectcreate : MultiArg<["-"], "sectcreate", 3>;
+def sectobjectsymbols : MultiArg<["-"], "sectobjectsymbols", 2>;
+def sectorder : MultiArg<["-"], "sectorder", 3>;
+def seg1addr : JoinedOrSeparate<["-"], "seg1addr">;
+def seg__addr__table__filename : Separate<["-"], "seg_addr_table_filename">;
+def seg__addr__table : Separate<["-"], "seg_addr_table">;
+def segaddr : MultiArg<["-"], "segaddr", 2>;
+def segcreate : MultiArg<["-"], "segcreate", 3>;
+def seglinkedit : Flag<["-"], "seglinkedit">;
+def segprot : MultiArg<["-"], "segprot", 3>;
+def segs__read__only__addr : Separate<["-"], "segs_read_only_addr">;
+def segs__read__write__addr : Separate<["-"], "segs_read_write_addr">;
+def segs__read__ : Joined<["-"], "segs_read_">;
+def shared_libgcc : Flag<["-"], "shared-libgcc">;
+def shared : Flag<["-", "--"], "shared">;
+def single__module : Flag<["-"], "single_module">;
+def specs_EQ : Joined<["-", "--"], "specs=">;
+def specs : Separate<["-", "--"], "specs">, Flags<[Unsupported]>;
+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 stdlib_EQ : Joined<"-stdlib=">, Flags<[CC1Option]>,
+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 sub__library : JoinedOrSeparate<["-"], "sub_library">;
+def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">;
+def s : Flag<["-"], "s">;
+def target : Separate<["-"], "target">, Flags<[DriverOption]>,
HelpText<"Generate code for the given target">;
-def gcc_toolchain : Separate<"-gcc-toolchain">, Flags<[DriverOption]>,
+def gcc_toolchain : Separate<["-"], "gcc-toolchain">, Flags<[DriverOption]>,
HelpText<"Use the gcc toolchain at the given directory">;
-// We should deprecate the use of -ccc-host-triple, and then remove.
-def ccc_host_triple : Separate<"-ccc-host-triple">, Alias<target>;
-def time : Flag<"-time">,
+def time : Flag<["-"], "time">,
HelpText<"Time individual commands">;
-def traditional_cpp : Flag<"-traditional-cpp">, Flags<[CC1Option]>,
+def traditional_cpp : Flag<["-", "--"], "traditional-cpp">, Flags<[CC1Option]>,
HelpText<"Enable some traditional CPP emulation">;
-def traditional : Flag<"-traditional">;
-def trigraphs : Flag<"-trigraphs">, Flags<[CC1Option]>,
+def traditional : Flag<["-", "--"], "traditional">;
+def trigraphs : Flag<["-", "--"], "trigraphs">, Flags<[CC1Option]>,
HelpText<"Process trigraph sequences">;
-def twolevel__namespace__hints : Flag<"-twolevel_namespace_hints">;
-def twolevel__namespace : Flag<"-twolevel_namespace">;
-def t : Flag<"-t">;
-def umbrella : Separate<"-umbrella">;
-def undefined : JoinedOrSeparate<"-undefined">, Group<u_Group>;
-def undef : Flag<"-undef">, Group<u_Group>, Flags<[CC1Option]>,
+def twolevel__namespace__hints : Flag<["-"], "twolevel_namespace_hints">;
+def twolevel__namespace : Flag<["-"], "twolevel_namespace">;
+def t : Flag<["-"], "t">;
+def umbrella : Separate<["-"], "umbrella">;
+def undefined : JoinedOrSeparate<["-"], "undefined">, Group<u_Group>;
+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]>,
+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]>,
- HelpText<"Verify output using a verifier.">;
-def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>;
-def weak__framework : Separate<"-weak_framework">, Flags<[LinkerInput]>;
-def weak__library : Separate<"-weak_library">, Flags<[LinkerInput]>;
-def weak__reference__mismatches : Separate<"-weak_reference_mismatches">;
-def whatsloaded : Flag<"-whatsloaded">;
-def whyload : Flag<"-whyload">;
-def w : Flag<"-w">, HelpText<"Suppress all warnings.">, Flags<[CC1Option]>;
-def x : JoinedOrSeparate<"-x">, Flags<[DriverOption,CC1Option]>,
+def verify : Flag<["-"], "verify">, Flags<[DriverOption,CC1Option]>,
+ HelpText<"Verify output using a verifier">;
+def weak_l : Joined<["-"], "weak-l">, Flags<[LinkerInput]>;
+def weak__framework : Separate<["-"], "weak_framework">, Flags<[LinkerInput]>;
+def weak__library : Separate<["-"], "weak_library">, Flags<[LinkerInput]>;
+def weak__reference__mismatches : Separate<["-"], "weak_reference_mismatches">;
+def whatsloaded : Flag<["-"], "whatsloaded">;
+def whyload : Flag<["-"], "whyload">;
+def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">, Flags<[CC1Option]>;
+def x : JoinedOrSeparate<["-"], "x">, Flags<[DriverOption,CC1Option]>,
HelpText<"Treat subsequent input files as having type <language>">,
MetaVarName<"<language>">;
-def y : Joined<"-y">;
+def y : Joined<["-"], "y">;
-def working_directory : JoinedOrSeparate<"-working-directory">, Flags<[CC1Option]>,
+def working_directory : JoinedOrSeparate<["-"], "working-directory">, Flags<[CC1Option]>,
HelpText<"Resolve file paths relative to the specified directory">;
-def working_directory_EQ : Joined<"-working-directory=">, Flags<[CC1Option]>,
+def working_directory_EQ : Joined<["-"], "working-directory=">, Flags<[CC1Option]>,
Alias<working_directory>;
// Double dash options, which are usually an alias for one of the previous
// options.
-def _CLASSPATH_EQ : Joined<"--CLASSPATH=">, Alias<fclasspath_EQ>;
-def _CLASSPATH : Separate<"--CLASSPATH">, Alias<fclasspath_EQ>;
-def _all_warnings : Flag<"--all-warnings">, Alias<Wall>;
-def _analyze_auto : Flag<"--analyze-auto">, Flags<[DriverOption]>;
-def _analyzer_no_default_checks : Flag<"--analyzer-no-default-checks">, Flags<[DriverOption]>;
-def _analyzer_output : JoinedOrSeparate<"--analyzer-output">, Flags<[DriverOption]>;
-def _analyze : Flag<"--analyze">, Flags<[DriverOption]>,
+def _CLASSPATH_EQ : Joined<["--"], "CLASSPATH=">, Alias<fclasspath_EQ>;
+def _CLASSPATH : Separate<["--"], "CLASSPATH">, Alias<fclasspath_EQ>;
+def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>;
+def _analyze_auto : Flag<["--"], "analyze-auto">, Flags<[DriverOption]>;
+def _analyzer_no_default_checks : Flag<["--"], "analyzer-no-default-checks">, Flags<[DriverOption]>;
+def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>;
+def _analyze : Flag<["--"], "analyze">, Flags<[DriverOption]>,
HelpText<"Run the static analyzer">;
-def _ansi : Flag<"--ansi">, Alias<ansi>;
-def _assemble : Flag<"--assemble">, Alias<S>;
-def _assert_EQ : Joined<"--assert=">, Alias<A>;
-def _assert : Separate<"--assert">, Alias<A>;
-def _bootclasspath_EQ : Joined<"--bootclasspath=">, Alias<fbootclasspath_EQ>;
-def _bootclasspath : Separate<"--bootclasspath">, Alias<fbootclasspath_EQ>;
-def _classpath_EQ : Joined<"--classpath=">, Alias<fclasspath_EQ>;
-def _classpath : Separate<"--classpath">, Alias<fclasspath_EQ>;
-def _combine : Flag<"--combine">, Alias<combine>;
-def _comments_in_macros : Flag<"--comments-in-macros">, Alias<CC>;
-def _comments : Flag<"--comments">, Alias<C>;
-def _compile : Flag<"--compile">, Alias<c>;
-def _constant_cfstrings : Flag<"--constant-cfstrings">;
-def _coverage : Flag<"--coverage">, Alias<coverage>;
-def _debug_EQ : Joined<"--debug=">, Alias<g_Flag>;
-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 _encoding_EQ : Joined<"--encoding=">, Alias<fencoding_EQ>;
-def _encoding : Separate<"--encoding">, Alias<fencoding_EQ>;
-def _entry : Flag<"--entry">, Alias<e>;
-def _extdirs_EQ : Joined<"--extdirs=">, Alias<fextdirs_EQ>;
-def _extdirs : Separate<"--extdirs">, Alias<fextdirs_EQ>;
-def _extra_warnings : Flag<"--extra-warnings">, Alias<W_Joined>;
-def _for_linker_EQ : Joined<"--for-linker=">, Alias<Xlinker>;
-def _for_linker : Separate<"--for-linker">, Alias<Xlinker>;
-def _force_link_EQ : Joined<"--force-link=">, Alias<u>;
-def _force_link : Separate<"--force-link">, Alias<u>;
-def _help_hidden : Flag<"--help-hidden">;
-def _help : Flag<"--help">, Alias<help>;
-def _imacros_EQ : Joined<"--imacros=">, Alias<imacros>;
-def _imacros : Separate<"--imacros">, Alias<imacros>;
-def _include_barrier : Flag<"--include-barrier">, Alias<I_>;
-def _include_directory_after_EQ : Joined<"--include-directory-after=">, Alias<idirafter>;
-def _include_directory_after : Separate<"--include-directory-after">, Alias<idirafter>;
-def _include_directory_EQ : Joined<"--include-directory=">, Alias<I>;
-def _include_directory : Separate<"--include-directory">, Alias<I>;
-def _include_prefix_EQ : Joined<"--include-prefix=">, Alias<iprefix>;
-def _include_prefix : Separate<"--include-prefix">, Alias<iprefix>;
-def _include_with_prefix_after_EQ : Joined<"--include-with-prefix-after=">, Alias<iwithprefix>;
-def _include_with_prefix_after : Separate<"--include-with-prefix-after">, Alias<iwithprefix>;
-def _include_with_prefix_before_EQ : Joined<"--include-with-prefix-before=">, Alias<iwithprefixbefore>;
-def _include_with_prefix_before : Separate<"--include-with-prefix-before">, Alias<iwithprefixbefore>;
-def _include_with_prefix_EQ : Joined<"--include-with-prefix=">, Alias<iwithprefix>;
-def _include_with_prefix : Separate<"--include-with-prefix">, Alias<iwithprefix>;
-def _include_EQ : Joined<"--include=">, Alias<include_>;
-def _include : Separate<"--include">, Alias<include_>;
-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_integrated_cpp : Flag<"--no-integrated-cpp">, Alias<no_integrated_cpp>;
-def _no_line_commands : Flag<"--no-line-commands">, Alias<P>;
-def _no_pedantic : Flag<"--no-pedantic">, Alias<no_pedantic>;
-def _no_standard_includes : Flag<"--no-standard-includes">, Alias<nostdinc>;
-def _no_standard_libraries : Flag<"--no-standard-libraries">, Alias<nostdlib>;
-def _no_undefined : Flag<"--no-undefined">, Flags<[LinkerInput]>;
-def _no_warnings : Flag<"--no-warnings">, Alias<w>;
-def _optimize_EQ : Joined<"--optimize=">, Alias<O>;
-def _optimize : Flag<"--optimize">, Alias<O>;
-def _output_class_directory_EQ : Joined<"--output-class-directory=">, Alias<foutput_class_dir_EQ>;
-def _output_class_directory : Separate<"--output-class-directory">, Alias<foutput_class_dir_EQ>;
-def _output_EQ : Joined<"--output=">, Alias<o>;
-def _output : Separate<"--output">, Alias<o>;
-def _param : Separate<"--param">;
-def _param_EQ : Joined<"--param=">, Alias<_param>;
-def _pass_exit_codes : Flag<"--pass-exit-codes">, Alias<pass_exit_codes>;
-def _pedantic_errors : Flag<"--pedantic-errors">, Alias<pedantic_errors>;
-def _pedantic : Flag<"--pedantic">, Alias<pedantic>;
-def _pipe : Flag<"--pipe">, Alias<pipe>;
-def _prefix_EQ : Joined<"--prefix=">, Alias<B>;
-def _prefix : Separate<"--prefix">, Alias<B>;
-def _preprocess : Flag<"--preprocess">, Alias<E>;
-def _print_diagnostic_categories : Flag<"--print-diagnostic-categories">;
-def _print_file_name_EQ : Joined<"--print-file-name=">, Alias<print_file_name_EQ>;
-def _print_file_name : Separate<"--print-file-name">, Alias<print_file_name_EQ>;
-def _print_libgcc_file_name : Flag<"--print-libgcc-file-name">, Alias<print_libgcc_file_name>;
-def _print_missing_file_dependencies : Flag<"--print-missing-file-dependencies">, Alias<MG>;
-def _print_multi_directory : Flag<"--print-multi-directory">, Alias<print_multi_directory>;
-def _print_multi_lib : Flag<"--print-multi-lib">, Alias<print_multi_lib>;
-def _print_multi_os_directory : Flag<"--print-multi-os-directory">, Alias<print_multi_os_directory>;
-def _print_prog_name_EQ : Joined<"--print-prog-name=">, Alias<print_prog_name_EQ>;
-def _print_prog_name : Separate<"--print-prog-name">, Alias<print_prog_name_EQ>;
-def _print_search_dirs : Flag<"--print-search-dirs">, Alias<print_search_dirs>;
-def _profile_blocks : Flag<"--profile-blocks">, Alias<a>;
-def _profile : Flag<"--profile">, Alias<p>;
-def _relocatable_pch : Flag<"--relocatable-pch">,
- HelpText<"Build a relocatable precompiled header">;
-def _resource_EQ : Joined<"--resource=">, Alias<fcompile_resource_EQ>;
-def _resource : Separate<"--resource">, Alias<fcompile_resource_EQ>;
-def _rtlib_EQ : Joined<"--rtlib=">, Alias<rtlib_EQ>;
-def _rtlib : Separate<"--rtlib">, Alias<rtlib_EQ>;
-def _save_temps : Flag<"--save-temps">, Alias<save_temps>;
-def _serialize_diags : Separate<"--serialize-diagnostics">, Flags<[DriverOption]>,
+def _assemble : Flag<["--"], "assemble">, Alias<S>;
+def _assert_EQ : Joined<["--"], "assert=">, Alias<A>;
+def _assert : Separate<["--"], "assert">, Alias<A>;
+def _bootclasspath_EQ : Joined<["--"], "bootclasspath=">, Alias<fbootclasspath_EQ>;
+def _bootclasspath : Separate<["--"], "bootclasspath">, Alias<fbootclasspath_EQ>;
+def _classpath_EQ : Joined<["--"], "classpath=">, Alias<fclasspath_EQ>;
+def _classpath : Separate<["--"], "classpath">, Alias<fclasspath_EQ>;
+def _comments_in_macros : Flag<["--"], "comments-in-macros">, Alias<CC>;
+def _comments : Flag<["--"], "comments">, Alias<C>;
+def _compile : Flag<["--"], "compile">, Alias<c>;
+def _constant_cfstrings : Flag<["--"], "constant-cfstrings">;
+def _debug_EQ : Joined<["--"], "debug=">, Alias<g_Flag>;
+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 _encoding_EQ : Joined<["--"], "encoding=">, Alias<fencoding_EQ>;
+def _encoding : Separate<["--"], "encoding">, Alias<fencoding_EQ>;
+def _entry : Flag<["--"], "entry">, Alias<e>;
+def _extdirs_EQ : Joined<["--"], "extdirs=">, Alias<fextdirs_EQ>;
+def _extdirs : Separate<["--"], "extdirs">, Alias<fextdirs_EQ>;
+def _extra_warnings : Flag<["--"], "extra-warnings">, Alias<W_Joined>;
+def _for_linker_EQ : Joined<["--"], "for-linker=">, Alias<Xlinker>;
+def _for_linker : Separate<["--"], "for-linker">, Alias<Xlinker>;
+def _force_link_EQ : Joined<["--"], "force-link=">, Alias<u>;
+def _force_link : Separate<["--"], "force-link">, Alias<u>;
+def _help_hidden : Flag<["--"], "help-hidden">;
+def _imacros_EQ : Joined<["--"], "imacros=">, Alias<imacros>;
+def _include_barrier : Flag<["--"], "include-barrier">, Alias<I_>;
+def _include_directory_after_EQ : Joined<["--"], "include-directory-after=">, Alias<idirafter>;
+def _include_directory_after : Separate<["--"], "include-directory-after">, Alias<idirafter>;
+def _include_directory_EQ : Joined<["--"], "include-directory=">, Alias<I>;
+def _include_directory : Separate<["--"], "include-directory">, Alias<I>;
+def _include_prefix_EQ : Joined<["--"], "include-prefix=">, Alias<iprefix>;
+def _include_prefix : Separate<["--"], "include-prefix">, Alias<iprefix>;
+def _include_with_prefix_after_EQ : Joined<["--"], "include-with-prefix-after=">, Alias<iwithprefix>;
+def _include_with_prefix_after : Separate<["--"], "include-with-prefix-after">, Alias<iwithprefix>;
+def _include_with_prefix_before_EQ : Joined<["--"], "include-with-prefix-before=">, Alias<iwithprefixbefore>;
+def _include_with_prefix_before : Separate<["--"], "include-with-prefix-before">, Alias<iwithprefixbefore>;
+def _include_with_prefix_EQ : Joined<["--"], "include-with-prefix=">, Alias<iwithprefix>;
+def _include_with_prefix : Separate<["--"], "include-with-prefix">, Alias<iwithprefix>;
+def _include_EQ : Joined<["--"], "include=">, Alias<include_>;
+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>;
+def _no_undefined : Flag<["--"], "no-undefined">, Flags<[LinkerInput]>;
+def _no_warnings : Flag<["--"], "no-warnings">, Alias<w>;
+def _optimize_EQ : Joined<["--"], "optimize=">, Alias<O>;
+def _optimize : Flag<["--"], "optimize">, Alias<O>;
+def _output_class_directory_EQ : Joined<["--"], "output-class-directory=">, Alias<foutput_class_dir_EQ>;
+def _output_class_directory : Separate<["--"], "output-class-directory">, Alias<foutput_class_dir_EQ>;
+def _output_EQ : Joined<["--"], "output=">, Alias<o>;
+def _output : Separate<["--"], "output">, Alias<o>;
+def _param : Separate<["--"], "param">;
+def _param_EQ : Joined<["--"], "param=">, Alias<_param>;
+def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>;
+def _prefix : Separate<["--"], "prefix">, Alias<B>;
+def _preprocess : Flag<["--"], "preprocess">, Alias<E>;
+def _print_diagnostic_categories : Flag<["--"], "print-diagnostic-categories">;
+def _print_file_name : Separate<["--"], "print-file-name">, Alias<print_file_name_EQ>;
+def _print_missing_file_dependencies : Flag<["--"], "print-missing-file-dependencies">, Alias<MG>;
+def _print_prog_name : Separate<["--"], "print-prog-name">, Alias<print_prog_name_EQ>;
+def _profile_blocks : Flag<["--"], "profile-blocks">, Alias<a>;
+def _profile : Flag<["--"], "profile">, Alias<p>;
+def _resource_EQ : Joined<["--"], "resource=">, Alias<fcompile_resource_EQ>;
+def _resource : Separate<["--"], "resource">, Alias<fcompile_resource_EQ>;
+def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>;
+def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>,
HelpText<"Serialize compiler diagnostics to a file">;
-def _shared : Flag<"--shared">, Alias<shared>;
-def _signed_char : Flag<"--signed-char">, Alias<fsigned_char>;
-def _specs_EQ : Joined<"--specs=">, Alias<specs_EQ>;
-def _specs : Separate<"--specs">, Alias<specs_EQ>;
-def _static : Flag<"--static">, Alias<static>;
-def _std_EQ : Joined<"--std=">, Alias<std_EQ>;
-def _std : Separate<"--std">, Alias<std_EQ>;
-def _stdlib_EQ : Joined<"--stdlib=">, Alias<stdlib_EQ>;
-def _stdlib : Separate<"--stdlib">, Alias<stdlib_EQ>;
-def _sysroot_EQ : Joined<"--sysroot=">;
-def _sysroot : Separate<"--sysroot">, Alias<_sysroot_EQ>;
-def _target_help : Flag<"--target-help">;
-def _trace_includes : Flag<"--trace-includes">, Alias<H>;
-def _traditional_cpp : Flag<"--traditional-cpp">, Alias<traditional_cpp>;
-def _traditional : Flag<"--traditional">, Alias<traditional>;
-def _trigraphs : Flag<"--trigraphs">, Alias<trigraphs>;
-def _undefine_macro_EQ : Joined<"--undefine-macro=">, Alias<U>;
-def _undefine_macro : Separate<"--undefine-macro">, Alias<U>;
-def _unsigned_char : Flag<"--unsigned-char">, Alias<funsigned_char>;
-def _user_dependencies : Flag<"--user-dependencies">, Alias<MM>;
-def _verbose : Flag<"--verbose">, Alias<v>;
-def _version : Flag<"--version">, Flags<[CC1Option]>;
-def _warn__EQ : Joined<"--warn-=">, Alias<W_Joined>;
-def _warn_ : Joined<"--warn-">, Alias<W_Joined>;
-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 serialize_diags : Separate<"-serialize-diagnostics">, Alias<_serialize_diags>;
+// We give --version different semantics from -version.
+def _version : Flag<["--"], "version">, Flags<[CC1Option]>;
+def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>;
+def _std : Separate<["--"], "std">, Alias<std_EQ>;
+def _stdlib : Separate<["--"], "stdlib">, Alias<stdlib_EQ>;
+def _sysroot_EQ : Joined<["--"], "sysroot=">;
+def _sysroot : Separate<["--"], "sysroot">, Alias<_sysroot_EQ>;
+def _target_help : Flag<["--"], "target-help">;
+def _trace_includes : Flag<["--"], "trace-includes">, Alias<H>;
+def _undefine_macro_EQ : Joined<["--"], "undefine-macro=">, Alias<U>;
+def _undefine_macro : Separate<["--"], "undefine-macro">, Alias<U>;
+def _unsigned_char : Flag<["--"], "unsigned-char">, Alias<funsigned_char>;
+def _user_dependencies : Flag<["--"], "user-dependencies">, Alias<MM>;
+def _verbose : Flag<["--"], "verbose">, Alias<v>;
+def _warn__EQ : Joined<["--"], "warn-=">, Alias<W_Joined>;
+def _warn_ : Joined<["--"], "warn-">, Alias<W_Joined>;
+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>;
// Special internal option to handle -Xlinker --no-demangle.
-def Z_Xlinker__no_demangle : Flag<"-Z-Xlinker-no-demangle">,
+def Z_Xlinker__no_demangle : Flag<["-"], "Z-Xlinker-no-demangle">,
Flags<[Unsupported, NoArgumentUnused]>;
// Special internal option to allow forwarding arbitrary arguments to linker.
-def Zlinker_input : Separate<"-Zlinker-input">,
+def Zlinker_input : Separate<["-"], "Zlinker-input">,
Flags<[Unsupported, NoArgumentUnused]>;
// Reserved library options.
-def Z_reserved_lib_stdcxx : Flag<"-Z-reserved-lib-stdc++">,
+def Z_reserved_lib_stdcxx : Flag<["-"], "Z-reserved-lib-stdc++">,
Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>;
-def Z_reserved_lib_cckext : Flag<"-Z-reserved-lib-cckext">,
+def Z_reserved_lib_cckext : Flag<["-"], "Z-reserved-lib-cckext">,
Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>;
include "CC1Options.td"
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 8822d7b3fe24..c62e7567ea3e 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -55,8 +55,8 @@ public:
/// driver add an additional "command failed" diagnostic on failures.
virtual bool hasGoodDiagnostics() const { return false; }
- /// ConstructJob - Construct jobs to perform the action \arg JA,
- /// writing to \arg Output and with \arg Inputs.
+ /// ConstructJob - Construct jobs to perform the action \p JA,
+ /// writing to \p Output and with \p Inputs.
///
/// \param TCArgs - The argument list for this toolchain, with any
/// tool chain specific translations applied.
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index ab417bb577cb..509e08d67efc 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -85,6 +85,10 @@ public:
StringRef getPlatform() const { return Triple.getVendorName(); }
StringRef getOS() const { return Triple.getOSName(); }
+ /// \brief Provide the default architecture name (as expected by -arch) for
+ /// this toolchain. Note t
+ std::string getDefaultUniversalArchName() const;
+
std::string getTripleString() const {
return Triple.getTriple();
}
@@ -107,15 +111,15 @@ public:
return 0;
}
- /// SelectTool - Choose a tool to use to handle the action \arg JA with the
- /// given \arg Inputs.
+ /// SelectTool - Choose a tool to use to handle the action \p JA with the
+ /// given \p Inputs.
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const = 0;
// Helper methods
std::string GetFilePath(const char *Name) const;
- std::string GetProgramPath(const char *Name, bool WantFile = false) const;
+ std::string GetProgramPath(const char *Name) const;
// Platform defaults information
@@ -144,6 +148,10 @@ public:
/// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable
/// -fobjc-default-synthesize-properties by default.
virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; }
+
+ /// IsEncodeExtendedBlockSignatureDefault - Does this tool chain enable
+ /// -fencode-extended-block-signature by default.
+ virtual bool IsEncodeExtendedBlockSignatureDefault() const { return false; }
/// IsObjCNonFragileABIDefault - Does this tool chain set
/// -fobjc-nonfragile-abi by default.
@@ -166,16 +174,15 @@ public:
/// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
/// by default.
- virtual bool IsUnwindTablesDefault() const = 0;
+ virtual bool IsUnwindTablesDefault() const;
- /// GetDefaultRelocationModel - Return the LLVM name of the default
- /// relocation model for this tool chain.
- virtual const char *GetDefaultRelocationModel() const = 0;
+ /// \brief Test whether this toolchain defaults to PIC.
+ virtual bool isPICDefault() const = 0;
- /// GetForcedPicModel - Return the LLVM name of the forced PIC model
- /// for this tool chain, or 0 if this tool chain does not force a
- /// particular PIC mode.
- virtual const char *GetForcedPicModel() const = 0;
+ /// \brief Tests whether this toolchain forces its default for PIC or non-PIC.
+ /// If this returns true, any PIC related flags should be ignored and instead
+ /// the result of \c isPICDefault() is used exclusively.
+ virtual bool isPICDefaultForced() const = 0;
/// SupportsProfiling - Does this tool chain support -pg.
virtual bool SupportsProfiling() const { return true; }
@@ -183,8 +190,8 @@ public:
/// Does this tool chain support Objective-C garbage collection.
virtual bool SupportsObjCGC() const { return true; }
- /// Does this tool chain support Objective-C ARC.
- virtual bool SupportsObjCARC() const { return true; }
+ /// Complain if this tool chain doesn't support Objective-C ARC.
+ virtual void CheckObjCARC() const {}
/// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf
/// compile unit information.
@@ -252,6 +259,13 @@ public:
/// for kernel extensions (Darwin-specific).
virtual void AddCCKextLibArgs(const ArgList &Args,
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;
};
} // end namespace driver
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index 3dea471cca42..d28ca888d302 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -59,10 +59,6 @@ namespace types {
/// isAcceptedByClang - Can clang handle this input type.
bool isAcceptedByClang(ID Id);
- /// isOnlyAcceptedByClang - Is clang the only compiler that can handle this
- /// input type.
- bool isOnlyAcceptedByClang(ID Id);
-
/// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
bool isCXX(ID Id);
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 144b79642d5c..5e409bd7ed83 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -19,11 +19,13 @@
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang-c/Index.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
@@ -56,21 +58,27 @@ class Preprocessor;
class SourceManager;
class TargetInfo;
class ASTFrontendAction;
+class ASTDeserializationListener;
/// \brief Utility class for loading a ASTContext from an AST file.
///
class ASTUnit : public ModuleLoader {
private:
- IntrusiveRefCntPtr<LangOptions> LangOpts;
- IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
- IntrusiveRefCntPtr<FileManager> FileMgr;
- IntrusiveRefCntPtr<SourceManager> SourceMgr;
- OwningPtr<HeaderSearch> HeaderInfo;
- IntrusiveRefCntPtr<TargetInfo> Target;
- IntrusiveRefCntPtr<Preprocessor> PP;
- IntrusiveRefCntPtr<ASTContext> Ctx;
+ IntrusiveRefCntPtr<LangOptions> LangOpts;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ IntrusiveRefCntPtr<FileManager> FileMgr;
+ IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ OwningPtr<HeaderSearch> HeaderInfo;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+ IntrusiveRefCntPtr<Preprocessor> PP;
+ IntrusiveRefCntPtr<ASTContext> Ctx;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
+ IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
ASTReader *Reader;
+ struct ASTWriterData;
+ OwningPtr<ASTWriterData> WriterData;
+
FileSystemOptions FileSystemOpts;
/// \brief The AST consumer that received information about the translation
@@ -85,13 +93,6 @@ private:
/// LoadFromCommandLine available.
IntrusiveRefCntPtr<CompilerInvocation> Invocation;
- /// \brief The set of target features.
- ///
- /// FIXME: each time we reparse, we need to restore the set of target
- /// features from this vector, because TargetInfo::CreateTargetInfo()
- /// mangles the target options in place. Yuck!
- std::vector<std::string> TargetFeatures;
-
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.
@@ -374,8 +375,8 @@ private:
/// \brief Clear out and deallocate
void ClearCachedCompletionResults();
- ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT
- ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT
+ ASTUnit(const ASTUnit &) LLVM_DELETED_FUNCTION;
+ void operator=(const ASTUnit &) LLVM_DELETED_FUNCTION;
explicit ASTUnit(bool MainFileIsAST);
@@ -466,7 +467,11 @@ public:
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
- const std::string &getOriginalSourceFileName();
+ StringRef getOriginalSourceFileName() {
+ return OriginalSourceFile;
+ }
+
+ ASTDeserializationListener *getDeserializationListener();
/// \brief Add a temporary file that the ASTUnit depends on.
///
@@ -515,7 +520,7 @@ public:
void addFileLevelDecl(Decl *D);
/// \brief Get the decls that are contained in a file in the Offset/Length
- /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// range. \p Length can be 0 to indicate a point at \p Offset instead of
/// a range.
void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
SmallVectorImpl<Decl *> &Decls);
@@ -542,14 +547,14 @@ public:
/// \brief Get the source location for the given file:offset pair.
SourceLocation getLocation(const FileEntry *File, unsigned Offset) const;
- /// \brief If \arg Loc is a loaded location from the preamble, returns
+ /// \brief If \p Loc is a loaded location from the preamble, returns
/// the corresponding local location of the main file, otherwise it returns
- /// \arg Loc.
+ /// \p Loc.
SourceLocation mapLocationFromPreamble(SourceLocation Loc);
- /// \brief If \arg Loc is a local location of the main file but inside the
+ /// \brief If \p Loc is a local location of the main file but inside the
/// preamble chunk, returns the corresponding loaded location from the
- /// preamble, otherwise it returns \arg Loc.
+ /// preamble, otherwise it returns \p Loc.
SourceLocation mapLocationToPreamble(SourceLocation Loc);
bool isInPreambleFileID(SourceLocation Loc);
@@ -557,13 +562,13 @@ public:
SourceLocation getStartOfMainFileID();
SourceLocation getEndOfPreambleFileID();
- /// \brief \see mapLocationFromPreamble.
+ /// \see mapLocationFromPreamble.
SourceRange mapRangeFromPreamble(SourceRange R) {
return SourceRange(mapLocationFromPreamble(R.getBegin()),
mapLocationFromPreamble(R.getEnd()));
}
- /// \brief \see mapLocationToPreamble.
+ /// \see mapLocationToPreamble.
SourceRange mapRangeToPreamble(SourceRange R) {
return SourceRange(mapLocationToPreamble(R.getBegin()),
mapLocationToPreamble(R.getEnd()));
@@ -607,6 +612,29 @@ public:
return CachedCompletionResults.size();
}
+ /// \brief Returns an iterator range for the local preprocessing entities
+ /// of the local Preprocessor, if this is a parsed source file, or the loaded
+ /// preprocessing entities of the primary module if this is an AST file.
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ getLocalPreprocessingEntities() const;
+
+ /// \brief Type for a function iterating over a number of declarations.
+ /// \returns true to continue iteration and false to abort.
+ typedef bool (*DeclVisitorFn)(void *context, const Decl *D);
+
+ /// \brief Iterate over local declarations (locally parsed if this is a parsed
+ /// source file or the loaded declarations of the primary module if this is an
+ /// AST file).
+ /// \returns true if the iteration was complete or false if it was aborted.
+ bool visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn);
+
+ /// \brief Get the PCH file if one was included.
+ const FileEntry *getPCHFile();
+
+ /// \brief Returns true if the ASTUnit was constructed from a serialized
+ /// module file.
+ bool isModuleFile();
+
llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
std::string *ErrorStr = 0);
@@ -679,7 +707,7 @@ public:
/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
/// mainly to allow the caller to see the diagnostics.
/// This will only receive an ASTUnit if a new one was created. If an already
- /// created ASTUnit was passed in \param Unit then the caller can check that.
+ /// created ASTUnit was passed in \p Unit then the caller can check that.
///
static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
@@ -750,6 +778,7 @@ public:
bool AllowPCHWithCompilerErrors = false,
bool SkipFunctionBodies = false,
bool UserFilesAreVolatile = false,
+ bool ForSerialization = false,
OwningPtr<ASTUnit> *ErrAST = 0);
/// \brief Reparse the source files using the same command-line options that
@@ -792,8 +821,9 @@ public:
/// \brief Save this translation unit to a file with the given name.
///
- /// \returns An indication of whether the save was successful or not.
- CXSaveError Save(StringRef File);
+ /// \returns true if there was a file error or false if the save was
+ /// successful.
+ bool Save(StringRef File);
/// \brief Serialize this translation unit with the given output stream.
///
diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h
deleted file mode 100644
index 4e489fea7423..000000000000
--- a/include/clang/Frontend/AnalyzerOptions.h
+++ /dev/null
@@ -1,135 +0,0 @@
-//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This header contains the structures necessary for a front-end to specify
-// various analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_FRONTEND_ANALYZEROPTIONS_H
-#define LLVM_CLANG_FRONTEND_ANALYZEROPTIONS_H
-
-#include <string>
-#include <vector>
-
-namespace clang {
-class ASTConsumer;
-class DiagnosticsEngine;
-class Preprocessor;
-class LangOptions;
-
-/// Analysis - Set of available source code analyses.
-enum Analyses {
-#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
-#include "clang/Frontend/Analyses.def"
-NumAnalyses
-};
-
-/// AnalysisStores - Set of available analysis store models.
-enum AnalysisStores {
-#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
-#include "clang/Frontend/Analyses.def"
-NumStores
-};
-
-/// AnalysisConstraints - Set of available constraint models.
-enum AnalysisConstraints {
-#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
-#include "clang/Frontend/Analyses.def"
-NumConstraints
-};
-
-/// AnalysisDiagClients - Set of available diagnostic clients for rendering
-/// analysis results.
-enum AnalysisDiagClients {
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
-#include "clang/Frontend/Analyses.def"
-NUM_ANALYSIS_DIAG_CLIENTS
-};
-
-/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
-enum AnalysisPurgeMode {
-#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
-#include "clang/Frontend/Analyses.def"
-NumPurgeModes
-};
-
-/// AnalysisIPAMode - Set of inter-procedural modes.
-enum AnalysisIPAMode {
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
-#include "clang/Frontend/Analyses.def"
-NumIPAModes
-};
-
-/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
-enum AnalysisInliningMode {
-#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
-#include "clang/Frontend/Analyses.def"
-NumInliningModes
-};
-
-class AnalyzerOptions {
-public:
- /// \brief Pair of checker name and enable/disable.
- std::vector<std::pair<std::string, bool> > CheckersControlList;
- AnalysisStores AnalysisStoreOpt;
- AnalysisConstraints AnalysisConstraintsOpt;
- AnalysisDiagClients AnalysisDiagOpt;
- AnalysisPurgeMode AnalysisPurgeOpt;
- AnalysisIPAMode IPAMode;
- std::string AnalyzeSpecificFunction;
- unsigned MaxNodes;
- unsigned MaxLoop;
- unsigned ShowCheckerHelp : 1;
- unsigned AnalyzeAll : 1;
- unsigned AnalyzerDisplayProgress : 1;
- unsigned AnalyzeNestedBlocks : 1;
- unsigned EagerlyAssume : 1;
- unsigned TrimGraph : 1;
- unsigned VisualizeEGDot : 1;
- unsigned VisualizeEGUbi : 1;
- unsigned UnoptimizedCFG : 1;
- unsigned CFGAddImplicitDtors : 1;
- unsigned EagerlyTrimEGraph : 1;
- unsigned PrintStats : 1;
- unsigned NoRetryExhausted : 1;
- unsigned InlineMaxStackDepth;
- unsigned InlineMaxFunctionSize;
- AnalysisInliningMode InliningMode;
-
-public:
- AnalyzerOptions() {
- AnalysisStoreOpt = RegionStoreModel;
- AnalysisConstraintsOpt = RangeConstraintsModel;
- AnalysisDiagOpt = PD_HTML;
- AnalysisPurgeOpt = PurgeStmt;
- IPAMode = Inlining;
- ShowCheckerHelp = 0;
- AnalyzeAll = 0;
- AnalyzerDisplayProgress = 0;
- AnalyzeNestedBlocks = 0;
- EagerlyAssume = 0;
- TrimGraph = 0;
- VisualizeEGDot = 0;
- VisualizeEGUbi = 0;
- UnoptimizedCFG = 0;
- CFGAddImplicitDtors = 0;
- EagerlyTrimEGraph = 0;
- PrintStats = 0;
- NoRetryExhausted = 0;
- // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
- InlineMaxStackDepth = 5;
- InlineMaxFunctionSize = 200;
- InliningMode = NoRedundancy;
- }
-};
-
-}
-
-#endif
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
new file mode 100644
index 000000000000..558e6f11113b
--- /dev/null
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -0,0 +1,132 @@
+//===--- CodeGenOptions.def - Code generation option 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 code generation options. Users of this file
+// must define the CODEGENOPT macro to make use of this information.
+// Optionally, the user may also define ENUM_CODEGENOPT (for options
+// that have enumeration type and VALUE_CODEGENOPT is a code
+// generation option that describes a value rather than a flag.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CODEGENOPT
+# error Define the CODEGENOPT macro to handle language options
+#endif
+
+#ifndef VALUE_CODEGENOPT
+# define VALUE_CODEGENOPT(Name, Bits, Default) \
+CODEGENOPT(Name, Bits, Default)
+#endif
+
+#ifndef ENUM_CODEGENOPT
+# define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
+CODEGENOPT(Name, Bits, Default)
+#endif
+
+CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
+CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
+CODEGENOPT(CUDAIsDevice , 1, 0) ///< Set when compiling for CUDA device.
+CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors.
+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(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(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
+ ///< Decl* various IR entities came from.
+ ///< Only useful when running CodeGen as a
+ ///< subroutine.
+CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
+CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
+CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
+CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
+ ///< are required.
+CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled.
+CODEGENOPT(HiddenWeakVTables , 1, 0) ///< Emit weak vtables, RTTI, and thunks with
+ ///< hidden visibility.
+CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is
+ ///< enabled.
+CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
+CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to
+ ///< be generated.
+CODEGENOPT(MergeAllConstants , 1, 1) ///< Merge identical constants.
+CODEGENOPT(NoCommon , 1, 0) ///< Set when -fno-common or C++ is enabled.
+CODEGENOPT(NoDwarf2CFIAsm , 1, 0) ///< Set when -fno-dwarf2-cfi-asm is enabled.
+CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is
+ ///< enabled.
+CODEGENOPT(NoExecStack , 1, 0) ///< Set when -Wa,--noexecstack is enabled.
+CODEGENOPT(NoGlobalMerge , 1, 0) ///< Set when -mno-global-merge is enabled.
+CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
+CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
+CODEGENOPT(NoInline , 1, 0) ///< Set when -fno-inline is enabled.
+ ///< Disables use of the inline keyword.
+CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN.
+CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
+/// \brief Method of Objective-C dispatch to use.
+ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
+CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
+ ///< 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.
+CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
+CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
+CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
+CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
+CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
+CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
+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(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns.
+CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables.
+
+ /// Attempt to use register sized accesses to bit-fields in structures, when
+ /// possible.
+CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0)
+
+CODEGENOPT(VerifyModule , 1, 1) ///< Control whether the module should be run
+ ///< through the LLVM Verifier.
+
+CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to permit stack
+ ///< realignment.
+CODEGENOPT(UseInitArray , 1, 0) ///< Control whether to use .init_array or
+ ///< .ctors.
+VALUE_CODEGENOPT(StackAlignment , 32, 0) ///< Overrides default stack
+ ///< alignment, if not 0.
+CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information
+ ///< in debug info.
+
+/// The user specified number of registers to be used for integral arguments,
+/// or 0 if unspecified.
+VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)
+
+/// The run-time penalty for bounds checking, or 0 to disable.
+VALUE_CODEGENOPT(BoundsChecking, 8, 0)
+
+/// The lower bound for a buffer to be considered for stack protection.
+VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
+
+/// The kind of generated debug info.
+ENUM_CODEGENOPT(DebugInfo, DebugInfoKind, 2, NoDebugInfo)
+
+/// The kind of inlining to perform.
+ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining)
+
+/// The default TLS model to use.
+ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
+
+#undef CODEGENOPT
+#undef ENUM_CODEGENOPT
+#undef VALUE_CODEGENOPT
+
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 3e3409335208..35671870f441 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -19,9 +19,23 @@
namespace clang {
+/// \brief Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure
+/// that this large collection of bitfields is a trivial class type.
+class CodeGenOptionsBase {
+public:
+#define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits;
+#define ENUM_CODEGENOPT(Name, Type, Bits, Default)
+#include "clang/Frontend/CodeGenOptions.def"
+
+protected:
+#define CODEGENOPT(Name, Bits, Default)
+#define ENUM_CODEGENOPT(Name, Type, Bits, Default) unsigned Name : Bits;
+#include "clang/Frontend/CodeGenOptions.def"
+};
+
/// CodeGenOptions - Track various options which control how the code
/// is optimized and passed to the backend.
-class CodeGenOptions {
+class CodeGenOptions : public CodeGenOptionsBase {
public:
enum InliningMethod {
NoInlining, // Perform no inlining whatsoever.
@@ -51,86 +65,6 @@ public:
LocalExecTLSModel
};
- unsigned AsmVerbose : 1; ///< -dA, -fverbose-asm.
- unsigned ObjCAutoRefCountExceptions : 1; ///< Whether ARC should be EH-safe.
- unsigned CUDAIsDevice : 1; ///< Set when compiling for CUDA device.
- unsigned CXAAtExit : 1; ///< Use __cxa_atexit for calling destructors.
- unsigned CXXCtorDtorAliases: 1; ///< Emit complete ctors/dtors as linker
- ///< aliases to base ctors when possible.
- unsigned DataSections : 1; ///< Set when -fdata-sections is enabled.
- unsigned DisableFPElim : 1; ///< Set when -fomit-frame-pointer is enabled.
- unsigned DisableLLVMOpts : 1; ///< Don't run any optimizations, for use in
- ///< getting .bc files that correspond to the
- ///< internal state before optimizations are
- ///< done.
- unsigned DisableRedZone : 1; ///< Set when -mno-red-zone is enabled.
- unsigned DisableTailCalls : 1; ///< Do not emit tail calls.
- unsigned EmitDeclMetadata : 1; ///< Emit special metadata indicating what
- ///< Decl* various IR entities came from. Only
- ///< useful when running CodeGen as a
- ///< subroutine.
- unsigned EmitGcovArcs : 1; ///< Emit coverage data files, aka. GCDA.
- unsigned EmitGcovNotes : 1; ///< Emit coverage "notes" files, aka GCNO.
- unsigned EmitOpenCLArgMetadata : 1; ///< Emit OpenCL kernel arg metadata.
- unsigned EmitMicrosoftInlineAsm : 1; ///< Enable emission of MS-style inline
- ///< assembly.
- unsigned ForbidGuardVariables : 1; ///< Issue errors if C++ guard variables
- ///< are required.
- unsigned FunctionSections : 1; ///< Set when -ffunction-sections is enabled.
- unsigned HiddenWeakTemplateVTables : 1; ///< Emit weak vtables and RTTI for
- ///< template classes with hidden visibility
- unsigned HiddenWeakVTables : 1; ///< Emit weak vtables, RTTI, and thunks with
- ///< hidden visibility.
- unsigned InstrumentFunctions : 1; ///< Set when -finstrument-functions is
- ///< enabled.
- unsigned InstrumentForProfiling : 1; ///< Set when -pg is enabled.
- unsigned LessPreciseFPMAD : 1; ///< Enable less precise MAD instructions to
- ///< be generated.
- unsigned MergeAllConstants : 1; ///< Merge identical constants.
- unsigned NoCommon : 1; ///< Set when -fno-common or C++ is enabled.
- unsigned NoDwarf2CFIAsm : 1; ///< Set when -fno-dwarf2-cfi-asm is enabled.
- unsigned NoDwarfDirectoryAsm : 1; ///< Set when -fno-dwarf-directory-asm is
- ///< enabled.
- unsigned NoExecStack : 1; ///< Set when -Wa,--noexecstack is enabled.
- unsigned NoGlobalMerge : 1; ///< Set when -mno-global-merge is enabled.
- unsigned NoImplicitFloat : 1; ///< Set when -mno-implicit-float is enabled.
- unsigned NoInfsFPMath : 1; ///< Assume FP arguments, results not +-Inf.
- unsigned NoInline : 1; ///< Set when -fno-inline is enabled. Disables
- ///< use of the inline keyword.
- unsigned NoNaNsFPMath : 1; ///< Assume FP arguments, results not NaN.
- unsigned NoZeroInitializedInBSS : 1; ///< -fno-zero-initialized-in-bss.
- unsigned ObjCDispatchMethod : 2; ///< Method of Objective-C dispatch to use.
- unsigned OmitLeafFramePointer : 1; ///< Set when -momit-leaf-frame-pointer is
- ///< enabled.
- unsigned OptimizationLevel : 3; ///< The -O[0-4] option specified.
- unsigned OptimizeSize : 2; ///< If -Os (==1) or -Oz (==2) is specified.
- unsigned RelaxAll : 1; ///< Relax all machine code instructions.
- unsigned RelaxedAliasing : 1; ///< Set when -fno-strict-aliasing is enabled.
- unsigned SaveTempLabels : 1; ///< Save temporary labels.
- unsigned SimplifyLibCalls : 1; ///< Set when -fbuiltin is enabled.
- unsigned SoftFloat : 1; ///< -soft-float.
- unsigned StrictEnums : 1; ///< Optimize based on strict enum definition.
- unsigned TimePasses : 1; ///< Set when -ftime-report is enabled.
- unsigned UnitAtATime : 1; ///< Unused. For mirroring GCC optimization
- ///< selection.
- unsigned UnrollLoops : 1; ///< Control whether loops are unrolled.
- unsigned UnsafeFPMath : 1; ///< Allow unsafe floating point optzns.
- unsigned UnwindTables : 1; ///< Emit unwind tables.
-
- /// Attempt to use register sized accesses to bit-fields in structures, when
- /// possible.
- unsigned UseRegisterSizedBitfieldAccess : 1;
-
- unsigned VerifyModule : 1; ///< Control whether the module should be run
- ///< through the LLVM Verifier.
-
- unsigned StackRealignment : 1; ///< Control whether to permit stack
- ///< realignment.
- unsigned UseInitArray : 1; ///< Control whether to use .init_array or
- ///< .ctors.
- unsigned StackAlignment; ///< Overrides default stack alignment,
- ///< if not 0.
-
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -144,9 +78,6 @@ public:
/// The string to embed in debug information as the current working directory.
std::string DebugCompilationDir;
- /// The kind of generated debug info.
- DebugInfoKind DebugInfo;
-
/// The string to embed in the debug information for the compile unit, if
/// non-empty.
std::string DwarfDebugFlags;
@@ -160,9 +91,6 @@ public:
/// The name of the bitcode file to link before optzns.
std::string LinkBitcodeFile;
- /// The kind of inlining to perform.
- InliningMethod Inlining;
-
/// The user provided name for the "main file", if non-empty. This is useful
/// in situations where the input file name does not match the original input
/// file, for example with -save-temps.
@@ -178,79 +106,21 @@ public:
/// A list of command-line options to forward to the LLVM backend.
std::vector<std::string> BackendOptions;
- /// The user specified number of registers to be used for integral arguments,
- /// or 0 if unspecified.
- unsigned NumRegisterParameters;
-
- /// The run-time penalty for bounds checking, or 0 to disable.
- unsigned char BoundsChecking;
-
- /// The default TLS model to use.
- TLSModel DefaultTLSModel;
-
public:
+ // Define accessors/mutators for code generation options of enumeration type.
+#define CODEGENOPT(Name, Bits, Default)
+#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
+ Type get##Name() const { return static_cast<Type>(Name); } \
+ void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }
+#include "clang/Frontend/CodeGenOptions.def"
+
CodeGenOptions() {
- AsmVerbose = 0;
- CUDAIsDevice = 0;
- CXAAtExit = 1;
- CXXCtorDtorAliases = 0;
- DataSections = 0;
- DisableFPElim = 0;
- DisableLLVMOpts = 0;
- DisableRedZone = 0;
- DisableTailCalls = 0;
- EmitDeclMetadata = 0;
- EmitGcovArcs = 0;
- EmitGcovNotes = 0;
- EmitOpenCLArgMetadata = 0;
- EmitMicrosoftInlineAsm = 0;
- ForbidGuardVariables = 0;
- FunctionSections = 0;
- HiddenWeakTemplateVTables = 0;
- HiddenWeakVTables = 0;
- InstrumentFunctions = 0;
- InstrumentForProfiling = 0;
- LessPreciseFPMAD = 0;
- MergeAllConstants = 1;
- NoCommon = 0;
- NoDwarf2CFIAsm = 0;
- NoImplicitFloat = 0;
- NoInfsFPMath = 0;
- NoInline = 0;
- NoNaNsFPMath = 0;
- NoZeroInitializedInBSS = 0;
- NumRegisterParameters = 0;
- ObjCAutoRefCountExceptions = 0;
- ObjCDispatchMethod = Legacy;
- OmitLeafFramePointer = 0;
- OptimizationLevel = 0;
- OptimizeSize = 0;
- RelaxAll = 0;
- RelaxedAliasing = 0;
- SaveTempLabels = 0;
- SimplifyLibCalls = 1;
- SoftFloat = 0;
- StrictEnums = 0;
- TimePasses = 0;
- UnitAtATime = 1;
- UnrollLoops = 0;
- UnsafeFPMath = 0;
- UnwindTables = 0;
- UseRegisterSizedBitfieldAccess = 0;
- VerifyModule = 1;
- StackRealignment = 0;
- StackAlignment = 0;
- BoundsChecking = 0;
- UseInitArray = 0;
+#define CODEGENOPT(Name, Bits, Default) Name = Default;
+#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
+ set##Name(Default);
+#include "clang/Frontend/CodeGenOptions.def"
- DebugInfo = NoDebugInfo;
- Inlining = NoInlining;
RelocationModel = "pic";
- DefaultTLSModel = GeneralDynamicTLSModel;
- }
-
- ObjCDispatchMethodKind getObjCDispatchMethod() const {
- return ObjCDispatchMethodKind(ObjCDispatchMethod);
}
};
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index b28e1031b835..2f3dc3f80847 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/ArrayRef.h"
@@ -130,8 +131,8 @@ class CompilerInstance : public ModuleLoader {
/// The list of active output files.
std::list<OutputFile> OutputFiles;
- void operator=(const CompilerInstance &); // DO NOT IMPLEMENT
- CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT
+ CompilerInstance(const CompilerInstance &) LLVM_DELETED_FUNCTION;
+ void operator=(const CompilerInstance &) LLVM_DELETED_FUNCTION;
public:
CompilerInstance();
~CompilerInstance();
@@ -189,10 +190,7 @@ public:
/// @name Forwarding Methods
/// {
- AnalyzerOptions &getAnalyzerOpts() {
- return Invocation->getAnalyzerOpts();
- }
- const AnalyzerOptions &getAnalyzerOpts() const {
+ AnalyzerOptionsRef getAnalyzerOpts() {
return Invocation->getAnalyzerOpts();
}
@@ -393,7 +391,7 @@ public:
ASTConsumer *takeASTConsumer() { return Consumer.take(); }
/// setASTConsumer - Replace the current AST consumer; the compiler instance
- /// takes ownership of \arg Value.
+ /// takes ownership of \p Value.
void setASTConsumer(ASTConsumer *Value);
/// }
@@ -433,7 +431,7 @@ public:
}
/// setCodeCompletionConsumer - Replace the current code completion consumer;
- /// the compiler instance takes ownership of \arg Value.
+ /// the compiler instance takes ownership of \p Value.
void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
/// }
@@ -488,7 +486,7 @@ public:
/// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
///
- /// The \arg Argc and \arg Argv arguments are used only for logging purposes,
+ /// The \p Argc and \p Argv arguments are used only for logging purposes,
/// when the diagnostic options indicate that the compiler should output
/// logging information.
///
@@ -498,8 +496,7 @@ public:
/// releasing the returned DiagnosticsEngine's client eventually.
///
/// \param Opts - The diagnostic options; note that the created text
- /// diagnostic object contains a reference to these options and its lifetime
- /// must extend past that of the diagnostic engine.
+ /// diagnostic object contains a reference to these options.
///
/// \param Client If non-NULL, a diagnostic client that will be
/// attached to (and, then, owned by) the returned DiagnosticsEngine
@@ -510,7 +507,7 @@ public:
///
/// \return The new object on success, or null on failure.
static IntrusiveRefCntPtr<DiagnosticsEngine>
- createDiagnostics(const DiagnosticOptions &Opts, int Argc,
+ createDiagnostics(DiagnosticOptions *Opts, int Argc,
const char* const *Argv,
DiagnosticConsumer *Client = 0,
bool ShouldOwnClient = true,
@@ -534,7 +531,6 @@ public:
/// context.
void createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
void *DeserializationListener);
@@ -544,7 +540,6 @@ public:
static ExternalASTSource *
createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
Preprocessor &PP, ASTContext &Context,
void *DeserializationListener, bool Preamble);
@@ -555,8 +550,7 @@ public:
void createCodeCompletionConsumer();
/// Create a code completion consumer to print code completion results, at
- /// \arg Filename, \arg Line, and \arg Column, to the given output stream \arg
- /// OS.
+ /// \p Filename, \p Line, and \p Column, to the given output stream \p OS.
static CodeCompleteConsumer *
createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename,
unsigned Line, unsigned Column,
@@ -596,15 +590,15 @@ public:
/// Create a new output file, optionally deriving the output path name.
///
- /// If \arg OutputPath is empty, then createOutputFile will derive an output
- /// path location as \arg BaseInput, with any suffix removed, and \arg
- /// Extension appended. If OutputPath is not stdout and \arg UseTemporary
+ /// If \p OutputPath is empty, then createOutputFile will derive an output
+ /// path location as \p BaseInput, with any suffix removed, and \p Extension
+ /// appended. If \p OutputPath is not stdout and \p UseTemporary
/// is true, createOutputFile will create a new temporary file that must be
- /// renamed to OutputPath in the end.
+ /// renamed to \p OutputPath in the end.
///
/// \param OutputPath - If given, the path to the output file.
/// \param Error [out] - On failure, the error message.
- /// \param BaseInput - If \arg OutputPath is empty, the input path name to use
+ /// \param BaseInput - If \p OutputPath is empty, the input path name to use
/// for deriving the output path.
/// \param Extension - The extension to use for derived output names.
/// \param Binary - The mode to open the file in.
@@ -613,7 +607,7 @@ public:
/// multithreaded use, as the underlying signal mechanism is not reentrant
/// \param UseTemporary - Create a new temporary file that must be renamed to
/// OutputPath in the end.
- /// \param CreateMissingDirectories - When \arg UseTemporary is true, create
+ /// \param CreateMissingDirectories - When \p UseTemporary is true, create
/// missing directories in the output path.
/// \param ResultPathName [out] - If given, the result path name will be
/// stored here on success.
@@ -637,15 +631,13 @@ public:
/// as the main file.
///
/// \return True on success.
- bool InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind = SrcMgr::C_User);
+ bool InitializeSourceManager(const FrontendInputFile &Input);
/// InitializeSourceManager - Initialize the source manager to set InputFile
/// as the main file.
///
/// \return True on success.
- static bool InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind,
+ static bool InitializeSourceManager(const FrontendInputFile &Input,
DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index d6fe003da0fd..1314956c3f47 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -13,15 +13,15 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/DependencyOutputOptions.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Frontend/HeaderSearchOptions.h"
#include "clang/Frontend/LangStandard.h"
-#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
@@ -52,6 +52,19 @@ class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> {
protected:
/// Options controlling the language variant.
IntrusiveRefCntPtr<LangOptions> LangOpts;
+
+ /// Options controlling the target.
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
+
+ /// Options controlling the diagnostic engine.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
+
+ /// Options controlling the \#include directive.
+ IntrusiveRefCntPtr<HeaderSearchOptions> HeaderSearchOpts;
+
+ /// Options controlling the preprocessor (aside from \#include handling).
+ IntrusiveRefCntPtr<PreprocessorOptions> PreprocessorOpts;
+
public:
CompilerInvocationBase();
@@ -59,6 +72,23 @@ public:
LangOptions *getLangOpts() { return LangOpts.getPtr(); }
const LangOptions *getLangOpts() const { return LangOpts.getPtr(); }
+
+ TargetOptions &getTargetOpts() { return *TargetOpts.getPtr(); }
+ const TargetOptions &getTargetOpts() const {
+ return *TargetOpts.getPtr();
+ }
+
+ DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; }
+
+ HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; }
+ const HeaderSearchOptions &getHeaderSearchOpts() const {
+ return *HeaderSearchOpts;
+ }
+
+ PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; }
+ const PreprocessorOptions &getPreprocessorOpts() const {
+ return *PreprocessorOpts;
+ }
};
/// \brief Helper class for holding the data necessary to invoke the compiler.
@@ -68,7 +98,7 @@ public:
/// options, the warning flags, and so on.
class CompilerInvocation : public CompilerInvocationBase {
/// Options controlling the static analyzer.
- AnalyzerOptions AnalyzerOpts;
+ AnalyzerOptionsRef AnalyzerOpts;
MigratorOptions MigratorOpts;
@@ -78,29 +108,17 @@ class CompilerInvocation : public CompilerInvocationBase {
/// Options controlling dependency output.
DependencyOutputOptions DependencyOutputOpts;
- /// Options controlling the diagnostic engine.
- DiagnosticOptions DiagnosticOpts;
-
/// Options controlling file system operations.
FileSystemOptions FileSystemOpts;
/// Options controlling the frontend itself.
FrontendOptions FrontendOpts;
- /// Options controlling the \#include directive.
- HeaderSearchOptions HeaderSearchOpts;
-
- /// Options controlling the preprocessor (aside from \#include handling).
- PreprocessorOptions PreprocessorOpts;
-
/// Options controlling preprocessed output.
PreprocessorOutputOptions PreprocessorOutputOpts;
- /// Options controlling the target.
- TargetOptions TargetOpts;
-
public:
- CompilerInvocation() {}
+ CompilerInvocation() : AnalyzerOpts(new AnalyzerOptions()) {}
/// @name Utility Methods
/// @{
@@ -127,10 +145,6 @@ public:
/// executable), for finding the builtin compiler path.
static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
- /// \brief Convert the CompilerInvocation to a list of strings suitable for
- /// passing to CreateFromArgs.
- void toArgs(std::vector<std::string> &Res) const;
-
/// \brief Set language defaults for the given input language and
/// language standard in the given LangOptions object.
///
@@ -148,8 +162,7 @@ public:
/// @name Option Subgroups
/// @{
- AnalyzerOptions &getAnalyzerOpts() { return AnalyzerOpts; }
- const AnalyzerOptions &getAnalyzerOpts() const {
+ AnalyzerOptionsRef getAnalyzerOpts() const {
return AnalyzerOpts;
}
@@ -170,29 +183,16 @@ public:
return DependencyOutputOpts;
}
- DiagnosticOptions &getDiagnosticOpts() { return DiagnosticOpts; }
- const DiagnosticOptions &getDiagnosticOpts() const { return DiagnosticOpts; }
-
FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
const FileSystemOptions &getFileSystemOpts() const {
return FileSystemOpts;
}
- HeaderSearchOptions &getHeaderSearchOpts() { return HeaderSearchOpts; }
- const HeaderSearchOptions &getHeaderSearchOpts() const {
- return HeaderSearchOpts;
- }
-
FrontendOptions &getFrontendOpts() { return FrontendOpts; }
const FrontendOptions &getFrontendOpts() const {
return FrontendOpts;
}
- PreprocessorOptions &getPreprocessorOpts() { return PreprocessorOpts; }
- const PreprocessorOptions &getPreprocessorOpts() const {
- return PreprocessorOpts;
- }
-
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return PreprocessorOutputOpts;
}
@@ -200,11 +200,6 @@ public:
return PreprocessorOutputOpts;
}
- TargetOptions &getTargetOpts() { return TargetOpts; }
- const TargetOptions &getTargetOpts() const {
- return TargetOpts;
- }
-
/// @}
};
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
deleted file mode 100644
index 8dec37ca0311..000000000000
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ /dev/null
@@ -1,111 +0,0 @@
-//===--- DiagnosticOptions.h ------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICOPTIONS_H
-#define LLVM_CLANG_FRONTEND_DIAGNOSTICOPTIONS_H
-
-#include "clang/Basic/Diagnostic.h"
-
-#include <string>
-#include <vector>
-
-namespace clang {
-
-/// DiagnosticOptions - Options for controlling the compiler diagnostics
-/// engine.
-class DiagnosticOptions {
-public:
- unsigned IgnoreWarnings : 1; /// -w
- unsigned NoRewriteMacros : 1; /// -Wno-rewrite-macros
- unsigned Pedantic : 1; /// -pedantic
- unsigned PedanticErrors : 1; /// -pedantic-errors
- unsigned ShowColumn : 1; /// Show column number on diagnostics.
- unsigned ShowLocation : 1; /// Show source location information.
- unsigned ShowCarets : 1; /// Show carets in diagnostics.
- unsigned ShowFixits : 1; /// Show fixit information.
- unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form.
- unsigned ShowParseableFixits : 1; /// Show machine parseable fix-its.
- unsigned ShowOptionNames : 1; /// Show the option name for mappable
- /// diagnostics.
- unsigned ShowNoteIncludeStack : 1; /// Show include stacks for notes.
- unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number,
- /// 2 -> Full Name.
-
- unsigned Format : 2; /// Format for diagnostics:
- enum TextDiagnosticFormat { Clang, Msvc, Vi };
-
- unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
- unsigned ShowOverloads : 1; /// Overload candidates to show. Values from
- /// DiagnosticsEngine::OverloadsShown
- unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
- /// diagnostics, indicated by markers in the
- /// input source file.
-
- unsigned ElideType: 1; /// Elide identical types in template diffing
- unsigned ShowTemplateTree: 1; /// Print a template tree when diffing
-
- unsigned ErrorLimit; /// Limit # errors emitted.
- unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace.
- unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
- unsigned ConstexprBacktraceLimit; /// Limit depth of constexpr backtrace.
-
- /// The distance between tab stops.
- unsigned TabStop;
- enum { DefaultTabStop = 8, MaxTabStop = 100,
- DefaultMacroBacktraceLimit = 6,
- DefaultTemplateBacktraceLimit = 10,
- DefaultConstexprBacktraceLimit = 10 };
-
- /// Column limit for formatting message diagnostics, or 0 if unused.
- unsigned MessageLength;
-
- /// If non-empty, a file to log extended build information to, for development
- /// testing and analysis.
- std::string DumpBuildInformation;
-
- /// The file to log diagnostic output to.
- std::string DiagnosticLogFile;
-
- /// The file to serialize diagnostics to (non-appending).
- std::string DiagnosticSerializationFile;
-
- /// The list of -W... options used to alter the diagnostic mappings, with the
- /// prefixes removed.
- std::vector<std::string> Warnings;
-
-public:
- DiagnosticOptions() {
- IgnoreWarnings = 0;
- TabStop = DefaultTabStop;
- MessageLength = 0;
- NoRewriteMacros = 0;
- Pedantic = 0;
- PedanticErrors = 0;
- ShowCarets = 1;
- ShowColors = 0;
- ShowOverloads = DiagnosticsEngine::Ovl_All;
- ShowColumn = 1;
- ShowFixits = 1;
- ShowLocation = 1;
- ShowOptionNames = 0;
- ShowCategories = 0;
- Format = Clang;
- ShowSourceRanges = 0;
- ShowParseableFixits = 0;
- VerifyDiagnostics = 0;
- ErrorLimit = 0;
- TemplateBacktraceLimit = DefaultTemplateBacktraceLimit;
- MacroBacktraceLimit = DefaultMacroBacktraceLimit;
- ConstexprBacktraceLimit = DefaultConstexprBacktraceLimit;
- }
-};
-
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
index 09d7ecb51d80..086bb137d46f 100644
--- a/include/clang/Frontend/DiagnosticRenderer.h
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -44,7 +44,7 @@ typedef llvm::PointerUnion<const Diagnostic *,
class DiagnosticRenderer {
protected:
const LangOptions &LangOpts;
- const DiagnosticOptions &DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// \brief The location of the previous diagnostic if known.
///
@@ -66,7 +66,7 @@ protected:
DiagnosticsEngine::Level LastLevel;
DiagnosticRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts);
+ DiagnosticOptions *DiagOpts);
virtual ~DiagnosticRenderer();
@@ -124,7 +124,7 @@ public:
/// \param Ranges The underlined ranges for this code snippet.
/// \param FixItHints The FixIt hints active for this diagnostic.
/// \param SM The SourceManager; will be null if the diagnostic came from the
- /// frontend, thus \param Loc will be invalid.
+ /// frontend, thus \p Loc will be invalid.
void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
@@ -139,7 +139,7 @@ public:
class DiagnosticNoteRenderer : public DiagnosticRenderer {
public:
DiagnosticNoteRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
+ DiagnosticOptions *DiagOpts)
: DiagnosticRenderer(LangOpts, DiagOpts) {}
virtual ~DiagnosticNoteRenderer();
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index c0056de5cae3..328344425c38 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -109,7 +109,7 @@ public:
/// @{
bool isCurrentFileAST() const {
- assert(!CurrentInput.File.empty() && "No current file!");
+ assert(!CurrentInput.isEmpty() && "No current file!");
return CurrentASTUnit != 0;
}
@@ -117,14 +117,14 @@ public:
return CurrentInput;
}
- const std::string &getCurrentFile() const {
- assert(!CurrentInput.File.empty() && "No current file!");
- return CurrentInput.File;
+ const StringRef getCurrentFile() const {
+ assert(!CurrentInput.isEmpty() && "No current file!");
+ return CurrentInput.getFile();
}
InputKind getCurrentFileKind() const {
- assert(!CurrentInput.File.empty() && "No current file!");
- return CurrentInput.Kind;
+ assert(!CurrentInput.isEmpty() && "No current file!");
+ return CurrentInput.getKind();
}
ASTUnit &getCurrentASTUnit() const {
@@ -167,8 +167,8 @@ public:
/// @name Public Action Interface
/// @{
- /// BeginSourceFile - Prepare the action for processing the input file \arg
- /// Filename; this is run after the options and frontend have been
+ /// BeginSourceFile - Prepare the action for processing the input file
+ /// \p Input; this is run after the options and frontend have been
/// initialized, but prior to executing any per-file processing.
///
/// \param CI - The compiler instance this action is being run from. The
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index ce1cd9b2d3bc..db2f5a5e7159 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -16,6 +16,10 @@
#include <string>
#include <vector>
+namespace llvm {
+class MemoryBuffer;
+}
+
namespace clang {
namespace frontend {
@@ -72,19 +76,41 @@ enum InputKind {
/// \brief An input file for the front end.
-struct FrontendInputFile {
+class FrontendInputFile {
/// \brief The file name, or "-" to read from standard input.
std::string File;
+ llvm::MemoryBuffer *Buffer;
+
/// \brief The kind of input, e.g., C source, AST file, LLVM IR.
InputKind Kind;
/// \brief Whether we're dealing with a 'system' input (vs. a 'user' input).
bool IsSystem;
-
- FrontendInputFile() : Kind(IK_None) { }
+
+public:
+ FrontendInputFile() : Buffer(0), Kind(IK_None) { }
FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)
- : File(File.str()), Kind(Kind), IsSystem(IsSystem) { }
+ : File(File.str()), Buffer(0), Kind(Kind), IsSystem(IsSystem) { }
+ FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,
+ bool IsSystem = false)
+ : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { }
+
+ InputKind getKind() const { return Kind; }
+ bool isSystem() const { return IsSystem; }
+
+ bool isEmpty() const { return File.empty() && Buffer == 0; }
+ bool isFile() const { return !isBuffer(); }
+ bool isBuffer() const { return Buffer != 0; }
+
+ StringRef getFile() const {
+ assert(isFile());
+ return File;
+ }
+ llvm::MemoryBuffer *getBuffer() const {
+ assert(isBuffer());
+ return Buffer;
+ }
};
/// FrontendOptions - Options for controlling the behavior of the frontend.
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index e6f44032ac95..f07cb0234bdb 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -18,16 +18,17 @@ namespace clang {
namespace frontend {
enum LangFeatures {
- BCPLComment = (1 << 0),
+ LineComment = (1 << 0),
C89 = (1 << 1),
C99 = (1 << 2),
C11 = (1 << 3),
CPlusPlus = (1 << 4),
CPlusPlus0x = (1 << 5),
- Digraphs = (1 << 6),
- GNUMode = (1 << 7),
- HexFloat = (1 << 8),
- ImplicitInt = (1 << 9)
+ CPlusPlus1y = (1 << 6),
+ Digraphs = (1 << 7),
+ GNUMode = (1 << 8),
+ HexFloat = (1 << 9),
+ ImplicitInt = (1 << 10)
};
}
@@ -53,8 +54,8 @@ public:
/// getDescription - Get the description of this standard.
const char *getDescription() const { return Description; }
- /// hasBCPLComments - Language supports '//' comments.
- bool hasBCPLComments() const { return Flags & frontend::BCPLComment; }
+ /// Language supports '//' comments.
+ bool hasLineComments() const { return Flags & frontend::LineComment; }
/// isC89 - Language is a superset of C89.
bool isC89() const { return Flags & frontend::C89; }
@@ -71,6 +72,9 @@ public:
/// isCPlusPlus0x - Language is a C++0x variant.
bool isCPlusPlus0x() const { return Flags & frontend::CPlusPlus0x; }
+ /// isCPlusPlus1y - Language is a C++1y variant.
+ bool isCPlusPlus1y() const { return Flags & frontend::CPlusPlus1y; }
+
/// hasDigraphs - Language supports digraphs.
bool hasDigraphs() const { return Flags & frontend::Digraphs; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index a604d4bff658..10807b7804b3 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -36,91 +36,99 @@ LANGSTANDARD(c94, "iso9899:199409",
LANGSTANDARD(gnu89, "gnu89",
"ISO C 1990 with GNU extensions",
- BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt)
+ LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
LANGSTANDARD(gnu90, "gnu90",
"ISO C 1990 with GNU extensions",
- BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt)
+ LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
// C99-ish modes
LANGSTANDARD(c99, "c99",
"ISO C 1999",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(c9x, "c9x",
"ISO C 1999",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(iso9899_1999,
"iso9899:1999", "ISO C 1999",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(iso9899_199x,
"iso9899:199x", "ISO C 1999",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(gnu99, "gnu99",
"ISO C 1999 with GNU extensions",
- BCPLComment | C99 | Digraphs | GNUMode | HexFloat)
+ LineComment | C99 | Digraphs | GNUMode | HexFloat)
LANGSTANDARD(gnu9x, "gnu9x",
"ISO C 1999 with GNU extensions",
- BCPLComment | C99 | Digraphs | GNUMode | HexFloat)
+ LineComment | C99 | Digraphs | GNUMode | HexFloat)
// C11 modes
LANGSTANDARD(c11, "c11",
"ISO C 2011",
- BCPLComment | C99 | C11 | Digraphs | HexFloat)
+ LineComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(c1x, "c1x",
"ISO C 2011",
- BCPLComment | C99 | C11 | Digraphs | HexFloat)
+ LineComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(iso9899_2011,
"iso9899:2011", "ISO C 2011",
- BCPLComment | C99 | C11 | Digraphs | HexFloat)
+ LineComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(iso9899_201x,
"iso9899:2011", "ISO C 2011",
- BCPLComment | C99 | C11 | Digraphs | HexFloat)
+ LineComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(gnu11, "gnu11",
"ISO C 2011 with GNU extensions",
- BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+ LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
LANGSTANDARD(gnu1x, "gnu1x",
"ISO C 2011 with GNU extensions",
- BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+ LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
// C++ modes
LANGSTANDARD(cxx98, "c++98",
"ISO C++ 1998 with amendments",
- BCPLComment | CPlusPlus | Digraphs)
+ LineComment | CPlusPlus | Digraphs)
LANGSTANDARD(cxx03, "c++03",
"ISO C++ 1998 with amendments",
- BCPLComment | CPlusPlus | Digraphs)
+ LineComment | CPlusPlus | Digraphs)
LANGSTANDARD(gnucxx98, "gnu++98",
"ISO C++ 1998 with amendments and GNU extensions",
- BCPLComment | CPlusPlus | Digraphs | GNUMode)
+ LineComment | CPlusPlus | Digraphs | GNUMode)
LANGSTANDARD(cxx0x, "c++0x",
"ISO C++ 2011 with amendments",
- BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus0x | Digraphs)
LANGSTANDARD(cxx11, "c++11",
"ISO C++ 2011 with amendments",
- BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus0x | Digraphs)
LANGSTANDARD(gnucxx0x, "gnu++0x",
"ISO C++ 2011 with amendments and GNU extensions",
- BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+ LineComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
LANGSTANDARD(gnucxx11, "gnu++11",
"ISO C++ 2011 with amendments and GNU extensions",
- BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+ LineComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+
+LANGSTANDARD(cxx1y, "c++1y",
+ "Working draft for ISO C++ 2014",
+ LineComment | CPlusPlus | CPlusPlus0x | CPlusPlus1y | Digraphs)
+LANGSTANDARD(gnucxx1y, "gnu++1y",
+ "Working draft for ISO C++ 2014 with GNU extensions",
+ LineComment | CPlusPlus | CPlusPlus0x | CPlusPlus1y | Digraphs |
+ GNUMode)
// OpenCL
LANGSTANDARD(opencl, "cl",
"OpenCL 1.0",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(opencl11, "CL1.1",
"OpenCL 1.1",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
LANGSTANDARD(opencl12, "CL1.2",
"OpenCL 1.2",
- BCPLComment | C99 | Digraphs | HexFloat)
+ LineComment | C99 | Digraphs | HexFloat)
// CUDA
LANGSTANDARD(cuda, "cuda",
"NVIDIA CUDA(tm)",
- BCPLComment | CPlusPlus | Digraphs)
+ LineComment | CPlusPlus | Digraphs)
#undef LANGSTANDARD
diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h
index 4de15f2aed5f..f4fa876ae392 100644
--- a/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -42,7 +42,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
raw_ostream &OS;
const LangOptions *LangOpts;
- const DiagnosticOptions *DiagOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
SourceLocation LastWarningLoc;
FullSourceLoc LastLoc;
@@ -54,7 +54,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
std::string DwarfDebugFlags;
public:
- LogDiagnosticPrinter(raw_ostream &OS, const DiagnosticOptions &Diags,
+ LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
bool OwnsOutputStream = false);
virtual ~LogDiagnosticPrinter();
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index ffa7b4a9dc6b..539f2c5c4df8 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -52,7 +52,6 @@ public:
virtual void InitializeSema(Sema &S);
virtual void ForgetSema();
- static bool classof(const MultiplexConsumer *) { return true; }
private:
std::vector<ASTConsumer*> Consumers; // Owns these.
OwningPtr<MultiplexASTMutationListener> MutationListener;
diff --git a/include/clang/Frontend/SerializedDiagnosticPrinter.h b/include/clang/Frontend/SerializedDiagnosticPrinter.h
index aa0695fe24b6..ab70afd21fc6 100644
--- a/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -54,7 +54,7 @@ enum RecordIDs {
/// (via libclang) without needing to parse Clang's command line output.
///
DiagnosticConsumer *create(llvm::raw_ostream *OS,
- const DiagnosticOptions &diags);
+ DiagnosticOptions *diags);
} // end serialized_diags namespace
} // end clang namespace
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index c869c08c0fc2..51f841ddd3c5 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -40,7 +40,7 @@ class TextDiagnostic : public DiagnosticRenderer {
public:
TextDiagnostic(raw_ostream &OS,
const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts);
+ DiagnosticOptions *DiagOpts);
virtual ~TextDiagnostic();
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 23cf5211cd01..91ac3c833942 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -18,6 +18,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
namespace clang {
class DiagnosticOptions;
@@ -26,7 +27,7 @@ class TextDiagnostic;
class TextDiagnosticPrinter : public DiagnosticConsumer {
raw_ostream &OS;
- const DiagnosticOptions *DiagOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// \brief Handle to the currently active text diagnostic emitter.
OwningPtr<TextDiagnostic> TextDiag;
@@ -37,7 +38,7 @@ class TextDiagnosticPrinter : public DiagnosticConsumer {
unsigned OwnsOutputStream : 1;
public:
- TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags,
+ TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
bool OwnsOutputStream = false);
virtual ~TextDiagnosticPrinter();
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index a74589edc94a..06a3b24f3a3f 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -12,9 +12,9 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include <climits>
@@ -33,7 +33,9 @@ class FileEntry;
/// Indicating that a line expects an error or a warning is simple. Put a
/// comment on the line that has the diagnostic, use:
///
-/// expected-{error,warning,note}
+/// \code
+/// expected-{error,warning,note}
+/// \endcode
///
/// to tag if it's an expected error or warning, and place the expected text
/// between {{ and }} markers. The full text doesn't have to be included, only
@@ -94,12 +96,15 @@ class FileEntry;
///
/// In this example, the diagnostic may appear only once, if at all.
///
-/// Regex matching mode may be selected by appending '-re' to type. Example:
+/// Regex matching mode may be selected by appending '-re' to type, such as:
///
+/// \code
/// expected-error-re
+/// \endcode
///
/// Examples matching error: "variable has incomplete type 'struct s'"
///
+/// \code
/// // expected-error {{variable has incomplete type 'struct s'}}
/// // expected-error {{variable has incomplete type}}
///
@@ -107,6 +112,15 @@ class FileEntry;
/// // expected-error-re {{variable has has type 'struct .*'}}
/// // expected-error-re {{variable has has type 'struct (.*)'}}
/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
+/// \endcode
+///
+/// VerifyDiagnosticConsumer expects at least one expected-* directive to
+/// be found inside the source code. If no diagnostics are expected the
+/// following directive can be used to indicate this:
+///
+/// \code
+/// // expected-no-diagnostics
+/// \endcode
///
class VerifyDiagnosticConsumer: public DiagnosticConsumer,
public CommentHandler {
@@ -146,8 +160,8 @@ public:
}
private:
- Directive(const Directive&); // DO NOT IMPLEMENT
- void operator=(const Directive&); // DO NOT IMPLEMENT
+ Directive(const Directive &) LLVM_DELETED_FUNCTION;
+ void operator=(const Directive &) LLVM_DELETED_FUNCTION;
};
typedef std::vector<Directive*> DirectiveList;
@@ -166,10 +180,12 @@ public:
}
};
-#ifndef NDEBUG
- typedef llvm::DenseSet<FileID> FilesWithDiagnosticsSet;
- typedef llvm::SmallPtrSet<const FileEntry *, 4> FilesParsedForDirectivesSet;
-#endif
+ enum DirectiveStatus {
+ HasNoDirectives,
+ HasNoDirectivesReported,
+ HasExpectedNoDiagnostics,
+ HasOtherExpectedDirectives
+ };
private:
DiagnosticsEngine &Diags;
@@ -177,13 +193,36 @@ private:
bool OwnsPrimaryClient;
OwningPtr<TextDiagnosticBuffer> Buffer;
const Preprocessor *CurrentPreprocessor;
+ const LangOptions *LangOpts;
+ SourceManager *SrcManager;
unsigned ActiveSourceFiles;
-#ifndef NDEBUG
- FilesWithDiagnosticsSet FilesWithDiagnostics;
- FilesParsedForDirectivesSet FilesParsedForDirectives;
-#endif
+ DirectiveStatus Status;
ExpectedData ED;
+
void CheckDiagnostics();
+ void setSourceManager(SourceManager &SM) {
+ assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
+ SrcManager = &SM;
+ }
+
+#ifndef NDEBUG
+ class UnparsedFileStatus {
+ llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
+
+ public:
+ UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
+ : Data(File, FoundDirectives) {}
+
+ const FileEntry *getFile() const { return Data.getPointer(); }
+ bool foundDirectives() const { return Data.getInt(); }
+ };
+
+ typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap;
+ typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap;
+
+ ParsedFilesMap ParsedFiles;
+ UnparsedFilesMap UnparsedFiles;
+#endif
public:
/// Create a new verifying diagnostic client, which will issue errors to
@@ -197,12 +236,19 @@ public:
virtual void EndSourceFile();
- /// \brief Manually register a file as parsed.
- inline void appendParsedFile(const FileEntry *File) {
-#ifndef NDEBUG
- FilesParsedForDirectives.insert(File);
-#endif
- }
+ enum ParsedStatus {
+ /// File has been processed via HandleComment.
+ IsParsed,
+
+ /// File has diagnostics and may have directives.
+ IsUnparsed,
+
+ /// File has diagnostics but guaranteed no directives.
+ IsUnparsedNoDirectives
+ };
+
+ /// \brief Update lists of parsed and unparsed files.
+ void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
virtual bool HandleComment(Preprocessor &PP, SourceRange Comment);
diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h
index f172b5c8d22d..d2e2412192ed 100644
--- a/include/clang/Lex/ExternalPreprocessorSource.h
+++ b/include/clang/Lex/ExternalPreprocessorSource.h
@@ -28,9 +28,6 @@ public:
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros() = 0;
- /// \brief Read the definition for the given macro.
- virtual void LoadMacroDefinition(IdentifierInfo *II) = 0;
-
/// \brief Update an out-of-date identifier.
virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0;
};
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index 107408dced10..8473a6a4e752 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_LEX_HEADERMAP_H
#include "clang/Basic/LLVM.h"
+#include "llvm/Support/Compiler.h"
namespace llvm {
class MemoryBuffer;
@@ -30,8 +31,8 @@ namespace clang {
/// symlinks to files. Its advantages are that it is dense and more efficient
/// to create and process than a directory of symlinks.
class HeaderMap {
- HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT
- void operator=(const HeaderMap&); // DO NOT IMPLEMENT
+ HeaderMap(const HeaderMap &) LLVM_DELETED_FUNCTION;
+ void operator=(const HeaderMap &) LLVM_DELETED_FUNCTION;
const llvm::MemoryBuffer *FileBuffer;
bool NeedsBSwap;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 8e9491fdc339..4334db771c85 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -17,6 +17,7 @@
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Allocator.h"
@@ -29,6 +30,7 @@ class DiagnosticsEngine;
class ExternalIdentifierLookup;
class FileEntry;
class FileManager;
+class HeaderSearchOptions;
class IdentifierInfo;
/// \brief The preprocessor keeps track of this information for each
@@ -131,8 +133,10 @@ class HeaderSearch {
bool IsUserSpecifiedSystemFramework;
};
+ /// \brief Header-search options used to initialize this header search.
+ llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
+
FileManager &FileMgr;
- DiagnosticsEngine &Diags;
/// \#include search path information. Requests for \#include "x" search the
/// directory of the \#including file first, then each directory in SearchDirs
/// consecutively. Requests for <x> search the current dir first, then each
@@ -207,17 +211,21 @@ class HeaderSearch {
unsigned NumFrameworkLookups, NumSubFrameworkLookups;
// HeaderSearch doesn't support default or copy construction.
- explicit HeaderSearch();
- explicit HeaderSearch(const HeaderSearch&);
- void operator=(const HeaderSearch&);
-
+ HeaderSearch(const HeaderSearch&) LLVM_DELETED_FUNCTION;
+ void operator=(const HeaderSearch&) LLVM_DELETED_FUNCTION;
+
friend class DirectoryLookup;
public:
- HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+ HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+ FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target);
~HeaderSearch();
+ /// \brief Retrieve the header-search options with which this header search
+ /// was initialized.
+ HeaderSearchOptions &getHeaderSearchOpts() const { return *HSOpts; }
+
FileManager &getFileMgr() const { return FileMgr; }
/// \brief Interface for setting the file search paths.
@@ -283,6 +291,11 @@ public:
/// \brief Retrieve the path to the module cache.
StringRef getModuleCachePath() const { return ModuleCachePath; }
+
+ /// \brief Consider modules when including files from this directory.
+ void setDirectoryHasModuleMap(const DirectoryEntry* Dir) {
+ DirectoryHasModuleMap[Dir] = true;
+ }
/// \brief Forget everything we know about headers so far.
void ClearFileInfo() {
diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index ebc8f264b2a2..468fefa4aba3 100644
--- a/include/clang/Frontend/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -7,9 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H
-#define LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H
+#ifndef LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
+#define LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include <vector>
@@ -36,7 +37,7 @@ namespace frontend {
/// HeaderSearchOptions - Helper class for storing options related to the
/// initialization of the HeaderSearch object.
-class HeaderSearchOptions {
+class HeaderSearchOptions : public llvm::RefCountedBase<HeaderSearchOptions> {
public:
struct Entry {
std::string Path;
@@ -125,7 +126,7 @@ public:
UseStandardSystemIncludes(true), UseStandardCXXIncludes(true),
UseLibcxx(false), Verbose(false) {}
- /// AddPath - Add the \arg Path path to the specified \arg Group list.
+ /// AddPath - Add the \p Path path to the specified \p Group list.
void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot,
bool IsInternal = false, bool ImplicitExternC = false) {
@@ -134,7 +135,7 @@ public:
}
/// AddSystemHeaderPrefix - Override whether \#include directives naming a
- /// path starting with \arg Prefix should be considered as naming a system
+ /// path starting with \p Prefix should be considered as naming a system
/// header.
void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {
SystemHeaderPrefixes.push_back(SystemHeaderPrefix(Prefix, IsSystemHeader));
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index ca233de71c39..407b644fd74c 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -31,11 +31,11 @@ class DiagnosticBuilder;
enum ConflictMarkerKind {
/// Not within a conflict marker.
CMK_None,
- /// A normal or diff3 conflict marker, initiated by at least 7 <s,
- /// separated by at least 7 =s or |s, and terminated by at least 7 >s.
+ /// A normal or diff3 conflict marker, initiated by at least 7 "<"s,
+ /// separated by at least 7 "="s or "|"s, and terminated by at least 7 ">"s.
CMK_Normal,
- /// A Perforce-style conflict marker, initiated by 4 >s, separated by 4 =s,
- /// and terminated by 4 <s.
+ /// A Perforce-style conflict marker, initiated by 4 ">"s,
+ /// separated by 4 "="s, and terminated by 4 "<"s.
CMK_Perforce
};
@@ -83,8 +83,8 @@ class Lexer : public PreprocessorLexer {
// CurrentConflictMarkerState - The kind of conflict marker we are handling.
ConflictMarkerKind CurrentConflictMarkerState;
- Lexer(const Lexer&); // DO NOT IMPLEMENT
- void operator=(const Lexer&); // DO NOT IMPLEMENT
+ Lexer(const Lexer &) LLVM_DELETED_FUNCTION;
+ void operator=(const Lexer &) LLVM_DELETED_FUNCTION;
friend class Preprocessor;
void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd);
@@ -128,9 +128,7 @@ public:
SourceLocation getFileLoc() const { return FileLoc; }
/// Lex - Return the next token in the file. If this is the end of file, it
- /// return the tok::eof token. Return true if an error occurred and
- /// compilation should terminate, false if normal. This implicitly involves
- /// the preprocessor.
+ /// return the tok::eof token. This implicitly involves the preprocessor.
void Lex(Token &Result) {
// Start a new token.
Result.startToken();
@@ -278,8 +276,6 @@ public:
/// \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
/// source location lands.
- ///
- /// \param Loc
static SourceLocation GetBeginningOfToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts);
@@ -324,7 +320,7 @@ public:
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
///
- /// \param MacroBegin If non-null and function returns true, it is set to
+ /// \param MacroEnd If non-null and function returns true, it is set to
/// end location of the macro.
static bool isAtEndOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
@@ -396,7 +392,36 @@ public:
static std::pair<unsigned, bool>
ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &LangOpts,
unsigned MaxLines = 0);
-
+
+ /// \brief Checks that the given token is the first token that occurs after
+ /// the given location (this excludes comments and whitespace). Returns the
+ /// location immediately after the specified token. If the token is not found
+ /// or the location is inside a macro, the returned source location will be
+ /// invalid.
+ static SourceLocation findLocationAfterToken(SourceLocation loc,
+ tok::TokenKind TKind,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool SkipTrailingWhitespaceAndNewLine);
+
+ /// \brief Returns true if the given character could appear in an identifier.
+ static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts);
+
+ /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
+ /// emit a warning.
+ static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &LangOpts) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (isObviouslySimpleCharacter(Ptr[0])) {
+ Size = 1;
+ return *Ptr;
+ }
+
+ Size = 0;
+ return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
+ }
+
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
private:
@@ -427,7 +452,6 @@ private:
//===--------------------------------------------------------------------===//
// Lexer character reading interfaces.
-public:
// This lexer is built on two interfaces for reading characters, both of which
// automatically provide phase 1/2 translation. getAndAdvanceChar is used
@@ -467,7 +491,6 @@ public:
return C;
}
-private:
/// ConsumeChar - When a character (identified by getCharAndSize) is consumed
/// and added to a given token, check to see if there are diagnostics that
/// need to be emitted or flags that need to be set on the token. If so, do
@@ -503,22 +526,6 @@ private:
/// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize
/// method.
char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0);
-public:
-
- /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
- /// emit a warning.
- static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
- const LangOptions &LangOpts) {
- // If this is not a trigraph and not a UCN or escaped newline, return
- // quickly.
- if (isObviouslySimpleCharacter(Ptr[0])) {
- Size = 1;
- return *Ptr;
- }
-
- Size = 0;
- return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
- }
/// getEscapedNewLineSize - Return the size of the specified escaped newline,
/// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry
@@ -530,22 +537,6 @@ public:
/// otherwise return P.
static const char *SkipEscapedNewLines(const char *P);
- /// \brief Checks that the given token is the first token that occurs after
- /// the given location (this excludes comments and whitespace). Returns the
- /// location immediately after the specified token. If the token is not found
- /// or the location is inside a macro, the returned source location will be
- /// invalid.
- static SourceLocation findLocationAfterToken(SourceLocation loc,
- tok::TokenKind TKind,
- const SourceManager &SM,
- const LangOptions &LangOpts,
- bool SkipTrailingWhitespaceAndNewLine);
-
- /// \brief Returns true if the given character could appear in an identifier.
- static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts);
-
-private:
-
/// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
/// diagnostic.
static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
@@ -571,15 +562,17 @@ private:
bool LexEndOfFile (Token &Result, const char *CurPtr);
bool SkipWhitespace (Token &Result, const char *CurPtr);
- bool SkipBCPLComment (Token &Result, const char *CurPtr);
+ bool SkipLineComment (Token &Result, const char *CurPtr);
bool SkipBlockComment (Token &Result, const char *CurPtr);
- bool SaveBCPLComment (Token &Result, const char *CurPtr);
+ bool SaveLineComment (Token &Result, const char *CurPtr);
bool IsStartOfConflictMarker(const char *CurPtr);
bool HandleEndOfConflictMarker(const char *CurPtr);
bool isCodeCompletionPoint(const char *CurPtr) const;
void cutOffLexing() { BufferPtr = BufferEnd; }
+
+ bool isHexaLiteral(const char *Start, const LangOptions &LangOpts);
};
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index bbce62d1d48a..3b68d1b570f4 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -18,6 +18,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
#include "clang/Basic/TokenKinds.h"
#include <cctype>
@@ -48,8 +49,9 @@ class NumericLiteralParser {
bool saw_exponent, saw_period, saw_ud_suffix;
public:
- NumericLiteralParser(const char *begin, const char *end,
- SourceLocation Loc, Preprocessor &PP);
+ NumericLiteralParser(StringRef TokSpelling,
+ SourceLocation TokLoc,
+ Preprocessor &PP);
bool hadError;
bool isUnsigned;
bool isLong; // This is *not* set for long long.
@@ -230,8 +232,8 @@ public:
private:
void init(const Token *StringToks, unsigned NumStringToks);
- bool CopyStringFragment(StringRef Fragment);
- bool DiagnoseBadString(const Token& Tok);
+ bool CopyStringFragment(const Token &Tok, const char *TokBegin,
+ StringRef Fragment);
void DiagnoseLexingError(SourceLocation Loc);
};
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index cbd201f849de..aba77d580d9b 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -32,6 +32,12 @@ class MacroInfo {
SourceLocation Location;
/// EndLocation - The location of the last token in the macro.
SourceLocation EndLocation;
+ /// \brief The location where the macro was #undef'd, or an invalid location
+ /// for macros that haven't been undefined.
+ SourceLocation UndefLocation;
+ /// \brief Previous definition, the identifier of this macro was defined to,
+ /// or NULL.
+ MacroInfo *PreviousDefinition;
/// Arguments - The list of arguments for a function-like macro. This can be
/// empty, for, e.g. "#define X()". In a C99-style variadic macro, this
@@ -99,7 +105,16 @@ private:
/// \brief Whether the macro has public (when described in a module).
bool IsPublic : 1;
-
+
+ /// \brief Whether the macro definition is currently "hidden".
+ /// Note that this is transient state that is never serialized to the AST
+ /// file.
+ bool IsHidden : 1;
+
+ /// \brief Whether the definition of this macro is ambiguous, due to
+ /// multiple definitions coming in from multiple modules.
+ bool IsAmbiguous : 1;
+
~MacroInfo() {
assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
}
@@ -128,10 +143,34 @@ public:
/// setDefinitionEndLoc - Set the location of the last token in the macro.
///
void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; }
+
/// getDefinitionEndLoc - Return the location of the last token in the macro.
///
SourceLocation getDefinitionEndLoc() const { return EndLocation; }
-
+
+ /// \brief Set the location where macro was undefined. Can only be set once.
+ void setUndefLoc(SourceLocation UndefLoc) {
+ assert(UndefLocation.isInvalid() && "UndefLocation is already set!");
+ assert(UndefLoc.isValid() && "Invalid UndefLoc!");
+ UndefLocation = UndefLoc;
+ }
+
+ /// \brief Get the location where macro was undefined.
+ SourceLocation getUndefLoc() const { return UndefLocation; }
+
+ /// \brief Set previous definition of the macro with the same name.
+ void setPreviousDefinition(MacroInfo *PreviousDef) {
+ PreviousDefinition = PreviousDef;
+ }
+
+ /// \brief Get previous definition of the macro with the same name.
+ MacroInfo *getPreviousDefinition() { return PreviousDefinition; }
+
+ /// \brief Find macro definition active in the specified source location. If
+ /// this macro was not defined there, return NULL.
+ const MacroInfo *findDefinitionAtLoc(SourceLocation L,
+ SourceManager &SM) const;
+
/// \brief Get length in characters of the macro definition.
unsigned getDefinitionLength(SourceManager &SM) const {
if (IsDefinitionLengthCached)
@@ -294,6 +333,23 @@ public:
/// \brief Determine the location where this macro was explicitly made
/// public or private within its module.
SourceLocation getVisibilityLocation() { return VisibilityLocation; }
+
+ /// \brief Determine whether this macro is currently defined (and has not
+ /// been #undef'd) or has been hidden.
+ bool isDefined() const { return UndefLocation.isInvalid() && !IsHidden; }
+
+ /// \brief Determine whether this macro definition is hidden.
+ bool isHidden() const { return IsHidden; }
+
+ /// \brief Set whether this macro definition is hidden.
+ void setHidden(bool Val) { IsHidden = Val; }
+
+ /// \brief Determine whether this macro definition is ambiguous with
+ /// other macro definitions.
+ bool isAmbiguous() const { return IsAmbiguous; }
+
+ /// \brief Set whether this macro definition is ambiguous.
+ void setAmbiguous(bool Val) { IsAmbiguous = Val; }
private:
unsigned getDefinitionLengthSlow(SourceManager &SM) const;
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index fe5abdfba7ad..082408d83ce3 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -52,10 +52,37 @@ class ModuleMap {
/// \brief The top-level modules that are known.
llvm::StringMap<Module *> Modules;
-
+
+ /// \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;
+
+ public:
+ KnownHeader() : Storage(0, false) { }
+ KnownHeader(Module *M, bool Excluded) : Storage(M, Excluded) { }
+
+ /// \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 Whether this header is available in the module.
+ bool isAvailable() const {
+ return !isExcluded() && getModule()->isAvailable();
+ }
+
+ // \brief Whether this known header is valid (i.e., it has an
+ // associated module).
+ operator bool() const { return Storage.getPointer() != 0; }
+ };
+
+ typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap;
+
/// \brief Mapping from each header to the module that owns the contents of the
/// that header.
- llvm::DenseMap<const FileEntry *, Module *> Headers;
+ HeadersMap Headers;
/// \brief Mapping from directories with umbrella headers to the module
/// that is generated from the umbrella header.
@@ -64,7 +91,26 @@ class ModuleMap {
/// in the module map over to the module that includes them via its umbrella
/// header.
llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs;
-
+
+ /// \brief A directory for which framework modules can be inferred.
+ struct InferredDirectory {
+ InferredDirectory() : InferModules(), InferSystemModules() { }
+
+ /// \brief Whether to infer modules from this directory.
+ unsigned InferModules : 1;
+
+ /// \brief Whether the modules we infer are [system] modules.
+ unsigned InferSystemModules : 1;
+
+ /// \brief The names of modules that cannot be inferred within this
+ /// directory.
+ llvm::SmallVector<std::string, 2> ExcludedModules;
+ };
+
+ /// \brief A mapping from directories to information about inferring
+ /// framework modules from within those directories.
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories;
+
friend class ModuleMapParser;
/// \brief Resolve the given export declaration into an actual export
@@ -170,7 +216,23 @@ public:
std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
bool IsFramework,
bool IsExplicit);
-
+
+ /// \brief Determine whether we can infer a framework module a framework
+ /// with the given name in the given
+ ///
+ /// \param ParentDir The directory that is the parent of the framework
+ /// directory.
+ ///
+ /// \param Name The name of the module.
+ ///
+ /// \param IsSystem Will be set to 'true' if the inferred module must be a
+ /// system module.
+ ///
+ /// \returns true if we are allowed to infer a framework module, and false
+ /// otherwise.
+ bool canInferFrameworkModule(const DirectoryEntry *ParentDir,
+ StringRef Name, bool &IsSystem);
+
/// \brief Infer the contents of a framework module map from the given
/// framework directory.
Module *inferFrameworkModule(StringRef ModuleName,
@@ -215,7 +277,9 @@ public:
void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
/// \brief Adds this header to the given module.
- void addHeader(Module *Mod, const FileEntry *Header);
+ /// \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);
/// \brief Parse the given module map file, and record any modules we
/// encounter.
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 962b4df6c492..8ba02cc4ea23 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_LEX_PPCALLBACKS_H
#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "llvm/ADT/StringRef.h"
@@ -93,10 +94,10 @@ public:
/// \param IsAngled Whether the file name was enclosed in angle brackets;
/// otherwise, it was enclosed in quotes.
///
- /// \param File The actual file that may be included by this inclusion
- /// directive.
+ /// \param FilenameRange The character range of the quotes or angle brackets
+ /// for the written file name.
///
- /// \param EndLoc The location of the last token within the inclusion
+ /// \param File The actual file that may be included by this inclusion
/// directive.
///
/// \param SearchPath Contains the search path which was used to find the file
@@ -110,14 +111,34 @@ public:
///
/// \param RelativePath The path relative to SearchPath, at which the include
/// file was found. This is equal to FileName except for framework includes.
+ ///
+ /// \param Imported The module, whenever an inclusion directive was
+ /// automatically turned into a module import or null otherwise.
+ ///
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
+ }
+
+ /// \brief Callback invoked whenever there was an explicit module-import
+ /// syntax.
+ ///
+ /// \param ImportLoc The location of import directive token.
+ ///
+ /// \param Path The identifiers (and their locations) of the module
+ /// "path", e.g., "std.vector" would be split into "std" and "vector".
+ ///
+ /// \param Imported The imported module; can be null if importing failed.
+ ///
+ virtual void moduleImport(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ const Module *Imported) {
}
/// \brief Callback invoked when the end of the main file is reached.
@@ -266,14 +287,24 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
- First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
- EndLoc, SearchPath, RelativePath);
- Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
- EndLoc, SearchPath, RelativePath);
+ StringRef RelativePath,
+ const Module *Imported) {
+ First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled,
+ FilenameRange, File, SearchPath, RelativePath,
+ Imported);
+ Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled,
+ FilenameRange, File, SearchPath, RelativePath,
+ Imported);
+ }
+
+ virtual void moduleImport(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ const Module *Imported) {
+ First->moduleImport(ImportLoc, Path, Imported);
+ Second->moduleImport(ImportLoc, Path, Imported);
}
virtual void EndOfMainFile() {
diff --git a/include/clang/Lex/PPMutationListener.h b/include/clang/Lex/PPMutationListener.h
new file mode 100644
index 000000000000..5319c66fa27d
--- /dev/null
+++ b/include/clang/Lex/PPMutationListener.h
@@ -0,0 +1,43 @@
+//===--- PPMutationListener.h - Preprocessor Mutation Interface -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PPMutationListener interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_PPTMUTATIONLISTENER_H
+#define LLVM_CLANG_LEX_PPTMUTATIONLISTENER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class MacroInfo;
+
+/// \brief A record that describes an update to a macro that was
+/// originally loaded to an AST file and has been modified within the
+/// current translation unit.
+struct MacroUpdate {
+ /// \brief The source location at which this macro was #undef'd.
+ SourceLocation UndefLoc;
+};
+
+/// \brief An abstract interface that should be implemented by
+/// listeners that want to be notified when a preprocessor entity gets
+/// modified after its initial creation.
+class PPMutationListener {
+public:
+ virtual ~PPMutationListener();
+
+ /// \brief A macro has been #undef'd.
+ virtual void UndefinedMacro(MacroInfo *MI) { }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index f6a97a0a90a4..a9276e86b726 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -44,8 +44,8 @@ class PTHLexer : public PreprocessorLexer {
/// to process when doing quick skipping of preprocessor blocks.
const unsigned char* CurPPCondPtr;
- PTHLexer(const PTHLexer&); // DO NOT IMPLEMENT
- void operator=(const PTHLexer&); // DO NOT IMPLEMENT
+ PTHLexer(const PTHLexer &) LLVM_DELETED_FUNCTION;
+ void operator=(const PTHLexer &) LLVM_DELETED_FUNCTION;
/// ReadToken - Used by PTHLexer to read tokens TokBuf.
void ReadToken(Token& T);
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index 44f9ab39f321..e64dbd8bbcb0 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -81,9 +81,8 @@ class PTHManager : public IdentifierInfoLookup {
void* stringIdLookup, unsigned numIds,
const unsigned char* spellingBase, const char *originalSourceFile);
- // Do not implement.
- PTHManager();
- void operator=(const PTHManager&);
+ PTHManager(const PTHManager &) LLVM_DELETED_FUNCTION;
+ void operator=(const PTHManager &) LLVM_DELETED_FUNCTION;
/// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached
/// spelling for a token.
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index fb3e081961bf..57e51b754e42 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -94,9 +94,6 @@ namespace clang {
/// entity.
bool isInvalid() const { return Kind == InvalidKind; }
- // Implement isa/cast/dyncast/etc.
- static bool classof(const PreprocessedEntity *) { return true; }
-
// Only allow allocation of preprocessed entities using the allocator
// in PreprocessingRecord or by doing a placement new.
void* operator new(size_t bytes, PreprocessingRecord& PR,
@@ -133,7 +130,6 @@ namespace clang {
return PD->getKind() >= FirstPreprocessingDirective &&
PD->getKind() <= LastPreprocessingDirective;
}
- static bool classof(const PreprocessingDirective *) { return true; }
};
/// \brief Record the location of a macro definition.
@@ -155,7 +151,6 @@ namespace clang {
static bool classof(const PreprocessedEntity *PE) {
return PE->getKind() == MacroDefinitionKind;
}
- static bool classof(const MacroDefinition *) { return true; }
};
/// \brief Records the location of a macro expansion.
@@ -193,7 +188,6 @@ namespace clang {
static bool classof(const PreprocessedEntity *PE) {
return PE->getKind() == MacroExpansionKind;
}
- static bool classof(const MacroExpansion *) { return true; }
};
/// \brief Record the location of an inclusion directive, such as an
@@ -227,13 +221,18 @@ namespace clang {
/// This is a value of type InclusionKind.
unsigned Kind : 2;
+ /// \brief Whether the inclusion directive was automatically turned into
+ /// a module import.
+ unsigned ImportedModule : 1;
+
/// \brief The file that was included.
const FileEntry *File;
public:
InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind, StringRef FileName,
- bool InQuotes, const FileEntry *File, SourceRange Range);
+ bool InQuotes, bool ImportedModule,
+ const FileEntry *File, SourceRange Range);
/// \brief Determine what kind of inclusion directive this is.
InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); }
@@ -244,6 +243,10 @@ namespace clang {
/// \brief Determine whether the included file name was written in quotes;
/// otherwise, it was written in angle brackets.
bool wasInQuotes() const { return InQuotes; }
+
+ /// \brief Determine whether the inclusion directive was automatically
+ /// turned into a module import.
+ bool importedModule() const { return ImportedModule; }
/// \brief Retrieve the file entry for the actual file that was included
/// by this directive.
@@ -253,7 +256,6 @@ namespace clang {
static bool classof(const PreprocessedEntity *PE) {
return PE->getKind() == InclusionDirectiveKind;
}
- static bool classof(const InclusionDirective *) { return true; }
};
/// \brief An abstract class that should be subclassed by any external source
@@ -269,12 +271,12 @@ namespace clang {
virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0;
/// \brief Returns a pair of [Begin, End) indices of preallocated
- /// preprocessed entities that \arg Range encompasses.
+ /// preprocessed entities that \p Range encompasses.
virtual std::pair<unsigned, unsigned>
findPreprocessedEntitiesInRange(SourceRange Range) = 0;
/// \brief Optionally returns true or false if the preallocated preprocessed
- /// entity with index \arg Index came from file \arg FID.
+ /// entity with index \p Index came from file \p FID.
virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
FileID FID) {
return llvm::Optional<bool>();
@@ -343,14 +345,21 @@ namespace clang {
/// Negative values are used to indicate preprocessed entities
/// loaded from the external source while non-negative values are used to
/// indicate preprocessed entities introduced by the current preprocessor.
- /// If M is the number of loaded preprocessed entities, value -M
- /// corresponds to element 0 in the loaded entities vector, position -M+1
- /// corresponds to element 1 in the loaded entities vector, etc.
- typedef int PPEntityID;
-
- PPEntityID getPPEntityID(unsigned Index, bool isLoaded) const {
- return isLoaded ? PPEntityID(Index) - LoadedPreprocessedEntities.size()
- : Index;
+ /// Value -1 corresponds to element 0 in the loaded entities vector,
+ /// value -2 corresponds to element 1 in the loaded entities vector, etc.
+ /// Value 0 is an invalid value, the index to local entities is 1-based,
+ /// value 1 corresponds to element 0 in the local entities vector,
+ /// value 2 corresponds to element 1 in the local entities vector, etc.
+ class PPEntityID {
+ int ID;
+ explicit PPEntityID(int ID) : ID(ID) {}
+ friend class PreprocessingRecord;
+ public:
+ PPEntityID() : ID(0) {}
+ };
+
+ static PPEntityID getPPEntityID(unsigned Index, bool isLoaded) {
+ return isLoaded ? PPEntityID(-int(Index)-1) : PPEntityID(Index+1);
}
/// \brief Mapping from MacroInfo structures to their definitions.
@@ -372,7 +381,7 @@ namespace clang {
}
/// \brief Returns a pair of [Begin, End) indices of local preprocessed
- /// entities that \arg Range encompasses.
+ /// entities that \p Range encompasses.
std::pair<unsigned, unsigned>
findLocalPreprocessedEntitiesInRange(SourceRange Range) const;
unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const;
@@ -419,7 +428,7 @@ namespace clang {
/// corresponds to element 0 in the loaded entities vector, position -M+1
/// corresponds to element 1 in the loaded entities vector, etc. This
/// gives us a reasonably efficient, source-order walk.
- PPEntityID Position;
+ int Position;
public:
typedef PreprocessedEntity *value_type;
@@ -430,11 +439,15 @@ namespace clang {
iterator() : Self(0), Position(0) { }
- iterator(PreprocessingRecord *Self, PPEntityID Position)
+ iterator(PreprocessingRecord *Self, int Position)
: Self(Self), Position(Position) { }
value_type operator*() const {
- return Self->getPreprocessedEntity(Position);
+ bool isLoaded = Position < 0;
+ unsigned Index = isLoaded ?
+ Self->LoadedPreprocessedEntities.size() + Position : Position;
+ PPEntityID ID = Self->getPPEntityID(Index, isLoaded);
+ return Self->getPreprocessedEntity(ID);
}
value_type operator[](difference_type D) {
@@ -539,15 +552,26 @@ namespace clang {
return iterator(this, PreprocessedEntities.size());
}
+ /// \brief begin/end iterator pair for the given range of loaded
+ /// preprocessed entities.
+ std::pair<iterator, iterator>
+ getIteratorsForLoadedRange(unsigned start, unsigned count) {
+ unsigned end = start + count;
+ assert(end <= LoadedPreprocessedEntities.size());
+ return std::make_pair(
+ iterator(this, int(start)-LoadedPreprocessedEntities.size()),
+ iterator(this, int(end)-LoadedPreprocessedEntities.size()));
+ }
+
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
- /// that source range \arg R encompasses.
+ /// that source range \p R encompasses.
///
/// \param R the range to look for preprocessed entities.
///
std::pair<iterator, iterator> getPreprocessedEntitiesInRange(SourceRange R);
- /// \brief Returns true if the preprocessed entity that \arg PPEI iterator
- /// points to is coming from the file \arg FID.
+ /// \brief Returns true if the preprocessed entity that \p PPEI iterator
+ /// points to is coming from the file \p FID.
///
/// Can be used to avoid implicit deserializations of preallocated
/// preprocessed entities if we only care about entities of a specific file
@@ -597,10 +621,11 @@ namespace clang {
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
virtual void If(SourceLocation Loc, SourceRange ConditionRange);
virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
SourceLocation IfLoc);
@@ -613,11 +638,10 @@ namespace clang {
/// query.
struct {
SourceRange Range;
- std::pair<PPEntityID, PPEntityID> Result;
+ std::pair<int, int> Result;
} CachedRangeQuery;
- std::pair<PPEntityID, PPEntityID>
- getPreprocessedEntitiesInRangeSlow(SourceRange R);
+ std::pair<int, int> getPreprocessedEntitiesInRangeSlow(SourceRange R);
friend class ASTReader;
friend class ASTWriter;
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 02e3f1e7e439..e9095fbf44a9 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -18,6 +18,7 @@
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/PPMutationListener.h"
#include "clang/Lex/TokenLexer.h"
#include "clang/Lex/PTHManager.h"
#include "clang/Basic/Builtins.h"
@@ -54,6 +55,28 @@ class CodeCompletionHandler;
class DirectoryLookup;
class PreprocessingRecord;
class ModuleLoader;
+class PreprocessorOptions;
+
+/// \brief Stores token information for comparing actual tokens with
+/// predefined values. Only handles simple tokens and identifiers.
+class TokenValue {
+ tok::TokenKind Kind;
+ IdentifierInfo *II;
+
+public:
+ TokenValue(tok::TokenKind Kind) : Kind(Kind), II(0) {
+ assert(Kind != tok::raw_identifier && "Raw identifiers are not supported.");
+ assert(Kind != tok::identifier &&
+ "Identifiers should be created by TokenValue(IdentifierInfo *)");
+ assert(!tok::isLiteral(Kind) && "Literals are not supported.");
+ assert(!tok::isAnnotation(Kind) && "Annotations are not supported.");
+ }
+ TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {}
+ bool operator==(const Token &Tok) const {
+ return Tok.getKind() == Kind &&
+ (!II || II == Tok.getIdentifierInfo());
+ }
+};
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
@@ -61,6 +84,7 @@ class ModuleLoader;
/// like the \#include stack, token expansion, etc.
///
class Preprocessor : public RefCountedBase<Preprocessor> {
+ llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts;
DiagnosticsEngine *Diags;
LangOptions &LangOpts;
const TargetInfo *Target;
@@ -98,6 +122,8 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
IdentifierInfo *Ident__has_include; // __has_include
IdentifierInfo *Ident__has_include_next; // __has_include_next
IdentifierInfo *Ident__has_warning; // __has_warning
+ IdentifierInfo *Ident__building_module; // __building_module
+ IdentifierInfo *Ident__MODULE__; // __MODULE__
SourceLocation DATELoc, TIMELoc;
unsigned CounterValue; // Next __COUNTER__ value.
@@ -265,6 +291,11 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// encountered (e.g. a file is \#included, etc).
PPCallbacks *Callbacks;
+ /// \brief Listener whose actions are invoked when an entity in the
+ /// preprocessor (e.g., a macro) that was loaded from an AST file is
+ /// later mutated.
+ PPMutationListener *Listener;
+
struct MacroExpandsInfo {
Token Tok;
MacroInfo *MI;
@@ -274,10 +305,12 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
};
SmallVector<MacroExpandsInfo, 2> DelayedMacroExpandsCallbacks;
- /// Macros - For each IdentifierInfo with 'HasMacro' set, we keep a mapping
- /// to the actual definition of the macro.
+ /// Macros - For each IdentifierInfo that was associated with a macro, we
+ /// keep a mapping to the history of all macro definitions and #undefs in
+ /// the reverse order (the latest one is in the head of the list).
llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros;
-
+ friend class ASTReader;
+
/// \brief Macros that we want to warn because they are not used at the end
/// of the translation unit; we store just their SourceLocations instead
/// something like MacroInfo*. The benefit of this is that when we are
@@ -362,10 +395,9 @@ private: // Cached tokens state.
/// allocation.
MacroInfoChain *MICache;
- MacroInfo *getInfoForMacro(IdentifierInfo *II) const;
-
public:
- Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+ Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+ DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target,
SourceManager &SM, HeaderSearch &Headers,
ModuleLoader &TheModuleLoader,
@@ -382,6 +414,10 @@ public:
/// \param Target Information about the target.
void Initialize(const TargetInfo &Target);
+ /// \brief Retrieve the preprocessor options used to initialize this
+ /// preprocessor.
+ PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }
+
DiagnosticsEngine &getDiagnostics() const { return *Diags; }
void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; }
@@ -457,37 +493,70 @@ public:
Callbacks = C;
}
+ /// \brief Attach an preprocessor mutation listener to the preprocessor.
+ ///
+ /// The preprocessor mutation listener provides the ability to track
+ /// modifications to the preprocessor entities committed after they were
+ /// initially created.
+ void setPPMutationListener(PPMutationListener *Listener) {
+ this->Listener = Listener;
+ }
+
+ /// \brief Retrieve a pointer to the preprocessor mutation listener
+ /// associated with this preprocessor, if any.
+ PPMutationListener *getPPMutationListener() const { return Listener; }
+
/// \brief Given an identifier, return the MacroInfo it is \#defined to
/// or null if it isn't \#define'd.
MacroInfo *getMacroInfo(IdentifierInfo *II) const {
if (!II->hasMacroDefinition())
return 0;
- return getInfoForMacro(II);
+ MacroInfo *MI = getMacroInfoHistory(II);
+ assert(MI->getUndefLoc().isInvalid() && "Macro is undefined!");
+ return MI;
}
- /// \brief Specify a macro for this identifier.
- void setMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- bool LoadedFromAST = false);
+ /// \brief Given an identifier, return the (probably #undef'd) MacroInfo
+ /// representing the most recent macro definition. One can iterate over all
+ /// previous macro definitions from it. This method should only be called for
+ /// identifiers that hadMacroDefinition().
+ MacroInfo *getMacroInfoHistory(IdentifierInfo *II) const;
- /// macro_iterator/macro_begin/macro_end - This allows you to walk the current
- /// state of the macro table. This visits every currently-defined macro.
+ /// \brief Specify a macro for this identifier.
+ void setMacroInfo(IdentifierInfo *II, MacroInfo *MI);
+ /// \brief Add a MacroInfo that was loaded from an AST file.
+ void addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI,
+ MacroInfo *Hint = 0);
+ /// \brief Make the given MacroInfo, that was loaded from an AST file and
+ /// previously hidden, visible.
+ void makeLoadedMacroInfoVisible(IdentifierInfo *II, MacroInfo *MI);
+ /// \brief Undefine a macro for this identifier.
+ void clearMacroInfo(IdentifierInfo *II);
+
+ /// macro_iterator/macro_begin/macro_end - This allows you to walk the macro
+ /// history table. Currently defined macros have
+ /// IdentifierInfo::hasMacroDefinition() set and an empty
+ /// MacroInfo::getUndefLoc() at the head of the list.
typedef llvm::DenseMap<IdentifierInfo*,
MacroInfo*>::const_iterator macro_iterator;
macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
macro_iterator macro_end(bool IncludeExternalMacros = true) const;
+ /// \brief Return the name of the macro defined before \p Loc that has
+ /// spelling \p Tokens. If there are multiple macros with same spelling,
+ /// return the last one defined.
+ StringRef getLastMacroWithSpelling(SourceLocation Loc,
+ ArrayRef<TokenValue> Tokens) const;
+
const std::string &getPredefines() const { return Predefines; }
/// setPredefines - Set the predefines for this Preprocessor. These
/// predefines are automatically injected when parsing the main file.
void setPredefines(const char *P) { Predefines = P; }
void setPredefines(const std::string &P) { Predefines = P; }
- /// getIdentifierInfo - Return information about the specified preprocessor
- /// identifier token. The version of this method that takes two character
- /// pointers is preferred unless the identifier is already available as a
- /// string (this avoids allocation and copying of memory to construct an
- /// std::string).
+ /// Return information about the specified preprocessor
+ /// identifier token.
IdentifierInfo *getIdentifierInfo(StringRef Name) const {
return &Identifiers.get(Name);
}
@@ -501,8 +570,8 @@ public:
}
/// RemovePragmaHandler - Remove the specific pragma handler from
- /// the preprocessor. If \arg Namespace is non-null, then it should
- /// be the namespace that \arg Handler was added to. It is an error
+ /// the preprocessor. If \p Namespace is non-null, then it should
+ /// be the namespace that \p Handler was added to. It is an error
/// to remove a handler that has not been registered.
void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler);
void RemovePragmaHandler(PragmaHandler *Handler) {
@@ -564,7 +633,8 @@ public:
///
/// ILEnd specifies the location of the ')' for a function-like macro or the
/// identifier for an object-like macro.
- void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args);
+ void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroInfo *Macro,
+ MacroArgs *Args);
/// EnterTokenStream - Add a "macro" context to the top of the include stack,
/// which will cause the lexer to start returning the specified tokens.
@@ -724,6 +794,14 @@ public:
CachedTokens[CachedLexPos-1] = Tok;
}
+ /// TypoCorrectToken - Update the current token to represent the provided
+ /// identifier, in order to cache an action performed by typo correction.
+ void TypoCorrectToken(const Token &Tok) {
+ assert(Tok.getIdentifierInfo() && "Expected identifier token");
+ if (CachedLexPos != 0 && isBacktrackEnabled())
+ CachedTokens[CachedLexPos-1] = Tok;
+ }
+
/// \brief Recompute the current lexer kind based on the CurLexer/CurPTHLexer/
/// CurTokenLexer pointers.
void recomputeCurLexerKind();
@@ -892,7 +970,7 @@ public:
/// CreateString - Plop the specified string into a scratch buffer and set the
/// specified token's location and length to it. If specified, the source
/// location provides a location of the expansion point of the token.
- void CreateString(const char *Buf, unsigned Len, Token &Tok,
+ void CreateString(StringRef Str, Token &Tok,
SourceLocation ExpansionLocStart = SourceLocation(),
SourceLocation ExpansionLocEnd = SourceLocation());
@@ -929,7 +1007,7 @@ public:
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
///
- /// \param MacroBegin If non-null and function returns true, it is set to
+ /// \param MacroEnd If non-null and function returns true, it is set to
/// end location of the macro.
bool isAtEndOfMacroExpansion(SourceLocation loc,
SourceLocation *MacroEnd = 0) const {
@@ -1103,10 +1181,10 @@ public:
/// from a macro as multiple tokens, which need to be glued together. This
/// occurs for code like:
/// \code
- /// \#define FOO <a/b.h>
+ /// \#define FOO <x/y.h>
/// \#include FOO
/// \endcode
- /// because in this case, "<a/b.h>" is returned as 7 tokens, not one.
+ /// because in this case, "<x/y.h>" is returned as 7 tokens, not one.
///
/// This code concatenates and consumes tokens up to the '>' token. It
/// returns false if the > was found, otherwise it returns true if it finds
@@ -1289,6 +1367,8 @@ private:
// Macro handling.
void HandleDefineDirective(Token &Tok);
void HandleUndefDirective(Token &Tok);
+ void UndefineMacro(IdentifierInfo *II, MacroInfo *MI,
+ SourceLocation UndefLoc);
// Conditional Inclusion.
void HandleIfdefDirective(Token &Tok, bool isIfndef,
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 8a0b3cf51acc..20fb8a0c4804 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -69,8 +69,8 @@ protected:
/// we are currently in.
SmallVector<PPConditionalInfo, 4> ConditionalStack;
- PreprocessorLexer(const PreprocessorLexer&); // DO NOT IMPLEMENT
- void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT
+ PreprocessorLexer(const PreprocessorLexer &) LLVM_DELETED_FUNCTION;
+ void operator=(const PreprocessorLexer &) LLVM_DELETED_FUNCTION;
friend class Preprocessor;
PreprocessorLexer(Preprocessor *pp, FileID fid);
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index d86a923d4307..e5fe37379355 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -7,9 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_
-#define LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_
+#ifndef LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
+#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
@@ -38,7 +39,7 @@ enum ObjCXXARCStandardLibraryKind {
/// PreprocessorOptions - This class is used for passing the various options
/// used in preprocessor initialization to InitializePreprocessor().
-class PreprocessorOptions {
+class PreprocessorOptions : public llvm::RefCountedBase<PreprocessorOptions> {
public:
std::vector<std::pair<std::string, bool/*isUndef*/> > Macros;
std::vector<std::string> Includes;
@@ -65,10 +66,6 @@ public:
/// precompiled headers.
bool DisablePCHValidation;
- /// \brief When true, disables the use of the stat cache within a
- /// precompiled header or AST file.
- bool DisableStatCache;
-
/// \brief When true, a PCH with compiler errors will not be rejected.
bool AllowPCHWithCompilerErrors;
@@ -167,7 +164,7 @@ public:
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
DetailedRecordConditionalDirectives(false),
- DisablePCHValidation(false), DisableStatCache(false),
+ DisablePCHValidation(false),
AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 9c5a023f30d9..50b86c84e571 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -90,26 +90,18 @@ public:
/// \brief Return true if this is a raw identifier (when lexing
/// in raw mode) or a non-keyword identifier (when lexing in non-raw mode).
bool isAnyIdentifier() const {
- return is(tok::identifier) || is(tok::raw_identifier);
+ return tok::isAnyIdentifier(getKind());
}
- /// isLiteral - Return true if this is a "literal", like a numeric
+ /// \brief Return true if this is a "literal", like a numeric
/// constant, string, etc.
bool isLiteral() const {
- return is(tok::numeric_constant) || is(tok::char_constant) ||
- is(tok::wide_char_constant) || is(tok::utf16_char_constant) ||
- is(tok::utf32_char_constant) || is(tok::string_literal) ||
- is(tok::wide_string_literal) || is(tok::utf8_string_literal) ||
- is(tok::utf16_string_literal) || is(tok::utf32_string_literal) ||
- is(tok::angle_string_literal);
+ return tok::isLiteral(getKind());
}
+ /// \brief Return true if this is any of tok::annot_* kind tokens.
bool isAnnotation() const {
-#define ANNOTATION(NAME) \
- if (is(tok::annot_##NAME)) \
- return true;
-#include "clang/Basic/TokenKinds.def"
- return false;
+ return tok::isAnnotation(getKind());
}
/// \brief Return a source location identifier for the specified
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index 1330ad5f3143..090402a811e2 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -22,7 +22,7 @@ namespace clang {
class Token;
class MacroArgs;
-/// TokenLexer - This implements a lexer that returns token from a macro body
+/// TokenLexer - This implements a lexer that returns tokens from a macro body
/// or token stream instead of lexing from a character buffer. This is used for
/// macro expansion and _Pragma handling, for example.
///
@@ -91,24 +91,25 @@ class TokenLexer {
/// should not be subject to further macro expansion.
bool DisableMacroExpansion : 1;
- TokenLexer(const TokenLexer&); // DO NOT IMPLEMENT
- void operator=(const TokenLexer&); // DO NOT IMPLEMENT
+ TokenLexer(const TokenLexer &) LLVM_DELETED_FUNCTION;
+ void operator=(const TokenLexer &) LLVM_DELETED_FUNCTION;
public:
/// Create a TokenLexer for the specified macro with the specified actual
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
/// ILEnd specifies the location of the ')' for a function-like macro or the
/// identifier for an object-like macro.
- TokenLexer(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs,
- Preprocessor &pp)
+ TokenLexer(Token &Tok, SourceLocation ILEnd, MacroInfo *MI,
+ MacroArgs *ActualArgs, Preprocessor &pp)
: Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) {
- Init(Tok, ILEnd, ActualArgs);
+ Init(Tok, ILEnd, MI, ActualArgs);
}
/// Init - Initialize this TokenLexer to expand from the specified macro
/// with the specified argument information. Note that this ctor takes
/// ownership of the ActualArgs pointer. ILEnd specifies the location of the
/// ')' for a function-like macro or the identifier for an object-like macro.
- void Init(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs);
+ void Init(Token &Tok, SourceLocation ILEnd, MacroInfo *MI,
+ MacroArgs *ActualArgs);
/// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is
/// specified, this takes ownership of the tokens and delete[]'s them when
@@ -168,7 +169,7 @@ private:
/// first token on the next line.
void HandleMicrosoftCommentPaste(Token &Tok);
- /// \brief If \arg loc is a FileID and points inside the current macro
+ /// \brief If \p loc is a FileID and points inside the current macro
/// definition, returns the appropriate source location pointing at the
/// macro expansion source location entry.
SourceLocation getExpansionLocForMacroDefLoc(SourceLocation loc) const;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 4ef92f7dbc69..c433344602c6 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -30,6 +30,7 @@ namespace clang {
class PragmaHandler;
class Scope;
class BalancedDelimiterTracker;
+ class CorrectionCandidateCallback;
class DeclGroupRef;
class DiagnosticBuilder;
class Parser;
@@ -163,6 +164,10 @@ class Parser : public CodeCompletionHandler {
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_override;
+ // C++ type trait keywords that have can be reverted to identifiers and
+ // still used as type traits.
+ llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertableTypeTraits;
+
OwningPtr<PragmaHandler> AlignHandler;
OwningPtr<PragmaHandler> GCCVisibilityHandler;
OwningPtr<PragmaHandler> OptionsHandler;
@@ -204,6 +209,9 @@ class Parser : public CodeCompletionHandler {
/// top-level declaration is finished.
SmallVector<TemplateIdAnnotation *, 16> TemplateIds;
+ /// \brief Identifiers which have been declared within a tentative parse.
+ SmallVector<IdentifierInfo *, 8> TentativelyDeclaredIdentifiers;
+
IdentifierInfo *getSEHExceptKeyword();
/// True if we are within an Objective-C container while parsing C-like decls.
@@ -244,7 +252,7 @@ public:
typedef clang::TypeResult TypeResult;
typedef Expr *ExprArg;
- typedef ASTMultiPtr<Stmt*> MultiStmtArg;
+ typedef llvm::MutableArrayRef<Stmt*> MultiStmtArg;
typedef Sema::FullExprArg FullExprArg;
/// Adorns a ExprResult with Actions to make it an ExprResult
@@ -278,6 +286,23 @@ public:
/// the EOF was encountered.
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
+ /// ConsumeToken - Consume the current 'peek token' and lex the next one.
+ /// This does not work with all kinds of tokens: strings and specific other
+ /// tokens must be consumed with custom methods below. This returns the
+ /// location of the consumed token.
+ SourceLocation ConsumeToken() {
+ assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
+ !isTokenBrace() &&
+ "Should consume special tokens with Consume*Token");
+
+ if (Tok.is(tok::code_completion))
+ return handleUnexpectedCodeCompletionToken();
+
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
+
private:
//===--------------------------------------------------------------------===//
// Low-Level token peeking and consumption methods.
@@ -310,23 +335,6 @@ private:
/// For typos, give a fixit to '='
bool isTokenEqualOrEqualTypo();
- /// ConsumeToken - Consume the current 'peek token' and lex the next one.
- /// This does not work with all kinds of tokens: strings and specific other
- /// tokens must be consumed with custom methods below. This returns the
- /// location of the consumed token.
- SourceLocation ConsumeToken() {
- assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
- !isTokenBrace() &&
- "Should consume special tokens with Consume*Token");
-
- if (Tok.is(tok::code_completion))
- return handleUnexpectedCodeCompletionToken();
-
- PrevTokLocation = Tok.getLocation();
- PP.Lex(Tok);
- return PrevTokLocation;
- }
-
/// ConsumeAnyToken - Dispatch to the right Consume* method based on the
/// current token type. This should only be used in cases where the type of
/// the token really isn't known, e.g. in error recovery.
@@ -433,6 +441,34 @@ private:
/// #pragma pack...
void HandlePragmaPack();
+ /// \brief Handle the annotation token produced for
+ /// #pragma ms_struct...
+ void HandlePragmaMSStruct();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma align...
+ void HandlePragmaAlign();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma weak id...
+ void HandlePragmaWeak();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma weak id = id...
+ void HandlePragmaWeakAlias();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma redefine_extname...
+ void HandlePragmaRedefineExtname();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma STDC FP_CONTRACT...
+ void HandlePragmaFPContract();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma OPENCL EXTENSION...
+ void HandlePragmaOpenCLExtension();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
@@ -445,6 +481,7 @@ private:
return PP.LookAhead(N-1);
}
+public:
/// NextToken - This peeks ahead one token and returns it without
/// consuming it.
const Token &NextToken() {
@@ -456,6 +493,7 @@ private:
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
}
+private:
static void setTypeAnnotation(Token &Tok, ParsedType T) {
Tok.setAnnotationValue(T.getAsOpaquePtr());
}
@@ -478,12 +516,36 @@ private:
Tok.setAnnotationValue(ER.get());
}
+public:
// If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to
// find a type name by attempting typo correction.
bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false,
bool NeedType = false);
+ bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
+ bool NeedType,
+ CXXScopeSpec &SS,
+ bool IsNewScope);
bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
+private:
+ enum AnnotatedNameKind {
+ /// Annotation has failed and emitted an error.
+ ANK_Error,
+ /// The identifier is a tentatively-declared name.
+ ANK_TentativeDecl,
+ /// The identifier is a template name. FIXME: Add an annotation for that.
+ ANK_TemplateName,
+ /// The identifier can't be resolved.
+ ANK_Unresolved,
+ /// Annotation was successful.
+ ANK_Success
+ };
+ AnnotatedNameKind TryAnnotateName(bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC = 0);
+
+ /// Push a tok::annot_cxxscope token onto the token stream.
+ void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
+
/// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens,
/// replacing them with the non-context-sensitive keywords. This returns
/// true if the token was replaced.
@@ -529,12 +591,15 @@ private:
class TentativeParsingAction {
Parser &P;
Token PrevTok;
+ size_t PrevTentativelyDeclaredIdentifierCount;
unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount;
bool isActive;
public:
explicit TentativeParsingAction(Parser& p) : P(p) {
PrevTok = P.Tok;
+ PrevTentativelyDeclaredIdentifierCount =
+ P.TentativelyDeclaredIdentifiers.size();
PrevParenCount = P.ParenCount;
PrevBracketCount = P.BracketCount;
PrevBraceCount = P.BraceCount;
@@ -543,6 +608,8 @@ private:
}
void Commit() {
assert(isActive && "Parsing action was finished!");
+ P.TentativelyDeclaredIdentifiers.resize(
+ PrevTentativelyDeclaredIdentifierCount);
P.PP.CommitBacktrackedTokens();
isActive = false;
}
@@ -550,6 +617,8 @@ private:
assert(isActive && "Parsing action was finished!");
P.PP.Backtrack();
P.Tok = PrevTok;
+ P.TentativelyDeclaredIdentifiers.resize(
+ PrevTentativelyDeclaredIdentifierCount);
P.ParenCount = PrevParenCount;
P.BracketCount = PrevBracketCount;
P.BraceCount = PrevBraceCount;
@@ -608,6 +677,7 @@ private:
/// \brief Consume any extra semi-colons until the end of the line.
void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+public:
//===--------------------------------------------------------------------===//
// Scope manipulation
@@ -619,8 +689,8 @@ private:
/// the parser will exit the scope.
class ParseScope {
Parser *Self;
- ParseScope(const ParseScope&); // do not implement
- ParseScope& operator=(const ParseScope&); // do not implement
+ ParseScope(const ParseScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const ParseScope &) LLVM_DELETED_FUNCTION;
public:
// ParseScope - Construct a new object to manage a scope in the
@@ -655,12 +725,13 @@ private:
/// ExitScope - Pop a scope off the scope stack.
void ExitScope();
+private:
/// \brief RAII object used to modify the scope flags for the current scope.
class ParseScopeFlags {
Scope *CurScope;
unsigned OldFlags;
- ParseScopeFlags(const ParseScopeFlags &); // do not implement
- void operator=(const ParseScopeFlags &); // do not implement
+ ParseScopeFlags(const ParseScopeFlags &) LLVM_DELETED_FUNCTION;
+ void operator=(const ParseScopeFlags &) LLVM_DELETED_FUNCTION;
public:
ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true);
@@ -682,6 +753,7 @@ private:
SourceRange ParenRange);
void CheckNestedObjCContexts(SourceLocation AtLoc);
+public:
/// 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
@@ -713,6 +785,7 @@ private:
/// point for skipping past a simple-declaration.
void SkipMalformedDecl();
+private:
//===--------------------------------------------------------------------===//
// Lexing and parsing of C++ inline methods.
@@ -775,9 +848,16 @@ private:
void addDecl(Decl *D) { Decls.push_back(D); }
};
- /// A list of late parsed attributes. Used by ParseGNUAttributes.
- typedef llvm::SmallVector<LateParsedAttribute*, 2> LateParsedAttrList;
+ // A list of late-parsed attributes. Used by ParseGNUAttributes.
+ class LateParsedAttrList: public llvm::SmallVector<LateParsedAttribute*, 2> {
+ public:
+ LateParsedAttrList(bool PSoon = false) : ParseSoon(PSoon) { }
+
+ bool parseSoon() { return ParseSoon; }
+ private:
+ bool ParseSoon; // Are we planning to parse these shortly after creation?
+ };
/// Contains the lexed tokens of a member function definition
/// which needs to be parsed at the end of the class declaration
@@ -880,9 +960,9 @@ private:
/// any member function declarations or definitions that need to be
/// parsed after the corresponding top-level class is complete.
struct ParsingClass {
- ParsingClass(Decl *TagOrTemplate, bool TopLevelClass)
+ ParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface)
: TopLevelClass(TopLevelClass), TemplateScope(false),
- TagOrTemplate(TagOrTemplate) { }
+ IsInterface(IsInterface), TagOrTemplate(TagOrTemplate) { }
/// \brief Whether this is a "top-level" class, meaning that it is
/// not nested within another class.
@@ -893,6 +973,9 @@ private:
/// othewise, it is a tag declaration.
bool TemplateScope : 1;
+ /// \brief Whether this class is an __interface.
+ bool IsInterface : 1;
+
/// \brief The class or class template whose definition we are parsing.
Decl *TagOrTemplate;
@@ -919,9 +1002,10 @@ private:
Sema::ParsingClassState State;
public:
- ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass)
+ ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass,
+ bool IsInterface)
: P(P), Popped(false),
- State(P.PushParsingClass(TagOrTemplate, TopLevelClass)) {
+ State(P.PushParsingClass(TagOrTemplate, TopLevelClass, IsInterface)) {
}
/// \brief Pop this class of the stack.
@@ -1009,7 +1093,7 @@ private:
void LateTemplateParser(const FunctionDecl *FD);
Sema::ParsingClassState
- PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
+ PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
void DeallocateParsedClasses(ParsingClass *Class);
void PopParsingClass(Sema::ParsingClassState);
@@ -1145,6 +1229,7 @@ private:
Decl *ParseObjCMethodDefinition();
+public:
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.
@@ -1160,6 +1245,7 @@ private:
// Expr that doesn't include commas.
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
+private:
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
@@ -1174,6 +1260,9 @@ private:
bool isAddressOfOperand = false,
TypeCastState isTypeCast = NotTypeCast);
+ /// Returns true if the next token cannot start an expression.
+ bool isNotExpressionStart();
+
/// Returns true if the next token would start a postfix-expression
/// suffix.
bool isPostfixExpressionSuffixStart() {
@@ -1245,6 +1334,8 @@ private:
bool *MayBePseudoDestructor = 0,
bool IsTypename = false);
+ void CheckForLParenAfterColonColon();
+
//===--------------------------------------------------------------------===//
// C++0x 5.1.2: Lambda expressions
@@ -1379,8 +1470,16 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
+ /// A SmallVector of statements, with stack size 32 (as that is the only one
+ /// used.)
+ typedef SmallVector<Stmt*, 32> StmtVector;
+ /// A SmallVector of expressions, with stack size 12 (the maximum used.)
+ typedef SmallVector<Expr*, 12> ExprVector;
+ /// A SmallVector of types.
+ typedef SmallVector<ParsedType, 12> TypeVector;
+
StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) {
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
}
StmtResult ParseStatementOrDeclaration(StmtVector &Stmts,
@@ -1399,6 +1498,7 @@ private:
StmtResult ParseCompoundStatement(bool isStmtExpr = false);
StmtResult ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags);
+ void ParseCompoundStatementLeadingPragmas();
StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
bool ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
@@ -1463,8 +1563,8 @@ private:
// C++ 6: Statements and Blocks
StmtResult ParseCXXTryBlock();
- StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc);
- StmtResult ParseCXXCatchBlock();
+ StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false);
+ StmtResult ParseCXXCatchBlock(bool FnCatch = false);
//===--------------------------------------------------------------------===//
// MS: SEH Statements and Blocks
@@ -1578,6 +1678,15 @@ private:
/// specifier or if we're not sure.
bool isKnownToBeTypeSpecifier(const Token &Tok) const;
+ /// \brief Return true if we know that we are definitely looking at a
+ /// decl-specifier, and isn't part of an expression such as a function-style
+ /// cast. Return false if it's no a decl-specifier, or we're not sure.
+ bool isKnownToBeDeclarationSpecifier() {
+ if (getLangOpts().CPlusPlus)
+ return isCXXDeclarationSpecifier() == TPResult::True();
+ return isDeclarationSpecifier(true);
+ }
+
/// isDeclarationStatement - Disambiguates between a declaration or an
/// expression statement, when parsing function bodies.
/// Returns true for declaration, false for expression.
@@ -1707,6 +1816,11 @@ private:
isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False(),
bool *HasMissingTypename = 0);
+ /// \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.
+ bool isTentativelyDeclared(IdentifierInfo *II);
+
// "Tentative parsing" functions, used for disambiguation. If a parsing error
// is encountered they will return TPResult::Error().
// Returning TPResult::True()/False() indicates that the ambiguity was
@@ -1724,11 +1838,14 @@ private:
TPResult TryParseFunctionDeclarator();
TPResult TryParseBracketDeclarator();
+public:
TypeResult ParseTypeName(SourceRange *Range = 0,
Declarator::TheContext Context
= Declarator::TypeNameContext,
AccessSpecifier AS = AS_none,
Decl **OwnedType = 0);
+
+private:
void ParseBlockId(SourceLocation CaretLoc);
// Check for the start of a C++11 attribute-specifier-seq in a context where
@@ -1748,6 +1865,11 @@ private:
}
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
+ // Forbid C++11 attributes that appear on certain syntactic
+ // locations which standard permits but we don't supported yet,
+ // for example, attributes appertain to decl specifiers.
+ void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs);
+
void MaybeParseGNUAttributes(Declarator &D,
LateParsedAttrList *LateAttrs = 0) {
if (Tok.is(tok::kw___attribute)) {
@@ -1769,7 +1891,10 @@ private:
void ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc);
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
void MaybeParseCXX0XAttributes(Declarator &D) {
if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
@@ -1799,6 +1924,7 @@ private:
SourceLocation *EndLoc = 0);
void ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = 0);
+
IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc);
void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs,
@@ -1856,7 +1982,7 @@ private:
VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const {
return isCXX0XVirtSpecifier(Tok);
}
- void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
+ void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
bool isCXX0XFinalKeyword() const;
@@ -2004,6 +2130,8 @@ private:
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result);
+
+public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
@@ -2011,6 +2139,7 @@ private:
SourceLocation& TemplateKWLoc,
UnqualifiedId &Result);
+private:
//===--------------------------------------------------------------------===//
// C++ 14: Templates [temp]
diff --git a/include/clang/Rewrite/DeltaTree.h b/include/clang/Rewrite/Core/DeltaTree.h
index f32906a323e0..a6109bf90157 100644
--- a/include/clang/Rewrite/DeltaTree.h
+++ b/include/clang/Rewrite/Core/DeltaTree.h
@@ -14,6 +14,8 @@
#ifndef CLANG_REWRITE_DELTATREE_H
#define CLANG_REWRITE_DELTATREE_H
+#include "llvm/Support/Compiler.h"
+
namespace clang {
/// DeltaTree - a multiway search tree (BTree) structure with some fancy
@@ -25,7 +27,7 @@ namespace clang {
/// as well, without traversing the whole tree.
class DeltaTree {
void *Root; // "DeltaTreeNode *"
- void operator=(const DeltaTree&); // DO NOT IMPLEMENT
+ void operator=(const DeltaTree &) LLVM_DELETED_FUNCTION;
public:
DeltaTree();
diff --git a/include/clang/Rewrite/HTMLRewrite.h b/include/clang/Rewrite/Core/HTMLRewrite.h
index 88caf85e6010..88caf85e6010 100644
--- a/include/clang/Rewrite/HTMLRewrite.h
+++ b/include/clang/Rewrite/Core/HTMLRewrite.h
diff --git a/include/clang/Rewrite/RewriteRope.h b/include/clang/Rewrite/Core/RewriteRope.h
index cb3f8a86f8ab..9f1bbe501318 100644
--- a/include/clang/Rewrite/RewriteRope.h
+++ b/include/clang/Rewrite/Core/RewriteRope.h
@@ -14,6 +14,8 @@
#ifndef LLVM_CLANG_REWRITEROPE_H
#define LLVM_CLANG_REWRITEROPE_H
+#include "llvm/Support/Compiler.h"
+
#include <cstring>
#include <cassert>
#include <cstddef>
@@ -33,11 +35,11 @@ namespace clang {
char Data[1]; // Variable sized.
void addRef() {
- if (this) ++RefCount;
+ ++RefCount;
}
void dropRef() {
- if (this && --RefCount == 0)
+ if (--RefCount == 0)
delete [] (char*)this;
}
};
@@ -63,22 +65,27 @@ namespace clang {
RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End)
: StrData(Str), StartOffs(Start), EndOffs(End) {
- StrData->addRef();
+ if (StrData)
+ StrData->addRef();
}
RopePiece(const RopePiece &RP)
: StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) {
- StrData->addRef();
+ if (StrData)
+ StrData->addRef();
}
~RopePiece() {
- StrData->dropRef();
+ if (StrData)
+ StrData->dropRef();
}
void operator=(const RopePiece &RHS) {
if (StrData != RHS.StrData) {
- StrData->dropRef();
+ if (StrData)
+ StrData->dropRef();
StrData = RHS.StrData;
- StrData->addRef();
+ if (StrData)
+ StrData->addRef();
}
StartOffs = RHS.StartOffs;
EndOffs = RHS.EndOffs;
@@ -148,7 +155,7 @@ namespace clang {
class RopePieceBTree {
void /*RopePieceBTreeNode*/ *Root;
- void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT
+ void operator=(const RopePieceBTree &) LLVM_DELETED_FUNCTION;
public:
RopePieceBTree();
RopePieceBTree(const RopePieceBTree &RHS);
@@ -191,7 +198,8 @@ public:
~RewriteRope() {
// If we had an allocation buffer, drop our reference to it.
- AllocBuffer->dropRef();
+ if (AllocBuffer)
+ AllocBuffer->dropRef();
}
typedef RopePieceBTree::iterator iterator;
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Core/Rewriter.h
index 5ffd88b05df5..a33ea134a7ac 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Core/Rewriter.h
@@ -16,8 +16,8 @@
#define LLVM_CLANG_REWRITER_H
#include "clang/Basic/SourceLocation.h"
-#include "clang/Rewrite/DeltaTree.h"
-#include "clang/Rewrite/RewriteRope.h"
+#include "clang/Rewrite/Core/DeltaTree.h"
+#include "clang/Rewrite/Core/RewriteRope.h"
#include "llvm/ADT/StringRef.h"
#include <cstring>
#include <map>
@@ -183,7 +183,7 @@ public:
/// location was not rewritable, false otherwise.
///
/// \param indentNewLines if true new lines in the string are indented
- /// using the indentation of the source line in position \arg Loc.
+ /// using the indentation of the source line in position \p Loc.
bool InsertText(SourceLocation Loc, StringRef Str,
bool InsertAfter = true, bool indentNewLines = false);
diff --git a/include/clang/Rewrite/TokenRewriter.h b/include/clang/Rewrite/Core/TokenRewriter.h
index 894db0953f7f..ec0bb5ba0827 100644
--- a/include/clang/Rewrite/TokenRewriter.h
+++ b/include/clang/Rewrite/Core/TokenRewriter.h
@@ -43,8 +43,8 @@ namespace clang {
///
OwningPtr<ScratchBuffer> ScratchBuf;
- TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT
- void operator=(const TokenRewriter&); // DO NOT IMPLEMENT.
+ TokenRewriter(const TokenRewriter &) LLVM_DELETED_FUNCTION;
+ void operator=(const TokenRewriter &) LLVM_DELETED_FUNCTION;
public:
/// TokenRewriter - This creates a TokenRewriter for the file with the
/// specified FileID.
diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/Frontend/ASTConsumers.h
index c9c92e3a0188..c9c92e3a0188 100644
--- a/include/clang/Rewrite/ASTConsumers.h
+++ b/include/clang/Rewrite/Frontend/ASTConsumers.h
diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/Frontend/FixItRewriter.h
index 44f0611b17e6..f12a034bd716 100644
--- a/include/clang/Rewrite/FixItRewriter.h
+++ b/include/clang/Rewrite/Frontend/FixItRewriter.h
@@ -17,7 +17,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Edit/EditedSource.h"
namespace clang {
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/Frontend/FrontendActions.h
index ea876d9980f6..ea876d9980f6 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/Frontend/FrontendActions.h
diff --git a/include/clang/Rewrite/Rewriters.h b/include/clang/Rewrite/Frontend/Rewriters.h
index f5ade5ad35d3..f5ade5ad35d3 100644
--- a/include/clang/Rewrite/Rewriters.h
+++ b/include/clang/Rewrite/Frontend/Rewriters.h
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index bf358862b09e..2e8b0c03f770 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -140,10 +140,10 @@ private:
return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1);
}
- AttributeList(const AttributeList &); // DO NOT IMPLEMENT
- void operator=(const AttributeList &); // DO NOT IMPLEMENT
- void operator delete(void *); // DO NOT IMPLEMENT
- ~AttributeList(); // DO NOT IMPLEMENT
+ AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION;
+ void operator=(const AttributeList &) LLVM_DELETED_FUNCTION;
+ void operator delete(void *) LLVM_DELETED_FUNCTION;
+ ~AttributeList() LLVM_DELETED_FUNCTION;
size_t allocated_size() const;
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index d43aaafb2924..b128bd866903 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -439,9 +439,6 @@ private:
/// \brief The availability of this code-completion result.
unsigned Availability : 2;
-
- /// \brief The kind of the parent context.
- unsigned ParentKind : 14;
/// \brief The name of the parent context.
StringRef ParentName;
@@ -450,13 +447,13 @@ private:
/// entity being completed by this result.
const char *BriefComment;
- CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
- CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
+ CodeCompletionString(const CodeCompletionString &) LLVM_DELETED_FUNCTION;
+ void operator=(const CodeCompletionString &) LLVM_DELETED_FUNCTION;
CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
unsigned Priority, CXAvailabilityKind Availability,
const char **Annotations, unsigned NumAnnotations,
- CXCursorKind ParentKind, StringRef ParentName,
+ StringRef ParentName,
const char *BriefComment);
~CodeCompletionString() { }
@@ -489,11 +486,6 @@ public:
/// \brief Retrieve the annotation string specified by \c AnnotationNr.
const char *getAnnotation(unsigned AnnotationNr) const;
-
- /// \brief Retrieve parent context's cursor kind.
- CXCursorKind getParentContextKind() const {
- return (CXCursorKind)ParentKind;
- }
/// \brief Retrieve the name of the parent context.
StringRef getParentContextName() const {
@@ -577,7 +569,6 @@ private:
CodeCompletionTUInfo &CCTUInfo;
unsigned Priority;
CXAvailabilityKind Availability;
- CXCursorKind ParentKind;
StringRef ParentName;
const char *BriefComment;
@@ -591,14 +582,14 @@ public:
CodeCompletionTUInfo &CCTUInfo)
: Allocator(Allocator), CCTUInfo(CCTUInfo),
Priority(0), Availability(CXAvailability_Available),
- ParentKind(CXCursor_NotImplemented), BriefComment(NULL) { }
+ BriefComment(NULL) { }
CodeCompletionBuilder(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
unsigned Priority, CXAvailabilityKind Availability)
: Allocator(Allocator), CCTUInfo(CCTUInfo),
Priority(Priority), Availability(Availability),
- ParentKind(CXCursor_NotImplemented), BriefComment(NULL) { }
+ BriefComment(NULL) { }
/// \brief Retrieve the allocator into which the code completion
/// strings should be allocated.
@@ -642,7 +633,6 @@ public:
void addBriefComment(StringRef Comment);
- CXCursorKind getParentKind() const { return ParentKind; }
StringRef getParentName() const { return ParentName; }
};
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 792b0c643d8d..0728e8737638 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -266,6 +266,7 @@ public:
static const TST TST_enum = clang::TST_enum;
static const TST TST_union = clang::TST_union;
static const TST TST_struct = clang::TST_struct;
+ static const TST TST_interface = clang::TST_interface;
static const TST TST_class = clang::TST_class;
static const TST TST_typename = clang::TST_typename;
static const TST TST_typeofType = clang::TST_typeofType;
@@ -378,11 +379,12 @@ private:
}
static bool isDeclRep(TST T) {
return (T == TST_enum || T == TST_struct ||
- T == TST_union || T == TST_class);
+ T == TST_interface || T == TST_union ||
+ T == TST_class);
}
- DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
- void operator=(const DeclSpec&); // DO NOT IMPLEMENT
+ DeclSpec(const DeclSpec &) LLVM_DELETED_FUNCTION;
+ void operator=(const DeclSpec &) LLVM_DELETED_FUNCTION;
public:
DeclSpec(AttributeFactory &attrFactory)
@@ -598,8 +600,7 @@ public:
}
bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID, const LangOptions &Lang,
- bool IsTypeSpec);
+ unsigned &DiagID, const LangOptions &Lang);
bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
@@ -781,8 +782,9 @@ private:
/// \brief Represents a C++ unqualified-id that has been parsed.
class UnqualifiedId {
private:
- const UnqualifiedId &operator=(const UnqualifiedId &); // DO NOT IMPLEMENT
-
+ UnqualifiedId(const UnqualifiedId &Other) LLVM_DELETED_FUNCTION;
+ const UnqualifiedId &operator=(const UnqualifiedId &) LLVM_DELETED_FUNCTION;
+
public:
/// \brief Describes the kind of unqualified-id parsed.
enum IdKind {
@@ -857,17 +859,6 @@ public:
UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { }
- /// \brief Do not use this copy constructor. It is temporary, and only
- /// exists because we are holding FieldDeclarators in a SmallVector when we
- /// don't actually need them.
- ///
- /// FIXME: Kill this copy constructor.
- UnqualifiedId(const UnqualifiedId &Other)
- : Kind(IK_Identifier), Identifier(Other.Identifier),
- StartLocation(Other.StartLocation), EndLocation(Other.EndLocation) {
- assert(Other.Kind == IK_Identifier && "Cannot copy non-identifiers");
- }
-
/// \brief Clear out this unqualified-id, setting it to default (invalid)
/// state.
void clear() {
@@ -1110,7 +1101,7 @@ struct DeclaratorChunk {
/// \brief Whether the ref-qualifier (if any) is an lvalue reference.
/// Otherwise, it's an rvalue reference.
unsigned RefQualifierIsLValueRef : 1;
-
+
/// The type qualifiers: const/volatile/restrict.
/// The qualifier bitmask values are the same as in QualType.
unsigned TypeQuals : 3;
@@ -1125,9 +1116,15 @@ struct DeclaratorChunk {
/// specified.
unsigned HasTrailingReturnType : 1;
+ /// The location of the left parenthesis in the source.
+ unsigned LParenLoc;
+
/// When isVariadic is true, the location of the ellipsis in the source.
unsigned EllipsisLoc;
+ /// The location of the right parenthesis in the source.
+ unsigned RParenLoc;
+
/// NumArgs - This is the number of formal arguments provided for the
/// declarator.
unsigned NumArgs;
@@ -1202,10 +1199,19 @@ struct DeclaratorChunk {
bool isKNRPrototype() const {
return !hasPrototype && NumArgs != 0;
}
-
+
+ SourceLocation getLParenLoc() const {
+ return SourceLocation::getFromRawEncoding(LParenLoc);
+ }
+
SourceLocation getEllipsisLoc() const {
return SourceLocation::getFromRawEncoding(EllipsisLoc);
}
+
+ SourceLocation getRParenLoc() const {
+ return SourceLocation::getFromRawEncoding(RParenLoc);
+ }
+
SourceLocation getExceptionSpecLoc() const {
return SourceLocation::getFromRawEncoding(ExceptionSpecLoc);
}
@@ -1358,11 +1364,13 @@ struct DeclaratorChunk {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
- static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
+ static DeclaratorChunk getFunction(bool hasProto,
bool isAmbiguous,
- SourceLocation EllipsisLoc,
+ SourceLocation LParenLoc,
ParamInfo *ArgInfo, unsigned NumArgs,
- unsigned TypeQuals,
+ SourceLocation EllipsisLoc,
+ SourceLocation RParenLoc,
+ unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
SourceLocation ConstQualifierLoc,
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index c241266c9b8d..a20480c7e44b 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -124,6 +124,7 @@ public:
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
StringRef Msg);
static DelayedDiagnostic makeAccess(SourceLocation Loc,
@@ -193,12 +194,17 @@ public:
return DeprecationData.UnknownObjCClass;
}
+ const ObjCPropertyDecl *getObjCProperty() const {
+ return DeprecationData.ObjCProperty;
+ }
+
private:
union {
/// Deprecation.
struct {
const NamedDecl *Decl;
const ObjCInterfaceDecl *UnknownObjCClass;
+ const ObjCPropertyDecl *ObjCProperty;
const char *Message;
size_t MessageLen;
} DeprecationData;
@@ -220,9 +226,8 @@ class DelayedDiagnosticPool {
const DelayedDiagnosticPool *Parent;
llvm::SmallVector<DelayedDiagnostic, 4> Diagnostics;
- // Do not implement.
- DelayedDiagnosticPool(const DelayedDiagnosticPool &other);
- DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &other);
+ DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
+ void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
public:
DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
~DelayedDiagnosticPool() {
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 785bf6acd12c..7a598498ff31 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -175,7 +175,6 @@ public:
static bool classof(const ExternalASTSource *Source) {
return Source->SemaSource;
}
- static bool classof(const ExternalSemaSource *) { return true; }
};
} // end namespace clang
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 77659be1470f..0b0af0cff6ef 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -901,9 +901,9 @@ public:
/// \brief Add a constructor-initialization step.
///
- /// \arg FromInitList The constructor call is syntactically an initializer
+ /// \param FromInitList The constructor call is syntactically an initializer
/// list.
- /// \arg AsInitList The constructor is called as an init list constructor.
+ /// \param AsInitList The constructor is called as an init list constructor.
void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
AccessSpecifier Access,
QualType T,
diff --git a/include/clang/Sema/LocInfoType.h b/include/clang/Sema/LocInfoType.h
index 93cb8cbda45f..63dfa72b8f74 100644
--- a/include/clang/Sema/LocInfoType.h
+++ b/include/clang/Sema/LocInfoType.h
@@ -55,7 +55,6 @@ public:
static bool classof(const Type *T) {
return T->getTypeClass() == (TypeClass)LocInfo;
}
- static bool classof(const LocInfoType *) { return true; }
};
} // end namespace clang
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
new file mode 100644
index 000000000000..1513aebb3e1e
--- /dev/null
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -0,0 +1,367 @@
+//===--- MultiplexExternalSemaSource.h - External Sema Interface-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ExternalSemaSource interface, dispatching to all clients
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
+#define LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
+
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Weak.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <utility>
+
+namespace clang {
+
+ class CXXConstructorDecl;
+ class CXXRecordDecl;
+ class DeclaratorDecl;
+ struct ExternalVTableUse;
+ class LookupResult;
+ class NamespaceDecl;
+ class Scope;
+ class Sema;
+ class TypedefNameDecl;
+ class ValueDecl;
+ class VarDecl;
+
+
+/// \brief An abstract interface that should be implemented by
+/// external AST sources that also provide information for semantic
+/// analysis.
+class MultiplexExternalSemaSource : public ExternalSemaSource {
+
+private:
+ llvm::SmallVector<ExternalSemaSource*, 2> Sources; // doesn't own them.
+
+public:
+
+ ///\brief Constructs a new multiplexing external sema source and appends the
+ /// given element to it.
+ ///
+ ///\param[in] s1 - A non-null (old) ExternalSemaSource.
+ ///\param[in] s2 - A non-null (new) ExternalSemaSource.
+ ///
+ MultiplexExternalSemaSource(ExternalSemaSource& s1, ExternalSemaSource& s2);
+
+ ~MultiplexExternalSemaSource();
+
+ ///\brief Appends new source to the source list.
+ ///
+ ///\param[in] source - An ExternalSemaSource.
+ ///
+ void addSource(ExternalSemaSource &source);
+
+ //===--------------------------------------------------------------------===//
+ // ExternalASTSource.
+ //===--------------------------------------------------------------------===//
+
+ /// \brief Resolve a declaration ID into a declaration, potentially
+ /// building a new declaration.
+ ///
+ /// This method only needs to be implemented if the AST source ever
+ /// passes back decl sets as VisibleDeclaration objects.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Decl *GetExternalDecl(uint32_t ID);
+
+ /// \brief Resolve a selector ID into a selector.
+ ///
+ /// This operation only needs to be implemented if the AST source
+ /// returns non-zero for GetNumKnownSelectors().
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Selector GetExternalSelector(uint32_t ID);
+
+ /// \brief Returns the number of selectors known to the external AST
+ /// source.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual uint32_t GetNumExternalSelectors();
+
+ /// \brief Resolve the offset of a statement in the decl stream into
+ /// a statement.
+ ///
+ /// This operation is meant to be used via a LazyOffsetPtr. It only
+ /// needs to be implemented if the AST source uses methods like
+ /// FunctionDecl::setLazyBody when building decls.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
+
+ /// \brief Resolve the offset of a set of C++ base specifiers in the decl
+ /// stream into an array of specifiers.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
+
+ /// \brief Finds all declarations with the given name in the
+ /// given context.
+ ///
+ /// Generally the final step of this method is either to call
+ /// SetExternalVisibleDeclsForName or to recursively call lookup on
+ /// the DeclContext after calling SetExternalVisibleDecls.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual DeclContextLookupResult
+ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
+
+ /// \brief Ensures that the table of all visible declarations inside this
+ /// context is up to date.
+ ///
+ /// The default implementation of this functino is a no-op.
+ virtual void completeVisibleDeclsMap(const DeclContext *DC);
+
+ /// \brief Finds all declarations lexically contained within the given
+ /// DeclContext, after applying an optional filter predicate.
+ ///
+ /// \param isKindWeWant a predicate function that returns true if the passed
+ /// declaration kind is one we are looking for. If NULL, all declarations
+ /// are returned.
+ ///
+ /// \return an indication of whether the load succeeded or failed.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Result);
+
+ /// \brief Finds all declarations lexically contained within the given
+ /// DeclContext.
+ ///
+ /// \return true if an error occurred
+ ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
+ SmallVectorImpl<Decl*> &Result) {
+ return FindExternalLexicalDecls(DC, 0, Result);
+ }
+
+ template <typename DeclTy>
+ ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
+ SmallVectorImpl<Decl*> &Result) {
+ return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
+ }
+
+ /// \brief Get the decls that are contained in a file in the Offset/Length
+ /// range. \p Length can be 0 to indicate a point at \p Offset instead of
+ /// a range.
+ virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
+ SmallVectorImpl<Decl *> &Decls);
+
+ /// \brief Gives the external AST source an opportunity to complete
+ /// an incomplete type.
+ virtual void CompleteType(TagDecl *Tag);
+
+ /// \brief Gives the external AST source an opportunity to complete an
+ /// incomplete Objective-C class.
+ ///
+ /// This routine will only be invoked if the "externally completed" bit is
+ /// set on the ObjCInterfaceDecl via the function
+ /// \c ObjCInterfaceDecl::setExternallyCompleted().
+ virtual void CompleteType(ObjCInterfaceDecl *Class);
+
+ /// \brief Loads comment ranges.
+ virtual void ReadComments();
+
+ /// \brief Notify ExternalASTSource that we started deserialization of
+ /// a decl or type so until FinishedDeserializing is called there may be
+ /// decls that are initializing. Must be paired with FinishedDeserializing.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual void StartedDeserializing();
+
+ /// \brief Notify ExternalASTSource that we finished the deserialization of
+ /// a decl or type. Must be paired with StartedDeserializing.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual void FinishedDeserializing();
+
+ /// \brief Function that will be invoked when we begin parsing a new
+ /// translation unit involving this external AST source.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual void StartTranslationUnit(ASTConsumer *Consumer);
+
+ /// \brief Print any statistics that have been gathered regarding
+ /// the external AST source.
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual void PrintStats();
+
+
+ /// \brief Perform layout on the given record.
+ ///
+ /// This routine allows the external AST source to provide an specific
+ /// layout for a record, overriding the layout that would normally be
+ /// constructed. It is intended for clients who receive specific layout
+ /// details rather than source code (such as LLDB). The client is expected
+ /// to fill in the field offsets, base offsets, virtual base offsets, and
+ /// complete object size.
+ ///
+ /// \param Record The record whose layout is being requested.
+ ///
+ /// \param Size The final size of the record, in bits.
+ ///
+ /// \param Alignment The final alignment of the record, in bits.
+ ///
+ /// \param FieldOffsets The offset of each of the fields within the record,
+ /// expressed in bits. All of the fields must be provided with offsets.
+ ///
+ /// \param BaseOffsets The offset of each of the direct, non-virtual base
+ /// classes. If any bases are not given offsets, the bases will be laid
+ /// out according to the ABI.
+ ///
+ /// \param VirtualBaseOffsets The offset of each of the virtual base classes
+ /// (either direct or not). If any bases are not given offsets, the bases will
+ /// be laid out according to the ABI.
+ ///
+ /// \returns true if the record layout was provided, false otherwise.
+ virtual bool
+ layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
+
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
+
+ //===--------------------------------------------------------------------===//
+ // ExternalSemaSource.
+ //===--------------------------------------------------------------------===//
+
+ /// \brief Initialize the semantic source with the Sema instance
+ /// being used to perform semantic analysis on the abstract syntax
+ /// tree.
+ virtual void InitializeSema(Sema &S);
+
+ /// \brief Inform the semantic consumer that Sema is no longer available.
+ virtual void ForgetSema();
+
+ /// \brief Load the contents of the global method pool for a given
+ /// selector.
+ virtual void ReadMethodPool(Selector Sel);
+
+ /// \brief Load the set of namespaces that are known to the external source,
+ /// which will be used during typo correction.
+ virtual void ReadKnownNamespaces(SmallVectorImpl<NamespaceDecl*> &Namespaces);
+
+ /// \brief Do last resort, unqualified lookup on a LookupResult that
+ /// Sema cannot find.
+ ///
+ /// \param R a LookupResult that is being recovered.
+ ///
+ /// \param S the Scope of the identifier occurrence.
+ ///
+ /// \return true to tell Sema to recover using the LookupResult.
+ virtual bool LookupUnqualified(LookupResult &R, Scope *S);
+
+ /// \brief Read the set of tentative definitions known to the external Sema
+ /// source.
+ ///
+ /// The external source should append its own tentative definitions to the
+ /// given vector of tentative definitions. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadTentativeDefinitions(SmallVectorImpl<VarDecl*> &Defs);
+
+ /// \brief Read the set of unused file-scope declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own unused, filed-scope to the
+ /// given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl*> &Decls);
+
+ /// \brief Read the set of delegating constructors known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own delegating constructors to the
+ /// given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl*> &Decls);
+
+ /// \brief Read the set of ext_vector type declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own ext_vector type declarations to
+ /// the given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl*> &Decls);
+
+ /// \brief Read the set of dynamic classes known to the external Sema source.
+ ///
+ /// The external source should append its own dynamic classes to
+ /// the given vector of declarations. Note that this routine may be
+ /// invoked multiple times; the external source should take care not to
+ /// introduce the same declarations repeatedly.
+ virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl*> &Decls);
+
+ /// \brief Read the set of locally-scoped external declarations known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own locally-scoped external
+ /// declarations to the given vector of declarations. Note that this routine
+ /// may be invoked multiple times; the external source should take care not
+ /// to introduce the same declarations repeatedly.
+ virtual void ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl*>&Decls);
+
+ /// \brief Read the set of referenced selectors known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own referenced selectors to the
+ /// given vector of selectors. Note that this routine
+ /// may be invoked multiple times; the external source should take care not
+ /// to introduce the same selectors repeatedly.
+ virtual void ReadReferencedSelectors(SmallVectorImpl<std::pair<Selector,
+ SourceLocation> > &Sels);
+
+ /// \brief Read the set of weak, undeclared identifiers known to the
+ /// external Sema source.
+ ///
+ /// The external source should append its own weak, undeclared identifiers to
+ /// the given vector. Note that this routine may be invoked multiple times;
+ /// the external source should take care not to introduce the same identifiers
+ /// repeatedly.
+ virtual void ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI);
+
+ /// \brief Read the set of used vtables known to the external Sema source.
+ ///
+ /// The external source should append its own used vtables to the given
+ /// vector. Note that this routine may be invoked multiple times; the external
+ /// source should take care not to introduce the same vtables repeatedly.
+ virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables);
+
+ /// \brief Read the set of pending instantiations known to the external
+ /// Sema source.
+ ///
+ /// The external source should append its own pending instantiations to the
+ /// given vector. Note that this routine may be invoked multiple times; the
+ /// external source should take care not to introduce the same instantiations
+ /// repeatedly.
+ virtual void ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl*, SourceLocation> >& Pending);
+
+ // isa/cast/dyn_cast support
+ static bool classof(const MultiplexExternalSemaSource*) { return true; }
+ //static bool classof(const ExternalSemaSource*) { return true; }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_SEMA_MULTIPLEX_EXTERNAL_SEMA_SOURCE_H
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index d2fc285c9e29..65ed781f743c 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -748,12 +748,14 @@ namespace clang {
unsigned NumInlineSequences;
char InlineSpace[16 * sizeof(ImplicitConversionSequence)];
- OverloadCandidateSet(const OverloadCandidateSet &);
- OverloadCandidateSet &operator=(const OverloadCandidateSet &);
-
+ OverloadCandidateSet(const OverloadCandidateSet &) LLVM_DELETED_FUNCTION;
+ void operator=(const OverloadCandidateSet &) LLVM_DELETED_FUNCTION;
+
+ void destroyCandidates();
+
public:
OverloadCandidateSet(SourceLocation Loc) : Loc(Loc), NumInlineSequences(0){}
- ~OverloadCandidateSet() { clear(); }
+ ~OverloadCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
@@ -808,7 +810,7 @@ namespace clang {
void NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
llvm::ArrayRef<Expr *> Args,
- const char *Opc = 0,
+ StringRef Opc = "",
SourceLocation Loc = SourceLocation());
};
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index fb9e368dde9f..e59fb3f46ba3 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -15,7 +15,7 @@
#define LLVM_CLANG_SEMA_OWNERSHIP_H
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
//===----------------------------------------------------------------------===//
@@ -30,8 +30,8 @@ namespace clang {
class DeclGroupRef;
class Expr;
class NestedNameSpecifier;
+ class ParsedTemplateArgument;
class QualType;
- class Sema;
class Stmt;
class TemplateName;
class TemplateParameterList;
@@ -112,96 +112,6 @@ namespace llvm {
struct isPodLike<clang::OpaquePtr<T> > { static const bool value = true; };
}
-
-
-// -------------------------- About Move Emulation -------------------------- //
-// The smart pointer classes in this file attempt to emulate move semantics
-// as they appear in C++0x with rvalue references. Since C++03 doesn't have
-// rvalue references, some tricks are needed to get similar results.
-// Move semantics in C++0x have the following properties:
-// 1) "Moving" means transferring the value of an object to another object,
-// similar to copying, but without caring what happens to the old object.
-// In particular, this means that the new object can steal the old object's
-// resources instead of creating a copy.
-// 2) Since moving can modify the source object, it must either be explicitly
-// requested by the user, or the modifications must be unnoticeable.
-// 3) As such, C++0x moving is only allowed in three contexts:
-// * By explicitly using std::move() to request it.
-// * From a temporary object, since that object cannot be accessed
-// afterwards anyway, thus making the state unobservable.
-// * On function return, since the object is not observable afterwards.
-//
-// To sum up: moving from a named object should only be possible with an
-// explicit std::move(), or on function return. Moving from a temporary should
-// be implicitly done. Moving from a const object is forbidden.
-//
-// The emulation is not perfect, and has the following shortcomings:
-// * move() is not in namespace std.
-// * move() is required on function return.
-// * There are difficulties with implicit conversions.
-// * Microsoft's compiler must be given the /Za switch to successfully compile.
-//
-// -------------------------- Implementation -------------------------------- //
-// The move emulation relies on the peculiar reference binding semantics of
-// C++03: as a rule, a non-const reference may not bind to a temporary object,
-// except for the implicit object parameter in a member function call, which
-// can refer to a temporary even when not being const.
-// The moveable object has five important functions to facilitate moving:
-// * A private, unimplemented constructor taking a non-const reference to its
-// own class. This constructor serves a two-fold purpose.
-// - It prevents the creation of a copy constructor that takes a const
-// reference. Temporaries would be able to bind to the argument of such a
-// constructor, and that would be bad.
-// - Named objects will bind to the non-const reference, but since it's
-// private, this will fail to compile. This prevents implicit moving from
-// named objects.
-// There's also a copy assignment operator for the same purpose.
-// * An implicit, non-const conversion operator to a special mover type. This
-// type represents the rvalue reference of C++0x. Being a non-const member,
-// its implicit this parameter can bind to temporaries.
-// * A constructor that takes an object of this mover type. This constructor
-// performs the actual move operation. There is an equivalent assignment
-// operator.
-// There is also a free move() function that takes a non-const reference to
-// an object and returns a temporary. Internally, this function uses explicit
-// constructor calls to move the value from the referenced object to the return
-// value.
-//
-// There are now three possible scenarios of use.
-// * Copying from a const object. Constructor overload resolution will find the
-// non-const copy constructor, and the move constructor. The first is not
-// viable because the const object cannot be bound to the non-const reference.
-// The second fails because the conversion to the mover object is non-const.
-// Moving from a const object fails as intended.
-// * Copying from a named object. Constructor overload resolution will select
-// the non-const copy constructor, but fail as intended, because this
-// constructor is private.
-// * Copying from a temporary. Constructor overload resolution cannot select
-// the non-const copy constructor, because the temporary cannot be bound to
-// the non-const reference. It thus selects the move constructor. The
-// temporary can be bound to the implicit this parameter of the conversion
-// operator, because of the special binding rule. Construction succeeds.
-// Note that the Microsoft compiler, as an extension, allows binding
-// temporaries against non-const references. The compiler thus selects the
-// non-const copy constructor and fails, because the constructor is private.
-// Passing /Za (disable extensions) disables this behaviour.
-// The free move() function is used to move from a named object.
-//
-// Note that when passing an object of a different type (the classes below
-// have OwningResult and OwningPtr, which should be mixable), you get a problem.
-// Argument passing and function return use copy initialization rules. The
-// effect of this is that, when the source object is not already of the target
-// type, the compiler will first seek a way to convert the source object to the
-// target type, and only then attempt to copy the resulting object. This means
-// that when passing an OwningResult where an OwningPtr is expected, the
-// compiler will first seek a conversion from OwningResult to OwningPtr, then
-// copy the OwningPtr. The resulting conversion sequence is:
-// OwningResult object -> ResultMover -> OwningResult argument to
-// OwningPtr(OwningResult) -> OwningPtr -> PtrMover -> final OwningPtr
-// This conversion sequence is too complex to be allowed. Thus the special
-// move_* functions, which help the compiler out with some explicit
-// conversions.
-
namespace clang {
// Basic
class DiagnosticBuilder;
@@ -239,6 +149,7 @@ namespace clang {
bool isUsable() const { return !Invalid && Val; }
PtrTy get() const { return Val; }
+ // FIXME: Replace with get.
PtrTy release() const { return Val; }
PtrTy take() const { return Val; }
template <typename T> T *takeAs() { return static_cast<T*>(get()); }
@@ -282,6 +193,7 @@ namespace clang {
void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01);
return PtrTraits::getFromVoidPointer(VP);
}
+ // FIXME: Replace with get.
PtrTy take() const { return get(); }
PtrTy release() const { return get(); }
template <typename T> T *takeAs() { return static_cast<T*>(get()); }
@@ -300,119 +212,11 @@ namespace clang {
}
};
- /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns
- /// the individual pointers, not the array holding them.
- template <typename PtrTy> class ASTMultiPtr;
-
- template <class PtrTy>
- class ASTMultiPtr {
- PtrTy *Nodes;
- unsigned Count;
-
- public:
- // Normal copying implicitly defined
- ASTMultiPtr() : Nodes(0), Count(0) {}
- explicit ASTMultiPtr(Sema &) : Nodes(0), Count(0) {}
- ASTMultiPtr(Sema &, PtrTy *nodes, unsigned count)
- : Nodes(nodes), Count(count) {}
- // Fake mover in Parse/AstGuard.h needs this:
- ASTMultiPtr(PtrTy *nodes, unsigned count) : Nodes(nodes), Count(count) {}
-
- /// Access to the raw pointers.
- PtrTy *get() const { return Nodes; }
-
- /// Access to the count.
- unsigned size() const { return Count; }
-
- PtrTy *release() {
- return Nodes;
- }
- };
-
- class ParsedTemplateArgument;
-
- class ASTTemplateArgsPtr {
- ParsedTemplateArgument *Args;
- mutable unsigned Count;
-
- public:
- ASTTemplateArgsPtr(Sema &actions, ParsedTemplateArgument *args,
- unsigned count) :
- Args(args), Count(count) { }
-
- // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
- ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) :
- Args(Other.Args), Count(Other.Count) {
- }
-
- // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
- ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) {
- Args = Other.Args;
- Count = Other.Count;
- return *this;
- }
-
- ParsedTemplateArgument *getArgs() const { return Args; }
- unsigned size() const { return Count; }
-
- void reset(ParsedTemplateArgument *args, unsigned count) {
- Args = args;
- Count = count;
- }
-
- const ParsedTemplateArgument &operator[](unsigned Arg) const;
-
- ParsedTemplateArgument *release() const {
- return Args;
- }
- };
-
- /// \brief A small vector that owns a set of AST nodes.
- template <class PtrTy, unsigned N = 8>
- class ASTOwningVector : public SmallVector<PtrTy, N> {
- ASTOwningVector(ASTOwningVector &); // do not implement
- ASTOwningVector &operator=(ASTOwningVector &); // do not implement
-
- public:
- explicit ASTOwningVector(Sema &Actions)
- { }
-
- PtrTy *take() {
- return &this->front();
- }
-
- template<typename T> T **takeAs() { return reinterpret_cast<T**>(take()); }
- };
-
/// An opaque type for threading parsed type information through the
/// parser.
typedef OpaquePtr<QualType> ParsedType;
typedef UnionOpaquePtr<QualType> UnionParsedType;
- /// A SmallVector of statements, with stack size 32 (as that is the only one
- /// used.)
- typedef ASTOwningVector<Stmt*, 32> StmtVector;
- /// A SmallVector of expressions, with stack size 12 (the maximum used.)
- typedef ASTOwningVector<Expr*, 12> ExprVector;
- /// A SmallVector of types.
- typedef ASTOwningVector<ParsedType, 12> TypeVector;
-
- template <class T, unsigned N> inline
- ASTMultiPtr<T> move_arg(ASTOwningVector<T, N> &vec) {
- return ASTMultiPtr<T>(vec.take(), vec.size());
- }
-
- // These versions are hopefully no-ops.
- template <class T, bool C>
- inline ActionResult<T,C> move(ActionResult<T,C> &ptr) {
- return ptr;
- }
-
- template <class T> inline
- ASTMultiPtr<T>& move(ASTMultiPtr<T> &ptr) {
- return ptr;
- }
-
// We can re-use the low bit of expression, statement, base, and
// member-initializer pointers for the "invalid" flag of
// ActionResult.
@@ -438,13 +242,11 @@ namespace clang {
typedef ActionResult<Decl*> DeclResult;
typedef OpaquePtr<TemplateName> ParsedTemplateTy;
- inline Expr *move(Expr *E) { return E; }
- inline Stmt *move(Stmt *S) { return S; }
-
- typedef ASTMultiPtr<Expr*> MultiExprArg;
- typedef ASTMultiPtr<Stmt*> MultiStmtArg;
- typedef ASTMultiPtr<ParsedType> MultiTypeArg;
- typedef ASTMultiPtr<TemplateParameterList*> MultiTemplateParamsArg;
+ typedef llvm::MutableArrayRef<Expr*> MultiExprArg;
+ typedef llvm::MutableArrayRef<Stmt*> MultiStmtArg;
+ typedef llvm::MutableArrayRef<ParsedTemplateArgument> ASTTemplateArgsPtr;
+ typedef llvm::MutableArrayRef<ParsedType> MultiTypeArg;
+ typedef llvm::MutableArrayRef<TemplateParameterList*> MultiTemplateParamsArg;
inline ExprResult ExprError() { return ExprResult(true); }
inline StmtResult StmtError() { return StmtResult(true); }
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 69080ad9b1d7..94db454a8543 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -209,11 +209,6 @@ namespace clang {
/// Retrieves the range of the given template parameter lists.
SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params,
unsigned NumParams);
-
- inline const ParsedTemplateArgument &
- ASTTemplateArgsPtr::operator[](unsigned Arg) const {
- return Args[Arg];
- }
}
#endif
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index b78556e65a6c..fa508cfc22d9 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -82,7 +82,13 @@ public:
SwitchScope = 0x800,
/// TryScope - This is the scope of a C++ try statement.
- TryScope = 0x1000
+ TryScope = 0x1000,
+
+ /// FnTryScope - This is the scope of a function-level C++ try scope.
+ FnTryScope = 0x3000,
+
+ /// FnCatchScope - This is the scope of a function-level C++ catch scope.
+ FnCatchScope = 0x4000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index b4752f5dbb12..feda9c96b857 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -7,7 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines FunctionScopeInfo and BlockScopeInfo.
+// This file defines FunctionScopeInfo and its subclasses, which contain
+// information about a single function, block, lambda, or method body.
//
//===----------------------------------------------------------------------===//
@@ -21,14 +22,20 @@
namespace clang {
+class Decl;
class BlockDecl;
class CXXMethodDecl;
+class ObjCPropertyDecl;
class IdentifierInfo;
class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
class VarDecl;
+class DeclRefExpr;
+class ObjCIvarRefExpr;
+class ObjCPropertyRefExpr;
+class ObjCMessageExpr;
namespace sema {
@@ -84,13 +91,10 @@ public:
/// \brief Whether this function contains any indirect gotos.
bool HasIndirectGoto;
- /// A flag that is set when parsing a -dealloc method and no [super dealloc]
- /// call was found yet.
- bool ObjCShouldCallSuperDealloc;
-
- /// A flag that is set when parsing a -finalize method and no [super finalize]
- /// call was found yet.
- bool ObjCShouldCallSuperFinalize;
+ /// A flag that is set when parsing a method that must call super's
+ /// implementation, such as \c -dealloc, \c -finalize, or any method marked
+ /// with \c __attribute__((objc_requires_super)).
+ bool ObjCShouldCallSuper;
/// \brief Used to determine if errors occurred in this function or block.
DiagnosticErrorTrap ErrorTrap;
@@ -113,6 +117,164 @@ public:
/// prior to being emitted.
SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags;
+public:
+ /// Represents a simple identification of a weak object.
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ ///
+ /// This is used to determine if two weak accesses refer to the same object.
+ /// Here are some examples of how various accesses are "profiled":
+ ///
+ /// Access Expression | "Base" Decl | "Property" Decl
+ /// :---------------: | :-----------------: | :------------------------------:
+ /// self.property | self (VarDecl) | property (ObjCPropertyDecl)
+ /// self.implicitProp | self (VarDecl) | -implicitProp (ObjCMethodDecl)
+ /// self->ivar.prop | ivar (ObjCIvarDecl) | prop (ObjCPropertyDecl)
+ /// cxxObj.obj.prop | obj (FieldDecl) | prop (ObjCPropertyDecl)
+ /// [self foo].prop | 0 (unknown) | prop (ObjCPropertyDecl)
+ /// self.prop1.prop2 | prop1 (ObjCPropertyDecl) | prop2 (ObjCPropertyDecl)
+ /// MyClass.prop | MyClass (ObjCInterfaceDecl) | -prop (ObjCMethodDecl)
+ /// weakVar | 0 (known) | weakVar (VarDecl)
+ /// self->weakIvar | self (VarDecl) | weakIvar (ObjCIvarDecl)
+ ///
+ /// Objects are identified with only two Decls to make it reasonably fast to
+ /// compare them.
+ class WeakObjectProfileTy {
+ /// The base object decl, as described in the class documentation.
+ ///
+ /// The extra flag is "true" if the Base and Property are enough to uniquely
+ /// identify the object in memory.
+ ///
+ /// \sa isExactProfile()
+ typedef llvm::PointerIntPair<const NamedDecl *, 1, bool> BaseInfoTy;
+ BaseInfoTy Base;
+
+ /// The "property" decl, as described in the class documentation.
+ ///
+ /// Note that this may not actually be an ObjCPropertyDecl, e.g. in the
+ /// case of "implicit" properties (regular methods accessed via dot syntax).
+ const NamedDecl *Property;
+
+ /// Used to find the proper base profile for a given base expression.
+ static BaseInfoTy getBaseInfo(const Expr *BaseE);
+
+ // For use in DenseMap.
+ friend class DenseMapInfo;
+ inline WeakObjectProfileTy();
+ static inline WeakObjectProfileTy getSentinel();
+
+ public:
+ WeakObjectProfileTy(const ObjCPropertyRefExpr *RE);
+ WeakObjectProfileTy(const Expr *Base, const ObjCPropertyDecl *Property);
+ WeakObjectProfileTy(const DeclRefExpr *RE);
+ WeakObjectProfileTy(const ObjCIvarRefExpr *RE);
+
+ const NamedDecl *getBase() const { return Base.getPointer(); }
+ const NamedDecl *getProperty() const { return Property; }
+
+ /// Returns true if the object base specifies a known object in memory,
+ /// rather than, say, an instance variable or property of another object.
+ ///
+ /// Note that this ignores the effects of aliasing; that is, \c foo.bar is
+ /// considered an exact profile if \c foo is a local variable, even if
+ /// another variable \c foo2 refers to the same object as \c foo.
+ ///
+ /// For increased precision, accesses with base variables that are
+ /// properties or ivars of 'self' (e.g. self.prop1.prop2) are considered to
+ /// be exact, though this is not true for arbitrary variables
+ /// (foo.prop1.prop2).
+ bool isExactProfile() const {
+ return Base.getInt();
+ }
+
+ bool operator==(const WeakObjectProfileTy &Other) const {
+ return Base == Other.Base && Property == Other.Property;
+ }
+
+ // For use in DenseMap.
+ // We can't specialize the usual llvm::DenseMapInfo at the end of the file
+ // because by that point the DenseMap in FunctionScopeInfo has already been
+ // instantiated.
+ class DenseMapInfo {
+ public:
+ static inline WeakObjectProfileTy getEmptyKey() {
+ return WeakObjectProfileTy();
+ }
+ static inline WeakObjectProfileTy getTombstoneKey() {
+ return WeakObjectProfileTy::getSentinel();
+ }
+
+ static unsigned getHashValue(const WeakObjectProfileTy &Val) {
+ typedef std::pair<BaseInfoTy, const NamedDecl *> Pair;
+ return llvm::DenseMapInfo<Pair>::getHashValue(Pair(Val.Base,
+ Val.Property));
+ }
+
+ static bool isEqual(const WeakObjectProfileTy &LHS,
+ const WeakObjectProfileTy &RHS) {
+ return LHS == RHS;
+ }
+ };
+ };
+
+ /// Represents a single use of a weak object.
+ ///
+ /// Stores both the expression and whether the access is potentially unsafe
+ /// (i.e. it could potentially be warned about).
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ class WeakUseTy {
+ llvm::PointerIntPair<const Expr *, 1, bool> Rep;
+ public:
+ WeakUseTy(const Expr *Use, bool IsRead) : Rep(Use, IsRead) {}
+
+ const Expr *getUseExpr() const { return Rep.getPointer(); }
+ bool isUnsafe() const { return Rep.getInt(); }
+ void markSafe() { Rep.setInt(false); }
+
+ bool operator==(const WeakUseTy &Other) const {
+ return Rep == Other.Rep;
+ }
+ };
+
+ /// Used to collect uses of a particular weak object in a function body.
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ typedef SmallVector<WeakUseTy, 4> WeakUseVector;
+
+ /// Used to collect all uses of weak objects in a function body.
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ typedef llvm::SmallDenseMap<WeakObjectProfileTy, WeakUseVector, 8,
+ WeakObjectProfileTy::DenseMapInfo>
+ WeakObjectUseMap;
+
+private:
+ /// Used to collect all uses of weak objects in this function body.
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ WeakObjectUseMap WeakObjectUses;
+
+public:
+ /// Record that a weak object was accessed.
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ template <typename ExprT>
+ inline void recordUseOfWeak(const ExprT *E, bool IsRead = true);
+
+ void recordUseOfWeak(const ObjCMessageExpr *Msg,
+ const ObjCPropertyDecl *Prop);
+
+ /// Record that a given expression is a "safe" access of a weak object (e.g.
+ /// assigning it to a strong variable.)
+ ///
+ /// Part of the implementation of -Wrepeated-use-of-weak.
+ void markSafeWeakUse(const Expr *E);
+
+ const WeakObjectUseMap &getWeakObjectUses() const {
+ return WeakObjectUses;
+ }
+
void setHasBranchIntoScope() {
HasBranchIntoScope = true;
}
@@ -135,8 +297,7 @@ public:
HasBranchProtectedScope(false),
HasBranchIntoScope(false),
HasIndirectGoto(false),
- ObjCShouldCallSuperDealloc(false),
- ObjCShouldCallSuperFinalize(false),
+ ObjCShouldCallSuper(false),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();
@@ -144,8 +305,6 @@ public:
/// \brief Clear out the information in this function scope, making it
/// suitable for reuse.
void Clear();
-
- static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
class CapturingScopeInfo : public FunctionScopeInfo {
@@ -262,11 +421,7 @@ public:
}
void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
- Expr *Cpy) {
- Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
- Cpy));
- CXXThisCaptureIndex = Captures.size();
- }
+ Expr *Cpy);
/// \brief Determine whether the C++ 'this' is captured.
bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
@@ -299,7 +454,6 @@ public:
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
}
- static bool classof(const CapturingScopeInfo *BSI) { return true; }
};
/// \brief Retains information about a block that is currently being parsed.
@@ -327,7 +481,6 @@ public:
static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Block;
}
- static bool classof(const BlockScopeInfo *BSI) { return true; }
};
class LambdaScopeInfo : public CapturingScopeInfo {
@@ -379,15 +532,42 @@ public:
void finishedExplicitCaptures() {
NumExplicitCaptures = Captures.size();
}
-
- static bool classof(const FunctionScopeInfo *FSI) {
+
+ static bool classof(const FunctionScopeInfo *FSI) {
return FSI->Kind == SK_Lambda;
}
- static bool classof(const LambdaScopeInfo *BSI) { return true; }
-
};
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy()
+ : Base(0, false), Property(0) {}
+
+FunctionScopeInfo::WeakObjectProfileTy
+FunctionScopeInfo::WeakObjectProfileTy::getSentinel() {
+ FunctionScopeInfo::WeakObjectProfileTy Result;
+ Result.Base.setInt(true);
+ return Result;
+}
+
+template <typename ExprT>
+void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) {
+ assert(E);
+ WeakUseVector &Uses = WeakObjectUses[WeakObjectProfileTy(E)];
+ Uses.push_back(WeakUseTy(E, IsRead));
}
+
+inline void
+CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc,
+ QualType CaptureType, Expr *Cpy) {
+ Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
+ Cpy));
+ CXXThisCaptureIndex = Captures.size();
+
+ if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(this))
+ LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
}
+} // end namespace sema
+} // end namespace clang
+
#endif
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index acc88c0578ed..9b572d8b4d70 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -187,9 +187,16 @@ typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
/// Sema - This implements semantic analysis and AST building for C.
class Sema {
- Sema(const Sema&); // DO NOT IMPLEMENT
- void operator=(const Sema&); // DO NOT IMPLEMENT
+ Sema(const Sema &) LLVM_DELETED_FUNCTION;
+ void operator=(const Sema &) LLVM_DELETED_FUNCTION;
mutable const TargetAttributesSema* TheTargetAttributesSema;
+
+ ///\brief Source of additional semantic information.
+ ExternalSemaSource *ExternalSource;
+
+ ///\brief Whether Sema has generated a multiplexer and has to delete it.
+ bool isMultiplexExternalSource;
+
public:
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
typedef OpaquePtr<TemplateName> TemplateTy;
@@ -208,9 +215,6 @@ public:
/// \brief Flag indicating whether or not to collect detailed statistics.
bool CollectStats;
- /// \brief Source of additional semantic information.
- ExternalSemaSource *ExternalSource;
-
/// \brief Code-completion consumer.
CodeCompleteConsumer *CodeCompleter;
@@ -234,6 +238,12 @@ public:
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
+ /// \brief Flag indicating if Sema is building a recovery call expression.
+ ///
+ /// This flag is used to avoid building recovery call expressions
+ /// if Sema is already doing so, which would cause infinite recursions.
+ bool IsBuildingRecoveryCallExpr;
+
/// ExprNeedsCleanups - True if the current evaluation context
/// requires cleanups to be run at its conclusion.
bool ExprNeedsCleanups;
@@ -456,6 +466,26 @@ public:
}
};
+ /// \brief RAII object to handle the state changes required to synthesize
+ /// a function body.
+ class SynthesizedFunctionScope {
+ Sema &S;
+ Sema::ContextRAII SavedContext;
+
+ public:
+ SynthesizedFunctionScope(Sema &S, DeclContext *DC)
+ : S(S), SavedContext(S, DC)
+ {
+ S.PushFunctionScope();
+ S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ }
+
+ ~SynthesizedFunctionScope() {
+ S.PopExpressionEvaluationContext();
+ S.PopFunctionScopeInfo();
+ }
+ };
+
/// WeakUndeclaredIdentifiers - Identifiers contained in
/// \#pragma weak before declared. rare. may alias another
/// identifier, declared or undeclared
@@ -729,6 +759,20 @@ public:
/// should not be used elsewhere.
void EmitCurrentDiagnostic(unsigned DiagID);
+ /// Records and restores the FP_CONTRACT state on entry/exit of compound
+ /// statements.
+ class FPContractStateRAII {
+ public:
+ FPContractStateRAII(Sema& S)
+ : S(S), OldFPContractState(S.FPFeatures.fp_contract) {}
+ ~FPContractStateRAII() {
+ S.FPFeatures.fp_contract = OldFPContractState;
+ }
+ private:
+ Sema& S;
+ bool OldFPContractState : 1;
+ };
+
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind = TU_Complete,
@@ -750,6 +794,14 @@ public:
ASTContext &getASTContext() const { return Context; }
ASTConsumer &getASTConsumer() const { return Consumer; }
ASTMutationListener *getASTMutationListener() const;
+ ExternalSemaSource* getExternalSource() const { return ExternalSource; }
+
+ ///\brief Registers an external source. If an external source already exists,
+ /// creates a multiplex external source and appends to it.
+ ///
+ ///\param[in] E - A non-null external sema source.
+ ///
+ void addExternalSource(ExternalSemaSource *E);
void PrintStats() const;
@@ -1203,7 +1255,7 @@ public:
assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template;
}
-};
+ };
/// \brief Perform name lookup on the given name, classifying it based on
/// the results of name lookup and the following token.
@@ -1223,11 +1275,19 @@ public:
///
/// \param NextToken The token following the identifier. Used to help
/// disambiguate the name.
+ ///
+ /// \param IsAddressOfOperand True if this name is the operand of a unary
+ /// address of ('&') expression, assuming it is classified as an
+ /// expression.
+ ///
+ /// \param CCC The correction callback, if typo correction is desired.
NameClassification ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc,
- const Token &NextToken);
+ const Token &NextToken,
+ bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC = 0);
Decl *ActOnDeclarator(Scope *S, Declarator &D);
@@ -1265,6 +1325,7 @@ public:
MultiTemplateParamsArg TemplateParamLists,
bool &AddToScope);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
+ void checkVoidParamDecl(ParmVarDecl *Param);
bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
@@ -1293,7 +1354,6 @@ public:
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
SourceLocation EqualLoc);
- void CheckSelfReference(Decl *OrigDecl, Expr *E);
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit,
bool TypeMayContainAuto);
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
@@ -1642,7 +1702,7 @@ public:
/// \brief Checks availability of the function depending on the current
/// function context.Inside an unavailable function,unavailability is ignored.
///
- /// \returns true if \arg FD is unavailable and current context is inside
+ /// \returns true if \p FD is unavailable and current context is inside
/// an available function, false otherwise.
bool isFunctionConsideredUnavailable(FunctionDecl *FD);
@@ -1866,8 +1926,7 @@ public:
llvm::ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
- bool PartialOverloading = false,
- bool StdNamespaceIsAssociated = false);
+ bool PartialOverloading = false);
// Emit as a 'note' the specific overload candidate
void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType());
@@ -1916,6 +1975,30 @@ public:
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
+ // An enum used to represent the different possible results of building a
+ // range-based for loop.
+ enum ForRangeStatus {
+ FRS_Success,
+ FRS_NoViableFunction,
+ FRS_DiagnosticIssued
+ };
+
+ // An enum to represent whether something is dealing with a call to begin()
+ // or a call to end() in a range-based for loop.
+ enum BeginEndFunction {
+ BEF_begin,
+ BEF_end
+ };
+
+ ForRangeStatus BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
+ SourceLocation RangeLoc,
+ VarDecl *Decl,
+ BeginEndFunction BEF,
+ const DeclarationNameInfo &NameInfo,
+ LookupResult &MemberLookup,
+ OverloadCandidateSet *CandidateSet,
+ Expr *Range, ExprResult *CallExpr);
+
ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
@@ -1924,6 +2007,12 @@ public:
Expr *ExecConfig,
bool AllowTypoCorrection=true);
+ bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ OverloadCandidateSet *CandidateSet,
+ ExprResult *Result);
+
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
const UnresolvedSetImpl &Fns,
@@ -2130,8 +2219,7 @@ public:
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
SourceLocation Loc,
llvm::ArrayRef<Expr *> Args,
- ADLResult &Functions,
- bool StdNamespaceIsAssociated = false);
+ ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
@@ -2148,7 +2236,8 @@ public:
bool EnteringContext = false,
const ObjCObjectPointerType *OPT = 0);
- void FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args,
+ void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
+ llvm::ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
@@ -2249,13 +2338,7 @@ public:
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap);
-
-
- /// LookupPropertyDecl - Looks up a property in the current class and all
- /// its protocols.
- ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
- IdentifierInfo *II);
-
+
/// Called by ActOnProperty to handle \@property declarations in
/// class extensions.
Decl *HandlePropertyInClassExtension(Scope *S,
@@ -2399,7 +2482,7 @@ public:
FullExprArg(const FullExprArg& Other) : E(Other.E) {}
ExprResult release() {
- return move(E);
+ return E;
}
Expr *get() const { return E; }
@@ -2502,15 +2585,28 @@ public:
SourceLocation RParenLoc);
StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body);
+ enum BuildForRangeKind {
+ /// Initial building of a for-range statement.
+ BFRK_Build,
+ /// Instantiation or recovery rebuild of a for-range statement. Don't
+ /// attempt any typo-correction.
+ BFRK_Rebuild,
+ /// Determining whether a for-range statement could be built. Avoid any
+ /// unnecessary or irreversible actions.
+ BFRK_Check
+ };
+
StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *LoopVar,
SourceLocation ColonLoc, Expr *Collection,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ BuildForRangeKind Kind);
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *BeginEndDecl,
Expr *Cond, Expr *Inc,
Stmt *LoopVarDecl,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ BuildForRangeKind Kind);
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);
StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
@@ -2528,21 +2624,19 @@ public:
StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
- StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
- bool IsSimple, bool IsVolatile,
- unsigned NumOutputs, unsigned NumInputs,
- IdentifierInfo **Names,
- MultiExprArg Constraints,
- MultiExprArg Exprs,
- Expr *AsmString,
- MultiExprArg Clobbers,
- SourceLocation RParenLoc,
- bool MSAsm = false);
+ StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ MultiExprArg Constraints, MultiExprArg Exprs,
+ Expr *AsmString, MultiExprArg Clobbers,
+ SourceLocation RParenLoc);
- StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc,
- SourceLocation LBraceLoc,
- ArrayRef<Token> AsmToks,
- SourceLocation EndLoc);
+ NamedDecl *LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
+ unsigned &Size);
+ bool LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset, SourceLocation AsmLoc);
+ StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
+ ArrayRef<Token> AsmToks, SourceLocation EndLoc);
VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
SourceLocation StartLoc,
@@ -2639,7 +2733,8 @@ public:
void EmitDeprecationWarning(NamedDecl *D, StringRef Message,
SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass=0);
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty);
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
@@ -2663,7 +2758,10 @@ public:
void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl = 0,
bool IsDecltype = false);
-
+ enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl };
+ void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ ReuseLambdaContextDecl_t,
+ bool IsDecltype = false);
void PopExpressionEvaluationContext();
void DiscardCleanupsInEvaluationContext();
@@ -2815,7 +2913,8 @@ public:
bool HasTrailingLParen);
ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo);
+ const DeclarationNameInfo &NameInfo,
+ bool IsAddressOfOperand);
ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
@@ -3279,18 +3378,11 @@ public:
// Pointer to allow copying
Sema *Self;
// We order exception specifications thus:
- // noexcept is the most restrictive, but is only used in C++0x.
+ // noexcept is the most restrictive, but is only used in C++11.
// throw() comes next.
// Then a throw(collected exceptions)
- // Finally no specification.
+ // Finally no specification, which is expressed as noexcept(false).
// throw(...) is used instead if any called function uses it.
- //
- // If this exception specification cannot be known yet (for instance,
- // because this is the exception specification for a defaulted default
- // constructor and we haven't finished parsing the deferred parts of the
- // class yet), the C++0x standard does not specify how to behave. We
- // record this as an 'unknown' exception specification, which overrules
- // any other specification (even 'none', to keep this rule simple).
ExceptionSpecificationType ComputedEST;
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
SmallVector<QualType, 4> Exceptions;
@@ -3330,8 +3422,17 @@ public:
/// computed exception specification.
void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const {
EPI.ExceptionSpecType = getExceptionSpecType();
- EPI.NumExceptions = size();
- EPI.Exceptions = data();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = size();
+ EPI.Exceptions = data();
+ } else if (EPI.ExceptionSpecType == EST_None) {
+ /// C++11 [except.spec]p14:
+ /// The exception-specification is noexcept(false) if the set of
+ /// potential exceptions of the special member function contains "any"
+ EPI.ExceptionSpecType = EST_ComputedNoexcept;
+ EPI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(),
+ tok::kw_false).take();
+ }
}
FunctionProtoType::ExtProtoInfo getEPI() const {
FunctionProtoType::ExtProtoInfo EPI;
@@ -3515,7 +3616,7 @@ public:
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
- ASTOwningVector<Expr*> &ConvertedArgs,
+ SmallVectorImpl<Expr*> &ConvertedArgs,
bool AllowExplicit = false);
ParsedType getDestructorName(SourceLocation TildeLoc,
@@ -3661,7 +3762,7 @@ public:
SourceLocation PlacementRParen,
SourceRange TypeIdParens, Declarator &D,
Expr *Initializer);
- ExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
+ ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -3991,7 +4092,8 @@ public:
/// \brief Create a new lambda closure type.
CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
- bool KnownDependent = false);
+ TypeSourceInfo *Info,
+ bool KnownDependent);
/// \brief Start the definition of a lambda expression.
CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
@@ -4300,7 +4402,7 @@ public:
SourceLocation RParenLoc,
bool Failed);
- FriendDecl *CheckFriendTypeDecl(SourceLocation Loc,
+ FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo);
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
@@ -4622,8 +4724,6 @@ public:
/// \brief Parsed an elaborated-type-specifier that refers to a template-id,
/// such as \c class T::template apply<U>.
- ///
- /// \param TUK
TypeResult ActOnTagTemplateIdType(TagUseKind TUK,
TypeSpecifierType TagSpec,
SourceLocation TagLoc,
@@ -4799,7 +4899,8 @@ public:
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
- const TemplateArgumentLoc &Arg);
+ const TemplateArgumentLoc &Arg,
+ unsigned ArgumentPackIndex);
ExprResult
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
@@ -5246,6 +5347,8 @@ public:
enum TemplateDeductionResult {
/// \brief Template argument deduction was successful.
TDK_Success = 0,
+ /// \brief The declaration was invalid; do nothing.
+ TDK_Invalid,
/// \brief Template argument deduction exceeded the maximum template
/// instantiation depth (which has already been diagnosed).
TDK_InstantiationDepth,
@@ -5681,10 +5784,10 @@ public:
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
- InstantiatingTemplate(const InstantiatingTemplate&); // not implemented
+ InstantiatingTemplate(const InstantiatingTemplate&) LLVM_DELETED_FUNCTION;
InstantiatingTemplate&
- operator=(const InstantiatingTemplate&); // not implemented
+ operator=(const InstantiatingTemplate&) LLVM_DELETED_FUNCTION;
};
void PrintInstantiationStack();
@@ -6016,7 +6119,7 @@ public:
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
- /// be modified to be consistent with \arg PropertyTy.
+ /// be modified to be consistent with \p PropertyTy.
void CheckObjCPropertyAttributes(Decl *PropertyPtrTy,
SourceLocation Loc,
unsigned &Attributes,
@@ -6252,8 +6355,7 @@ public:
/// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align.
void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
- SourceLocation PragmaLoc,
- SourceLocation KindLoc);
+ SourceLocation PragmaLoc);
enum PragmaPackKind {
PPK_Default, // #pragma pack([n])
@@ -6748,6 +6850,7 @@ public:
/// might create an obvious retain cycle.
void checkRetainCycles(ObjCMessageExpr *msg);
void checkRetainCycles(Expr *receiver, Expr *argument);
+ void checkRetainCycles(VarDecl *Var, Expr *Init);
/// checkUnsafeAssigns - Check whether +1 expr is being assigned
/// to weak/__unsafe_unretained type.
@@ -6763,6 +6866,7 @@ public:
/// \return true iff there were any incompatible types.
bool CheckMessageArgumentTypes(QualType ReceiverType,
Expr **Args, unsigned NumArgs, Selector Sel,
+ ArrayRef<SourceLocation> SelectorLocs,
ObjCMethodDecl *Method, bool isClassMessage,
bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
@@ -7210,6 +7314,14 @@ public:
}
AvailabilityResult getCurContextAvailability() const;
+
+ const DeclContext *getCurObjCLexicalContext() const {
+ const DeclContext *DC = getCurLexicalContext();
+ // A category implicitly has the attribute of the interface.
+ if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(DC))
+ DC = CatD->getClassInterface();
+ return DC;
+ }
};
/// \brief RAII object that enters a new expression evaluation context.
@@ -7225,6 +7337,15 @@ public:
Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl,
IsDecltype);
}
+ EnterExpressionEvaluationContext(Sema &Actions,
+ Sema::ExpressionEvaluationContext NewContext,
+ Sema::ReuseLambdaContextDecl_t,
+ bool IsDecltype = false)
+ : Actions(Actions) {
+ Actions.PushExpressionEvaluationContext(NewContext,
+ Sema::ReuseLambdaContextDecl,
+ IsDecltype);
+ }
~EnterExpressionEvaluationContext() {
Actions.PopExpressionEvaluationContext();
diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h
index 139cce8d7365..676646afbd59 100644
--- a/include/clang/Sema/SemaConsumer.h
+++ b/include/clang/Sema/SemaConsumer.h
@@ -42,7 +42,6 @@ namespace clang {
static bool classof(const ASTConsumer *Consumer) {
return Consumer->SemaConsumer;
}
- static bool classof(const SemaConsumer *) { return true; }
};
}
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 273374dfd8b0..bbccd259678a 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -239,8 +239,9 @@ namespace clang {
unsigned NumArgsInPartiallySubstitutedPack;
// This class is non-copyable
- LocalInstantiationScope(const LocalInstantiationScope &);
- LocalInstantiationScope &operator=(const LocalInstantiationScope &);
+ LocalInstantiationScope(
+ const LocalInstantiationScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const LocalInstantiationScope &) LLVM_DELETED_FUNCTION;
public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 4c2d876d1f87..251a65990b3b 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -19,7 +19,6 @@
namespace clang {
-class ASTContext;
class TemplateArgumentList;
namespace sema {
@@ -28,9 +27,6 @@ namespace sema {
/// deduction, whose success or failure was described by a
/// TemplateDeductionResult value.
class TemplateDeductionInfo {
- /// \brief The context in which the template arguments are stored.
- ASTContext &Context;
-
/// \brief The deduced template argument list.
///
TemplateArgumentList *Deduced;
@@ -46,17 +42,12 @@ class TemplateDeductionInfo {
/// SFINAE while performing template argument deduction.
SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
- // do not implement these
- TemplateDeductionInfo(const TemplateDeductionInfo&);
- TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
+ TemplateDeductionInfo(const TemplateDeductionInfo &) LLVM_DELETED_FUNCTION;
+ void operator=(const TemplateDeductionInfo &) LLVM_DELETED_FUNCTION;
public:
- TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc)
- : Context(Context), Deduced(0), Loc(Loc), HasSFINAEDiagnostic(false) { }
-
- ~TemplateDeductionInfo() {
- // FIXME: if (Deduced) Deduced->Destroy(Context);
- }
+ TemplateDeductionInfo(SourceLocation Loc)
+ : Deduced(0), Loc(Loc), HasSFINAEDiagnostic(false) { }
/// \brief Returns the location at which template argument is
/// occurring.
@@ -83,7 +74,6 @@ public:
/// \brief Provide a new template argument list that contains the
/// results of template argument deduction.
void reset(TemplateArgumentList *NewDeduced) {
- // FIXME: if (Deduced) Deduced->Destroy(Context);
Deduced = NewDeduced;
}
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index a8f6e1178b72..2b4a9e62167b 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -170,6 +170,17 @@ public:
return CorrectionDecls.size() > 1;
}
+ void setCorrectionRange(CXXScopeSpec* SS,
+ const DeclarationNameInfo &TypoName) {
+ CorrectionRange.setBegin(CorrectionNameSpec && SS ? SS->getBeginLoc()
+ : TypoName.getLoc());
+ CorrectionRange.setEnd(TypoName.getLoc());
+ }
+
+ SourceRange getCorrectionRange() const {
+ return CorrectionRange;
+ }
+
typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
decl_iterator begin() {
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
@@ -193,6 +204,7 @@ private:
unsigned CharDistance;
unsigned QualifierDistance;
unsigned CallbackDistance;
+ SourceRange CorrectionRange;
};
/// @brief Base class for callback objects used by Sema::CorrectTypo to check
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index dbe6e5a31440..8c58fb281662 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -126,7 +126,13 @@ namespace clang {
/// \brief The number of predefined identifier IDs.
const unsigned int NUM_PREDEF_IDENT_IDS = 1;
+
+ /// \brief An ID number that refers to a macro in an AST file.
+ typedef uint32_t MacroID;
+ /// \brief The number of predefined macro IDs.
+ const unsigned int NUM_PREDEF_MACRO_IDS = 1;
+
/// \brief An ID number that refers to an ObjC selector in an AST file.
typedef uint32_t SelectorID;
@@ -210,7 +216,71 @@ namespace clang {
SUBMODULE_BLOCK_ID,
/// \brief The block containing comments.
- COMMENTS_BLOCK_ID
+ COMMENTS_BLOCK_ID,
+
+ /// \brief The control block, which contains all of the
+ /// information that needs to be validated prior to committing
+ /// to loading the AST file.
+ CONTROL_BLOCK_ID,
+
+ /// \brief The block of input files, which were used as inputs
+ /// to create this AST file.
+ ///
+ /// This block is part of the control block.
+ INPUT_FILES_BLOCK_ID
+ };
+
+ /// \brief Record types that occur within the control block.
+ enum ControlRecordTypes {
+ /// \brief AST file metadata, including the AST file version number
+ /// and information about the compiler used to build this AST file.
+ METADATA = 1,
+
+ /// \brief Record code for the list of other AST files imported by
+ /// this AST file.
+ IMPORTS = 2,
+
+ /// \brief Record code for the language options table.
+ ///
+ /// The record with this code contains the contents of the
+ /// LangOptions structure. We serialize the entire contents of
+ /// the structure, and let the reader decide which options are
+ /// actually important to check.
+ LANGUAGE_OPTIONS = 3,
+
+ /// \brief Record code for the target options table.
+ TARGET_OPTIONS = 4,
+
+ /// \brief Record code for the original file that was used to
+ /// generate the AST file, including both its file ID and its
+ /// name.
+ ORIGINAL_FILE = 5,
+
+ /// \brief The directory that the PCH was originally created in.
+ ORIGINAL_PCH_DIR = 6,
+
+ /// \brief Offsets into the input-files block where input files
+ /// reside.
+ INPUT_FILE_OFFSETS = 7,
+
+ /// \brief Record code for the diagnostic options table.
+ DIAGNOSTIC_OPTIONS = 8,
+
+ /// \brief Record code for the filesystem options table.
+ FILE_SYSTEM_OPTIONS = 9,
+
+ /// \brief Record code for the headers search options table.
+ HEADER_SEARCH_OPTIONS = 10,
+
+ /// \brief Record code for the preprocessor options table.
+ PREPROCESSOR_OPTIONS = 11
+ };
+
+ /// \brief Record types that occur within the input-files block
+ /// inside the control block.
+ enum InputFileRecordTypes {
+ /// \brief An input file.
+ INPUT_FILE = 1
};
/// \brief Record types that occur within the AST block itself.
@@ -241,25 +311,13 @@ namespace clang {
/// reserved for the translation unit declaration.
DECL_OFFSET = 2,
- /// \brief Record code for the language options table.
- ///
- /// The record with this code contains the contents of the
- /// LangOptions structure. We serialize the entire contents of
- /// the structure, and let the reader decide which options are
- /// actually important to check.
- LANGUAGE_OPTIONS = 3,
-
- /// \brief AST file metadata, including the AST file version number
- /// and the target triple used to build the AST file.
- METADATA = 4,
-
/// \brief Record code for the table of offsets of each
/// identifier ID.
///
/// The offset table contains offsets into the blob stored in
/// the IDENTIFIER_TABLE record. Each offset points to the
/// NULL-terminated string that corresponds to that identifier.
- IDENTIFIER_OFFSET = 5,
+ IDENTIFIER_OFFSET = 3,
/// \brief Record code for the identifier table.
///
@@ -273,7 +331,7 @@ namespace clang {
/// between offsets (for unresolved identifier IDs) and
/// IdentifierInfo pointers (for already-resolved identifier
/// IDs).
- IDENTIFIER_TABLE = 6,
+ IDENTIFIER_TABLE = 4,
/// \brief Record code for the array of external definitions.
///
@@ -283,7 +341,7 @@ namespace clang {
/// reported to the AST consumer after the AST file has been
/// read, since their presence can affect the semantics of the
/// program (e.g., for code generation).
- EXTERNAL_DEFINITIONS = 7,
+ EXTERNAL_DEFINITIONS = 5,
/// \brief Record code for the set of non-builtin, special
/// types.
@@ -292,33 +350,33 @@ namespace clang {
/// that are constructed during semantic analysis (e.g.,
/// __builtin_va_list). The SPECIAL_TYPE_* constants provide
/// offsets into this record.
- SPECIAL_TYPES = 8,
+ SPECIAL_TYPES = 6,
/// \brief Record code for the extra statistics we gather while
/// generating an AST file.
- STATISTICS = 9,
+ STATISTICS = 7,
/// \brief Record code for the array of tentative definitions.
- TENTATIVE_DEFINITIONS = 10,
+ TENTATIVE_DEFINITIONS = 8,
/// \brief Record code for the array of locally-scoped external
/// declarations.
- LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
+ LOCALLY_SCOPED_EXTERNAL_DECLS = 9,
/// \brief Record code for the table of offsets into the
/// Objective-C method pool.
- SELECTOR_OFFSETS = 12,
+ SELECTOR_OFFSETS = 10,
/// \brief Record code for the Objective-C method pool,
- METHOD_POOL = 13,
+ METHOD_POOL = 11,
/// \brief The value of the next __COUNTER__ to dispense.
/// [PP_COUNTER_VALUE, Val]
- PP_COUNTER_VALUE = 14,
+ PP_COUNTER_VALUE = 12,
/// \brief Record code for the table of offsets into the block
/// of source-location information.
- SOURCE_LOCATION_OFFSETS = 15,
+ SOURCE_LOCATION_OFFSETS = 13,
/// \brief Record code for the set of source location entries
/// that need to be preloaded by the AST reader.
@@ -326,153 +384,138 @@ namespace clang {
/// This set contains the source location entry for the
/// predefines buffer and for any file entries that need to be
/// preloaded.
- SOURCE_LOCATION_PRELOADS = 16,
-
- /// \brief Record code for the stat() cache.
- STAT_CACHE = 17,
+ SOURCE_LOCATION_PRELOADS = 14,
/// \brief Record code for the set of ext_vector type names.
- EXT_VECTOR_DECLS = 18,
-
- /// \brief Record code for the original file that was used to
- /// generate the AST file.
- ORIGINAL_FILE_NAME = 19,
-
- /// \brief Record code for the file ID of the original file used to
- /// generate the AST file.
- ORIGINAL_FILE_ID = 20,
-
- /// \brief Record code for the version control branch and revision
- /// information of the compiler used to build this AST file.
- VERSION_CONTROL_BRANCH_REVISION = 21,
+ EXT_VECTOR_DECLS = 16,
/// \brief Record code for the array of unused file scoped decls.
- UNUSED_FILESCOPED_DECLS = 22,
+ UNUSED_FILESCOPED_DECLS = 17,
/// \brief Record code for the table of offsets to entries in the
/// preprocessing record.
- PPD_ENTITIES_OFFSETS = 23,
+ PPD_ENTITIES_OFFSETS = 18,
/// \brief Record code for the array of VTable uses.
- VTABLE_USES = 24,
+ VTABLE_USES = 19,
/// \brief Record code for the array of dynamic classes.
- DYNAMIC_CLASSES = 25,
-
- /// \brief Record code for the list of other AST files imported by
- /// this AST file.
- IMPORTS = 26,
+ DYNAMIC_CLASSES = 20,
/// \brief Record code for referenced selector pool.
- REFERENCED_SELECTOR_POOL = 27,
+ REFERENCED_SELECTOR_POOL = 21,
/// \brief Record code for an update to the TU's lexically contained
/// declarations.
- TU_UPDATE_LEXICAL = 28,
+ TU_UPDATE_LEXICAL = 22,
/// \brief Record code for the array describing the locations (in the
/// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by
/// the first known ID.
- LOCAL_REDECLARATIONS_MAP = 29,
+ LOCAL_REDECLARATIONS_MAP = 23,
/// \brief Record code for declarations that Sema keeps references of.
- SEMA_DECL_REFS = 30,
+ SEMA_DECL_REFS = 24,
/// \brief Record code for weak undeclared identifiers.
- WEAK_UNDECLARED_IDENTIFIERS = 31,
+ WEAK_UNDECLARED_IDENTIFIERS = 25,
/// \brief Record code for pending implicit instantiations.
- PENDING_IMPLICIT_INSTANTIATIONS = 32,
+ PENDING_IMPLICIT_INSTANTIATIONS = 26,
/// \brief Record code for a decl replacement block.
///
/// If a declaration is modified after having been deserialized, and then
/// written to a dependent AST file, its ID and offset must be added to
/// the replacement block.
- DECL_REPLACEMENTS = 33,
+ DECL_REPLACEMENTS = 27,
/// \brief Record code for an update to a decl context's lookup table.
///
/// In practice, this should only be used for the TU and namespaces.
- UPDATE_VISIBLE = 34,
+ UPDATE_VISIBLE = 28,
/// \brief Record for offsets of DECL_UPDATES records for declarations
/// that were modified after being deserialized and need updates.
- DECL_UPDATE_OFFSETS = 35,
+ DECL_UPDATE_OFFSETS = 29,
/// \brief Record of updates for a declaration that was modified after
/// being deserialized.
- DECL_UPDATES = 36,
+ DECL_UPDATES = 30,
/// \brief Record code for the table of offsets to CXXBaseSpecifier
/// sets.
- CXX_BASE_SPECIFIER_OFFSETS = 37,
+ CXX_BASE_SPECIFIER_OFFSETS = 31,
/// \brief Record code for \#pragma diagnostic mappings.
- DIAG_PRAGMA_MAPPINGS = 38,
+ DIAG_PRAGMA_MAPPINGS = 32,
/// \brief Record code for special CUDA declarations.
- CUDA_SPECIAL_DECL_REFS = 39,
+ CUDA_SPECIAL_DECL_REFS = 33,
/// \brief Record code for header search information.
- HEADER_SEARCH_TABLE = 40,
-
- /// \brief The directory that the PCH was originally created in.
- ORIGINAL_PCH_DIR = 41,
+ HEADER_SEARCH_TABLE = 34,
/// \brief Record code for floating point \#pragma options.
- FP_PRAGMA_OPTIONS = 42,
+ FP_PRAGMA_OPTIONS = 35,
/// \brief Record code for enabled OpenCL extensions.
- OPENCL_EXTENSIONS = 43,
+ OPENCL_EXTENSIONS = 36,
/// \brief The list of delegating constructor declarations.
- DELEGATING_CTORS = 44,
+ DELEGATING_CTORS = 37,
- /// \brief Record code for the table of offsets into the block
- /// of file source-location information.
- FILE_SOURCE_LOCATION_OFFSETS = 45,
-
/// \brief Record code for the set of known namespaces, which are used
/// for typo correction.
- KNOWN_NAMESPACES = 46,
+ KNOWN_NAMESPACES = 38,
/// \brief Record code for the remapping information used to relate
/// loaded modules to the various offsets and IDs(e.g., source location
/// offests, declaration and type IDs) that are used in that module to
/// refer to other modules.
- MODULE_OFFSET_MAP = 47,
+ MODULE_OFFSET_MAP = 39,
/// \brief Record code for the source manager line table information,
/// which stores information about \#line directives.
- SOURCE_MANAGER_LINE_TABLE = 48,
+ SOURCE_MANAGER_LINE_TABLE = 40,
/// \brief Record code for map of Objective-C class definition IDs to the
/// ObjC categories in a module that are attached to that class.
- OBJC_CATEGORIES_MAP = 49,
+ OBJC_CATEGORIES_MAP = 41,
/// \brief Record code for a file sorted array of DeclIDs in a module.
- FILE_SORTED_DECLS = 50,
+ FILE_SORTED_DECLS = 42,
/// \brief Record code for an array of all of the (sub)modules that were
/// imported by the AST file.
- IMPORTED_MODULES = 51,
+ IMPORTED_MODULES = 43,
/// \brief Record code for the set of merged declarations in an AST file.
- MERGED_DECLARATIONS = 52,
+ MERGED_DECLARATIONS = 44,
/// \brief Record code for the array of redeclaration chains.
///
/// This array can only be interpreted properly using the local
/// redeclarations map.
- LOCAL_REDECLARATIONS = 53,
+ LOCAL_REDECLARATIONS = 45,
/// \brief Record code for the array of Objective-C categories (including
/// extensions).
///
/// This array can only be interpreted properly using the Objective-C
/// categories map.
- OBJC_CATEGORIES = 54
+ OBJC_CATEGORIES = 46,
+
+ /// \brief Record code for the table of offsets of each macro ID.
+ ///
+ /// The offset table contains offsets into the blob stored in
+ /// the preprocessor block. Each offset points to the corresponding
+ /// macro definition.
+ MACRO_OFFSET = 47,
+
+ /// \brief Record of updates for a macro that was modified after
+ /// being deserialized.
+ MACRO_UPDATES = 48
};
/// \brief Record types used within a source manager block.
@@ -537,16 +580,21 @@ namespace clang {
SUBMODULE_UMBRELLA_HEADER = 2,
/// \brief Specifies a header that falls into this (sub)module.
SUBMODULE_HEADER = 3,
+ /// \brief Specifies a top-level header that falls into this (sub)module.
+ SUBMODULE_TOPHEADER = 4,
/// \brief Specifies an umbrella directory.
- SUBMODULE_UMBRELLA_DIR = 4,
+ SUBMODULE_UMBRELLA_DIR = 5,
/// \brief Specifies the submodules that are imported by this
/// submodule.
- SUBMODULE_IMPORTS = 5,
+ SUBMODULE_IMPORTS = 6,
/// \brief Specifies the submodules that are re-exported from this
/// submodule.
- SUBMODULE_EXPORTS = 6,
+ SUBMODULE_EXPORTS = 7,
/// \brief Specifies a required feature.
- SUBMODULE_REQUIRES = 7
+ SUBMODULE_REQUIRES = 8,
+ /// \brief Specifies a header that has been explicitly excluded
+ /// from this submodule.
+ SUBMODULE_EXCLUDED_HEADER = 9
};
/// \brief Record types used within a comments block.
@@ -642,7 +690,9 @@ namespace clang {
/// \brief The pseudo-object placeholder type.
PREDEF_TYPE_PSEUDO_OBJECT = 35,
/// \brief The __va_list_tag placeholder type.
- PREDEF_TYPE_VA_LIST_TAG = 36
+ PREDEF_TYPE_VA_LIST_TAG = 36,
+ /// \brief The placeholder type for builtin functions.
+ PREDEF_TYPE_BUILTIN_FN = 37
};
/// \brief The number of predefined type IDs that are reserved for
@@ -943,6 +993,9 @@ namespace clang {
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
/// non-type template parameter pack.
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
+ /// \brief A TemplateTemplateParmDecl record that stores an expanded
+ /// template template parameter pack.
+ DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK,
/// \brief A ClassScopeFunctionSpecializationDecl record a class scope
/// function specialization. (Microsoft extension).
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
@@ -999,8 +1052,10 @@ namespace clang {
STMT_RETURN,
/// \brief A DeclStmt record.
STMT_DECL,
- /// \brief An AsmStmt record.
- STMT_ASM,
+ /// \brief A GCC-style AsmStmt record.
+ STMT_GCCASM,
+ /// \brief A MS-style AsmStmt record.
+ STMT_MSASM,
/// \brief A PredefinedExpr record.
EXPR_PREDEFINED,
/// \brief A DeclRefExpr record.
@@ -1186,6 +1241,7 @@ namespace clang {
EXPR_SIZEOF_PACK, // SizeOfPackExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
+ EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
// CUDA
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index ab0d313a5c84..0218129fb625 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -23,6 +23,7 @@ class Decl;
class ASTReader;
class QualType;
class MacroDefinition;
+class MacroInfo;
class Module;
class ASTDeserializationListener {
@@ -37,6 +38,8 @@ public:
/// \brief An identifier was deserialized from the AST file.
virtual void IdentifierRead(serialization::IdentID ID,
IdentifierInfo *II) { }
+ /// \brief A macro was read from the AST file.
+ virtual void MacroRead(serialization::MacroID ID, MacroInfo *MI) { }
/// \brief A type was deserialized from the AST file. The ID here has the
/// qualifier bits already removed, and T is guaranteed to be locally
/// unqualified.
@@ -48,9 +51,6 @@ public:
/// \brief A macro definition was read from the AST file.
virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
MacroDefinition *MD) { }
- /// \brief A macro definition that had previously been deserialized
- /// (and removed via IdentifierRead) has now been made visible.
- virtual void MacroVisible(IdentifierInfo *II) { }
/// \brief A module definition was read from the AST file.
virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) { }
};
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index f0b727531a57..e23ea5cca7e5 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -24,6 +24,7 @@
#include "clang/AST/TemplateBase.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PPMutationListener.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
@@ -33,6 +34,7 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
@@ -61,6 +63,7 @@ class ASTUnit; // FIXME: Layering violation and egregious hack.
class Attr;
class Decl;
class DeclContext;
+class DiagnosticOptions;
class NestedNameSpecifier;
class CXXBaseSpecifier;
class CXXConstructorDecl;
@@ -70,6 +73,7 @@ class MacroDefinition;
class NamedDecl;
class OpaqueValueExpr;
class Preprocessor;
+class PreprocessorOptions;
class Sema;
class SwitchCase;
class ASTDeserializationListener;
@@ -80,15 +84,7 @@ class ASTStmtReader;
class TypeLocReader;
struct HeaderFileInfo;
class VersionTuple;
-
-struct PCHPredefinesBlock {
- /// \brief The file ID for this predefines buffer in a PCH file.
- FileID BufferID;
-
- /// \brief This predefines buffer in a PCH file.
- StringRef Data;
-};
-typedef SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
+class TargetOptions;
/// \brief Abstract interface for callback invocations by the ASTReader.
///
@@ -103,32 +99,58 @@ public:
/// \brief Receives the language options.
///
/// \returns true to indicate the options are invalid or false otherwise.
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
return false;
}
- /// \brief Receives the target triple.
+ /// \brief Receives the target options.
///
- /// \returns true to indicate the target triple is invalid or false otherwise.
- virtual bool ReadTargetTriple(StringRef Triple) {
+ /// \returns true to indicate the target options are invalid, or false
+ /// otherwise.
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
return false;
}
- /// \brief Receives the contents of the predefines buffer.
+ /// \brief Receives the diagnostic options.
///
- /// \param Buffers Information about the predefines buffers.
+ /// \returns true to indicate the diagnostic options are invalid, or false
+ /// otherwise.
+ virtual bool ReadDiagnosticOptions(const DiagnosticOptions &DiagOpts,
+ bool Complain) {
+ return false;
+ }
+
+ /// \brief Receives the file system options.
///
- /// \param OriginalFileName The original file name for the AST file, which
- /// will appear as an entry in the predefines buffer.
+ /// \returns true to indicate the file system options are invalid, or false
+ /// otherwise.
+ virtual bool ReadFileSystemOptions(const FileSystemOptions &FSOpts,
+ bool Complain) {
+ return false;
+ }
+
+ /// \brief Receives the header search options.
+ ///
+ /// \returns true to indicate the header search options are invalid, or false
+ /// otherwise.
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ bool Complain) {
+ return false;
+ }
+
+ /// \brief Receives the preprocessor options.
///
- /// \param SuggestedPredefines If necessary, additional definitions are added
- /// here.
+ /// \param SuggestedPredefines Can be filled in with the set of predefines
+ /// that are suggested by the preprocessor options. Typically only used when
+ /// loading a precompiled header.
///
- /// \returns true to indicate the predefines are invalid or false otherwise.
- virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr) {
+ /// \returns true to indicate the preprocessor options are invalid, or false
+ /// otherwise.
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
return false;
}
@@ -136,7 +158,8 @@ public:
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {}
/// \brief Receives __COUNTER__ value.
- virtual void ReadCounter(unsigned Value) {}
+ virtual void ReadCounter(const serialization::ModuleFile &M,
+ unsigned Value) {}
};
/// \brief ASTReaderListener implementation to validate the information of
@@ -151,14 +174,15 @@ public:
PCHValidator(Preprocessor &PP, ASTReader &Reader)
: PP(PP), Reader(Reader), NumHeaderInfos(0) {}
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
- virtual bool ReadTargetTriple(StringRef Triple);
- virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr);
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain);
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain);
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines);
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
- virtual void ReadCounter(unsigned Value);
+ virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value);
private:
void Error(const char *Msg);
@@ -201,7 +225,26 @@ class ASTReader
public:
typedef SmallVector<uint64_t, 64> RecordData;
- enum ASTReadResult { Success, Failure, IgnorePCH };
+ /// \brief The result of reading the control block of an AST file, which
+ /// can fail for various reasons.
+ enum ASTReadResult {
+ /// \brief The control block was read successfully. Aside from failures,
+ /// the AST file is safe to read into the current context.
+ Success,
+ /// \brief The AST file itself appears corrupted.
+ Failure,
+ /// \brief The AST file is out-of-date relative to its input files,
+ /// and needs to be regenerated.
+ OutOfDate,
+ /// \brief The AST file was written by a different version of Clang.
+ VersionMismatch,
+ /// \brief The AST file was writtten with a different language/target
+ /// configuration.
+ ConfigurationMismatch,
+ /// \brief The AST file has errors.
+ HadErrors
+ };
+
/// \brief Types of AST files.
friend class PCHValidator;
friend class ASTDeclReader;
@@ -341,7 +384,15 @@ private:
/// \brief The set of C++ or Objective-C classes that have forward
/// declarations that have not yet been linked to their definitions.
llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
-
+
+ typedef llvm::MapVector<Decl *, uint64_t,
+ llvm::SmallDenseMap<Decl *, unsigned, 4>,
+ llvm::SmallVector<std::pair<Decl *, uint64_t>, 4> >
+ PendingBodiesMap;
+
+ /// \brief Functions or methods that have bodies that will be attached.
+ PendingBodiesMap PendingBodies;
+
/// \brief Read the records that describe the contents of declcontexts.
bool ReadDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
@@ -359,11 +410,36 @@ private:
typedef ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4>
GlobalIdentifierMapType;
- /// \brief Mapping from global identifer IDs to the module in which the
+ /// \brief Mapping from global identifier IDs to the module in which the
/// identifier resides along with the offset that should be added to the
/// global identifier ID to produce a local ID.
GlobalIdentifierMapType GlobalIdentifierMap;
+ /// \brief A vector containing macros that have already been
+ /// loaded.
+ ///
+ /// If the pointer at index I is non-NULL, then it refers to the
+ /// MacroInfo for the identifier with ID=I+1 that has already
+ /// been loaded.
+ std::vector<MacroInfo *> MacrosLoaded;
+
+ typedef ContinuousRangeMap<serialization::MacroID, ModuleFile *, 4>
+ GlobalMacroMapType;
+
+ /// \brief Mapping from global macro IDs to the module in which the
+ /// macro resides along with the offset that should be added to the
+ /// global macro ID to produce a local ID.
+ GlobalMacroMapType GlobalMacroMap;
+
+ typedef llvm::DenseMap<serialization::MacroID,
+ llvm::SmallVector<std::pair<serialization::SubmoduleID,
+ MacroUpdate>, 1> >
+ MacroUpdatesMap;
+
+ /// \brief Mapping from (global) macro IDs to the set of updates to be
+ /// performed to the corresponding macro.
+ MacroUpdatesMap MacroUpdates;
+
/// \brief A vector containing submodules that have already been loaded.
///
/// This vector is indexed by the Submodule ID (-1). NULL submodule entries
@@ -378,8 +454,55 @@ private:
/// global submodule ID to produce a local ID.
GlobalSubmoduleMapType GlobalSubmoduleMap;
+ /// \brief An entity that has been hidden.
+ class HiddenName {
+ public:
+ enum NameKind {
+ Declaration,
+ MacroVisibility,
+ MacroUndef
+ } Kind;
+
+ private:
+ unsigned Loc;
+
+ union {
+ Decl *D;
+ MacroInfo *MI;
+ };
+
+ IdentifierInfo *Id;
+
+ public:
+ HiddenName(Decl *D) : Kind(Declaration), Loc(), D(D), Id() { }
+
+ HiddenName(IdentifierInfo *II, MacroInfo *MI)
+ : Kind(MacroVisibility), Loc(), MI(MI), Id(II) { }
+
+ HiddenName(IdentifierInfo *II, MacroInfo *MI, SourceLocation Loc)
+ : Kind(MacroUndef), Loc(Loc.getRawEncoding()), MI(MI), Id(II) { }
+
+ NameKind getKind() const { return Kind; }
+
+ Decl *getDecl() const {
+ assert(getKind() == Declaration && "Hidden name is not a declaration");
+ return D;
+ }
+
+ std::pair<IdentifierInfo *, MacroInfo *> getMacro() const {
+ assert((getKind() == MacroUndef || getKind() == MacroVisibility)
+ && "Hidden name is not a macro!");
+ return std::make_pair(Id, MI);
+ }
+
+ SourceLocation getMacroUndefLoc() const {
+ assert(getKind() == MacroUndef && "Hidden name is not an undef!");
+ return SourceLocation::getFromRawEncoding(Loc);
+ }
+};
+
/// \brief A set of hidden declarations.
- typedef llvm::SmallVector<llvm::PointerUnion<Decl *, IdentifierInfo *>, 2>
+ typedef llvm::SmallVector<HiddenName, 2>
HiddenNames;
typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType;
@@ -431,10 +554,13 @@ private:
/// global method pool for this selector.
llvm::DenseMap<Selector, unsigned> SelectorGeneration;
- /// \brief Mapping from identifiers that represent macros whose definitions
- /// have not yet been deserialized to the global offset where the macro
- /// record resides.
- llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets;
+ typedef llvm::MapVector<IdentifierInfo *,
+ llvm::SmallVector<serialization::MacroID, 2> >
+ PendingMacroIDsMap;
+
+ /// \brief Mapping from identifiers that have a macro history to the global
+ /// IDs have not yet been deserialized to the global IDs of those macros.
+ PendingMacroIDsMap PendingMacroIDs;
typedef ContinuousRangeMap<unsigned, ModuleFile *, 4>
GlobalPreprocessedEntityMapType;
@@ -553,28 +679,9 @@ private:
SmallVector<serialization::SubmoduleID, 2> ImportedModules;
//@}
- /// \brief The original file name that was used to build the primary AST file,
- /// which may have been modified for relocatable-pch support.
- std::string OriginalFileName;
-
- /// \brief The actual original file name that was used to build the primary
- /// AST file.
- std::string ActualOriginalFileName;
-
- /// \brief The file ID for the original file that was used to build the
- /// primary AST file.
- FileID OriginalFileID;
-
- /// \brief The directory that the PCH was originally created in. Used to
- /// allow resolving headers even after headers+PCH was moved to a new path.
- std::string OriginalDir;
-
/// \brief The directory that the PCH we are reading is stored in.
std::string CurrentDir;
- /// \brief Whether this precompiled header is a relocatable PCH file.
- bool RelocatablePCH;
-
/// \brief The system include root to be used when loading the
/// precompiled header.
std::string isysroot;
@@ -583,9 +690,6 @@ private:
/// headers when they are loaded.
bool DisableValidation;
- /// \brief Whether to disable the use of stat caches in AST files.
- bool DisableStatCache;
-
/// \brief Whether to accept an AST file with compiler errors.
bool AllowASTWithCompilerErrors;
@@ -602,10 +706,6 @@ private:
SwitchCaseMapTy *CurrSwitchCaseStmts;
- /// \brief The number of stat() calls that hit/missed the stat
- /// cache.
- unsigned NumStatHits, NumStatMisses;
-
/// \brief The number of source location entries de-serialized from
/// the PCH file.
unsigned NumSLocEntriesRead;
@@ -687,7 +787,7 @@ private:
/// Objective-C protocols.
std::deque<Decl *> InterestingDecls;
- /// \brief The set of redeclarable declaraations that have been deserialized
+ /// \brief The set of redeclarable declarations that have been deserialized
/// since the last time the declaration chains were linked.
llvm::SmallPtrSet<Decl *, 16> RedeclsDeserialized;
@@ -758,8 +858,8 @@ private:
ASTReader &Reader;
enum ReadingKind PrevKind;
- ReadingKindTracker(const ReadingKindTracker&); // do not implement
- ReadingKindTracker &operator=(const ReadingKindTracker&);// do not implement
+ ReadingKindTracker(const ReadingKindTracker &) LLVM_DELETED_FUNCTION;
+ void operator=(const ReadingKindTracker &) LLVM_DELETED_FUNCTION;
public:
ReadingKindTracker(enum ReadingKind newKind, ASTReader &reader)
@@ -770,10 +870,6 @@ private:
~ReadingKindTracker() { Reader.ReadingKind = PrevKind; }
};
- /// \brief All predefines buffers in the chain, to be treated as if
- /// concatenated.
- PCHPredefinesBlocks PCHPredefinesBuffers;
-
/// \brief Suggested contents of the predefines buffer, after this
/// PCH file has been processed.
///
@@ -787,24 +883,45 @@ private:
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
+ typedef llvm::PointerIntPair<const FileEntry *, 1, bool> InputFile;
+
+ /// \brief Retrieve the file entry and 'overridden' bit for an input
+ /// file in the given module file.
+ InputFile getInputFile(ModuleFile &F, unsigned ID, bool Complain = true);
+
/// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
/// into account all the necessary relocations.
const FileEntry *getFileEntry(StringRef filename);
- void MaybeAddSystemRootToFilename(std::string &Filename);
+ void MaybeAddSystemRootToFilename(ModuleFile &M, std::string &Filename);
ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
- ModuleFile *ImportedBy);
- ASTReadResult ReadASTBlock(ModuleFile &F);
- bool CheckPredefinesBuffers();
+ ModuleFile *ImportedBy,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities);
+ ASTReadResult ReadControlBlock(ModuleFile &F,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities);
+ bool ReadASTBlock(ModuleFile &F);
bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
- ASTReadResult ReadSourceManagerBlock(ModuleFile &F);
- ASTReadResult ReadSLocEntryRecord(int ID);
+ bool ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
SourceLocation getImportLocation(ModuleFile *F);
- ASTReadResult ReadSubmoduleBlock(ModuleFile &F);
- bool ParseLanguageOptions(const RecordData &Record);
-
+ bool ReadSubmoduleBlock(ModuleFile &F);
+ static bool ParseLanguageOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener);
+ static bool ParseTargetOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener);
+ static bool ParseDiagnosticOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener);
+ static bool ParseFileSystemOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener);
+ static bool ParseHeaderSearchOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener);
+ static bool ParsePreprocessorOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener,
+ std::string &SuggestedPredefines);
+
struct RecordLocation {
RecordLocation(ModuleFile *M, uint64_t O)
: F(M), Offset(O) {}
@@ -836,18 +953,82 @@ private:
/// \brief Find the next module that contains entities and return the ID
/// of the first entry.
- /// \arg SLocMapI points at a chunk of a module that contains no
+ ///
+ /// \param SLocMapI points at a chunk of a module that contains no
/// preprocessed entities or the entities it contains are not the
/// ones we are looking for.
serialization::PreprocessedEntityID
findNextPreprocessedEntity(
GlobalSLocOffsetMapType::const_iterator SLocMapI) const;
- /// \brief Returns (ModuleFile, Local index) pair for \arg GlobalIndex of a
+ /// \brief Returns (ModuleFile, Local index) pair for \p GlobalIndex of a
/// preprocessed entity.
std::pair<ModuleFile *, unsigned>
getModulePreprocessedEntity(unsigned GlobalIndex);
+ /// \brief Returns (begin, end) pair for the preprocessed entities of a
+ /// particular module.
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ getModulePreprocessedEntities(ModuleFile &Mod) const;
+
+ class ModuleDeclIterator {
+ ASTReader *Reader;
+ ModuleFile *Mod;
+ const serialization::LocalDeclID *Pos;
+
+ public:
+ typedef const Decl *value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+
+ ModuleDeclIterator() : Reader(0), Mod(0), Pos(0) { }
+
+ ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod,
+ const serialization::LocalDeclID *Pos)
+ : Reader(Reader), Mod(Mod), Pos(Pos) { }
+
+ value_type operator*() const {
+ return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, *Pos));
+ }
+
+ ModuleDeclIterator &operator++() {
+ ++Pos;
+ return *this;
+ }
+
+ ModuleDeclIterator operator++(int) {
+ ModuleDeclIterator Prev(*this);
+ ++Pos;
+ return Prev;
+ }
+
+ ModuleDeclIterator &operator--() {
+ --Pos;
+ return *this;
+ }
+
+ ModuleDeclIterator operator--(int) {
+ ModuleDeclIterator Prev(*this);
+ --Pos;
+ return Prev;
+ }
+
+ friend bool operator==(const ModuleDeclIterator &LHS,
+ const ModuleDeclIterator &RHS) {
+ assert(LHS.Reader == RHS.Reader && LHS.Mod == RHS.Mod);
+ return LHS.Pos == RHS.Pos;
+ }
+
+ friend bool operator!=(const ModuleDeclIterator &LHS,
+ const ModuleDeclIterator &RHS) {
+ assert(LHS.Reader == RHS.Reader && LHS.Mod == RHS.Mod);
+ return LHS.Pos != RHS.Pos;
+ }
+ };
+
+ std::pair<ModuleDeclIterator, ModuleDeclIterator>
+ getModuleFileLevelDecls(ModuleFile &Mod);
+
void PassInterestingDeclsToConsumer();
void PassInterestingDeclToConsumer(Decl *D);
@@ -861,8 +1042,8 @@ private:
void Error(unsigned DiagID, StringRef Arg1 = StringRef(),
StringRef Arg2 = StringRef());
- ASTReader(const ASTReader&); // do not implement
- ASTReader &operator=(const ASTReader &); // do not implement
+ ASTReader(const ASTReader &) LLVM_DELETED_FUNCTION;
+ void operator=(const ASTReader &) LLVM_DELETED_FUNCTION;
public:
/// \brief Load the AST file and validate its contents against the given
/// Preprocessor.
@@ -881,29 +1062,49 @@ public:
/// of its regular consistency checking, allowing the use of precompiled
/// headers that cannot be determined to be compatible.
///
- /// \param DisableStatCache If true, the AST reader will ignore the
- /// stat cache in the AST files. This performance pessimization can
- /// help when an AST file is being used in cases where the
- /// underlying files in the file system may have changed, but
- /// parsing should still continue.
- ///
/// \param AllowASTWithCompilerErrors If true, the AST reader will accept an
/// AST file the was created out of an AST with compiler errors,
/// otherwise it will reject it.
ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
- bool DisableValidation = false, bool DisableStatCache = false,
+ bool DisableValidation = false,
bool AllowASTWithCompilerErrors = false);
~ASTReader();
SourceManager &getSourceManager() const { return SourceMgr; }
- /// \brief Load the AST file designated by the given file name.
- ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type);
+ /// \brief Flags that indicate what kind of AST loading failures the client
+ /// of the AST reader can directly handle.
+ ///
+ /// When a client states that it can handle a particular kind of failure,
+ /// the AST reader will not emit errors when producing that kind of failure.
+ enum LoadFailureCapabilities {
+ /// \brief The client can't handle any AST loading failures.
+ ARR_None = 0,
+ /// \brief The client can handle an AST file that cannot load because it
+ /// is out-of-date relative to its input files.
+ ARR_OutOfDate = 0x1,
+ /// \brief The client can handle an AST file that cannot load because it
+ /// was built with a different version of Clang.
+ ARR_VersionMismatch = 0x2,
+ /// \brief The client can handle an AST file that cannot load because it's
+ /// compiled configuration doesn't match that of the context it was
+ /// loaded into.
+ ARR_ConfigurationMismatch = 0x4
+ };
- /// \brief Checks that no file that is stored in PCH is out-of-sync with
- /// the actual file in the file system.
- ASTReadResult validateFileEntries(ModuleFile &M);
+ /// \brief Load the AST file designated by the given file name.
+ ///
+ /// \param FileName The name of the AST file to load.
+ ///
+ /// \param Type The kind of AST being loaded, e.g., PCH, module, main file,
+ /// or preamble.
+ ///
+ /// \param ClientLoadCapabilities The set of client load-failure
+ /// capabilities, represented as a bitset of the enumerators of
+ /// LoadFailureCapabilities.
+ ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type,
+ unsigned ClientLoadCapabilities);
/// \brief Make the entities in the given module and any of its (non-explicit)
/// submodules visible to name lookup.
@@ -947,8 +1148,11 @@ public:
/// \brief Retrieve the preprocessor.
Preprocessor &getPreprocessor() const { return PP; }
- /// \brief Retrieve the name of the original source file name
- const std::string &getOriginalSourceFile() { return OriginalFileName; }
+ /// \brief Retrieve the name of the original source file name for the primary
+ /// module file.
+ StringRef getOriginalSourceFile() {
+ return ModuleMgr.getPrimaryModule().OriginalSourceFileName;
+ }
/// \brief Retrieve the name of the original source file name directly from
/// the AST file, without actually loading the AST file.
@@ -956,6 +1160,21 @@ public:
FileManager &FileMgr,
DiagnosticsEngine &Diags);
+ /// \brief Read the control block for the named AST file.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ static bool readASTFileControlBlock(StringRef Filename,
+ FileManager &FileMgr,
+ ASTReaderListener &Listener);
+
+ /// \brief Determine whether the given AST file is acceptable to load into a
+ /// translation unit with the given language and target options.
+ static bool isAcceptableASTFile(StringRef Filename,
+ FileManager &FileMgr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts);
+
/// \brief Returns the suggested contents of the predefines buffer,
/// which contains a (typically-empty) subset of the predefines
/// build prior to including the precompiled header.
@@ -968,12 +1187,12 @@ public:
virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index);
/// \brief Returns a pair of [Begin, End) indices of preallocated
- /// preprocessed entities that \arg Range encompasses.
+ /// preprocessed entities that \p Range encompasses.
virtual std::pair<unsigned, unsigned>
findPreprocessedEntitiesInRange(SourceRange Range);
/// \brief Optionally returns true or false if the preallocated preprocessed
- /// entity with index \arg Index came from file \arg FID.
+ /// entity with index \p Index came from file \p FID.
virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
FileID FID);
@@ -992,6 +1211,11 @@ public:
return static_cast<unsigned>(IdentifiersLoaded.size());
}
+ /// \brief Returns the number of macros found in the chain.
+ unsigned getTotalNumMacros() const {
+ return static_cast<unsigned>(MacrosLoaded.size());
+ }
+
/// \brief Returns the number of types found in the chain.
unsigned getTotalNumTypes() const {
return static_cast<unsigned>(TypesLoaded.size());
@@ -1065,17 +1289,17 @@ public:
/// \brief Map from a local declaration ID within a given module to a
/// global declaration ID.
- serialization::DeclID getGlobalDeclID(ModuleFile &F, unsigned LocalID) const;
+ serialization::DeclID getGlobalDeclID(ModuleFile &F,
+ serialization::LocalDeclID LocalID) const;
- /// \brief Returns true if global DeclID \arg ID originated from module
- /// \arg M.
+ /// \brief Returns true if global DeclID \p ID originated from module \p M.
bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const;
/// \brief Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
ModuleFile *getOwningModuleFile(Decl *D);
- /// \brief Returns the source location for the decl \arg ID.
+ /// \brief Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID);
/// \brief Resolve a declaration ID into a declaration, potentially
@@ -1172,7 +1396,7 @@ public:
SmallVectorImpl<Decl*> &Decls);
/// \brief Get the decls that are contained in a file in the Offset/Length
- /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// range. \p Length can be 0 to indicate a point at \p Offset instead of
/// a range.
virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
SmallVectorImpl<Decl *> &Decls);
@@ -1285,6 +1509,9 @@ public:
}
virtual IdentifierInfo *GetIdentifier(serialization::IdentifierID ID) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
return DecodeIdentifierInfo(ID);
}
@@ -1293,6 +1520,13 @@ public:
serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M,
unsigned LocalID);
+ /// \brief Retrieve the macro with the given ID.
+ MacroInfo *getMacro(serialization::MacroID ID, MacroInfo *Hint = 0);
+
+ /// \brief Retrieve the global macro ID corresponding to the given local
+ /// ID within the given module file.
+ serialization::MacroID getGlobalMacroID(ModuleFile &M, unsigned LocalID);
+
/// \brief Read the source location entry with index ID.
virtual bool ReadSLocEntry(int ID);
@@ -1404,10 +1638,10 @@ public:
llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx);
// \brief Read a string
- std::string ReadString(const RecordData &Record, unsigned &Idx);
+ static std::string ReadString(const RecordData &Record, unsigned &Idx);
/// \brief Read a version tuple.
- VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
+ static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
@@ -1436,43 +1670,29 @@ public:
Expr *ReadSubExpr();
/// \brief Reads the macro record located at the given offset.
- void ReadMacroRecord(ModuleFile &F, uint64_t Offset);
+ void ReadMacroRecord(ModuleFile &F, uint64_t Offset, MacroInfo *Hint = 0);
/// \brief Determine the global preprocessed entity ID that corresponds to
/// the given local ID within the given module.
serialization::PreprocessedEntityID
getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const;
- /// \brief Note that the identifier is a macro whose record will be loaded
- /// from the given AST file at the given (file-local) offset.
+ /// \brief Note that the identifier has a macro history.
///
/// \param II The name of the macro.
///
- /// \param F The module file from which the macro definition was deserialized.
- ///
- /// \param Offset The offset into the module file at which the macro
- /// definition is located.
- ///
- /// \param Visible Whether the macro should be made visible.
- void setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F,
- uint64_t Offset, bool Visible);
+ /// \param IDs The global macro IDs that are associated with this identifier.
+ void setIdentifierIsMacro(IdentifierInfo *II,
+ ArrayRef<serialization::MacroID> IDs);
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
- /// \brief Read the macro definition for this identifier.
- virtual void LoadMacroDefinition(IdentifierInfo *II);
-
/// \brief Update an out-of-date identifier.
virtual void updateOutOfDateIdentifier(IdentifierInfo &II);
/// \brief Note that this identifier is up-to-date.
void markIdentifierUpToDate(IdentifierInfo *II);
-
- /// \brief Read the macro definition corresponding to this iterator
- /// into the unread macro record offsets table.
- void LoadMacroDefinition(
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos);
/// \brief Load all external visible decls in the given DeclContext.
void completeVisibleDeclsMap(const DeclContext *DC);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index d038d58aed8b..ac81e2164c57 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -18,6 +18,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/Lex/PPMutationListener.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Sema/SemaConsumer.h"
@@ -25,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include <map>
@@ -43,14 +45,15 @@ class ASTContext;
class NestedNameSpecifier;
class CXXBaseSpecifier;
class CXXCtorInitializer;
+class FileEntry;
class FPOptions;
class HeaderSearch;
class IdentifierResolver;
class MacroDefinition;
-class MemorizeStatCalls;
class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
+class MacroInfo;
class Module;
class PreprocessedEntity;
class PreprocessingRecord;
@@ -70,6 +73,7 @@ namespace SrcMgr { class SLocEntry; }
/// data structures. This bitstream can be de-serialized via an
/// instance of the ASTReader class.
class ASTWriter : public ASTDeserializationListener,
+ public PPMutationListener,
public ASTMutationListener {
public:
typedef SmallVector<uint64_t, 64> RecordData;
@@ -117,6 +121,10 @@ private:
/// \brief Indicates that the AST contained compiler errors.
bool ASTHasCompilerErrors;
+ /// \brief Mapping from input file entries to the index into the
+ /// offset table where information about that input file is stored.
+ llvm::DenseMap<const FileEntry *, uint32_t> InputFileIDs;
+
/// \brief Stores a declaration or a type to be written to the AST file.
class DeclOrType {
public:
@@ -171,8 +179,7 @@ private:
/// indicates the index that this particular vector has in the global one.
unsigned FirstDeclIndex;
};
- typedef llvm::DenseMap<const SrcMgr::SLocEntry *,
- DeclIDInFileInfo *> FileDeclIDsTy;
+ typedef llvm::DenseMap<FileID, DeclIDInFileInfo *> FileDeclIDsTy;
/// \brief Map from file SLocEntries to info about the file-level declarations
/// that it contains.
@@ -215,6 +222,15 @@ private:
/// IdentifierInfo.
llvm::DenseMap<const IdentifierInfo *, serialization::IdentID> IdentifierIDs;
+ /// \brief The first ID number we can use for our own macros.
+ serialization::MacroID FirstMacroID;
+
+ /// \brief The identifier ID that will be assigned to the next new identifier.
+ serialization::MacroID NextMacroID;
+
+ /// \brief Map that provides the ID numbers of each macro.
+ llvm::DenseMap<MacroInfo *, serialization::MacroID> MacroIDs;
+
/// @name FlushStmt Caches
/// @{
@@ -250,16 +266,10 @@ private:
/// table, indexed by the Selector ID (-1).
std::vector<uint32_t> SelectorOffsets;
- /// \brief Offsets of each of the macro identifiers into the
- /// bitstream.
- ///
- /// For each identifier that is associated with a macro, this map
- /// provides the offset into the bitstream where that macro is
- /// defined.
- llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets;
+ typedef llvm::MapVector<MacroInfo *, MacroUpdate> MacroUpdatesMap;
- /// \brief The set of identifiers that had macro definitions at some point.
- std::vector<const IdentifierInfo *> DeserializedMacroNames;
+ /// \brief Updates to macro definitions that were loaded from an AST file.
+ MacroUpdatesMap MacroUpdates;
/// \brief Mapping from macro definitions (as they occur in the preprocessing
/// record) to the macro IDs.
@@ -403,10 +413,9 @@ private:
llvm::DenseSet<Stmt *> &ParentStmts);
void WriteBlockInfoBlock();
- void WriteMetadata(ASTContext &Context, StringRef isysroot,
- const std::string &OutputFile);
- void WriteLanguageOptions(const LangOptions &LangOpts);
- void WriteStatCache(MemorizeStatCalls &StatCalls);
+ void WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot, const std::string &OutputFile);
+ void WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
StringRef isysroot);
@@ -428,6 +437,7 @@ private:
void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
bool IsModule);
void WriteAttributes(ArrayRef<const Attr*> Attrs, RecordDataImpl &Record);
+ void WriteMacroUpdates();
void ResolveDeclUpdatesBlocks();
void WriteDeclUpdatesBlocks();
void WriteDeclReplacementsBlock();
@@ -455,7 +465,7 @@ private:
void WriteDeclsBlockAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
- void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ void WriteASTCore(Sema &SemaRef,
StringRef isysroot, const std::string &OutputFile,
Module *WritingModule);
@@ -470,15 +480,12 @@ public:
/// \param SemaRef a reference to the semantic analysis object that processed
/// the AST to be written into the precompiled header.
///
- /// \param StatCalls the object that cached all of the stat() calls made while
- /// searching for source files and headers.
- ///
/// \param WritingModule The module that we are writing. If null, we are
/// writing a precompiled header.
///
/// \param isysroot if non-empty, write a relocatable file whose headers
/// are relative to the given system root.
- void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ void WriteAST(Sema &SemaRef,
const std::string &OutputFile,
Module *WritingModule, StringRef isysroot,
bool hasErrors = false);
@@ -501,6 +508,9 @@ public:
/// \brief Emit a reference to an identifier.
void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record);
+ /// \brief Emit a reference to a macro.
+ void addMacroRef(MacroInfo *MI, RecordDataImpl &Record);
+
/// \brief Emit a Selector (which is a smart pointer reference).
void AddSelectorRef(Selector, RecordDataImpl &Record);
@@ -518,15 +528,8 @@ public:
/// \brief Get the unique number used to refer to the given identifier.
serialization::IdentID getIdentifierRef(const IdentifierInfo *II);
- /// \brief Retrieve the offset of the macro definition for the given
- /// identifier.
- ///
- /// The identifier must refer to a macro.
- uint64_t getMacroOffset(const IdentifierInfo *II) {
- assert(MacroOffsets.find(II) != MacroOffsets.end() &&
- "Identifier does not name a macro");
- return MacroOffsets[II];
- }
+ /// \brief Get the unique number used to refer to the given macro.
+ serialization::MacroID getMacroRef(MacroInfo *MI);
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordDataImpl &Record);
@@ -689,13 +692,16 @@ public:
// ASTDeserializationListener implementation
void ReaderInitialized(ASTReader *Reader);
void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II);
+ void MacroRead(serialization::MacroID ID, MacroInfo *MI);
void TypeRead(serialization::TypeIdx Idx, QualType T);
void SelectorRead(serialization::SelectorID ID, Selector Sel);
void MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinition *MD);
- void MacroVisible(IdentifierInfo *II);
void ModuleRead(serialization::SubmoduleID ID, Module *Mod);
-
+
+ // PPMutationListener implementation.
+ virtual void UndefinedMacro(MacroInfo *MI);
+
// ASTMutationListener implementation.
virtual void CompletedTagDefinition(const TagDecl *D);
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
@@ -722,7 +728,6 @@ class PCHGenerator : public SemaConsumer {
std::string isysroot;
raw_ostream *Out;
Sema *SemaPtr;
- MemorizeStatCalls *StatCalls; // owned by the FileManager
llvm::SmallVector<char, 128> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
@@ -738,6 +743,7 @@ public:
~PCHGenerator();
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
+ virtual PPMutationListener *GetPPMutationListener();
virtual ASTMutationListener *GetASTMutationListener();
virtual ASTDeserializationListener *GetASTDeserializationListener();
};
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
index f368a80a97d8..d89cd02903d6 100644
--- a/include/clang/Serialization/ContinuousRangeMap.h
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -108,8 +108,8 @@ public:
class Builder {
ContinuousRangeMap &Self;
- Builder(const Builder&); // DO NOT IMPLEMENT
- Builder &operator=(const Builder&); // DO NOT IMPLEMENT
+ Builder(const Builder&) LLVM_DELETED_FUNCTION;
+ Builder &operator=(const Builder&) LLVM_DELETED_FUNCTION;
public:
explicit Builder(ContinuousRangeMap &Self) : Self(Self) { }
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 786ecd33c1d3..39fa3d90ced4 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -25,6 +25,7 @@
namespace clang {
+class FileEntry;
class DeclContext;
class Module;
template<typename Info> class OnDiskChainedHashTable;
@@ -74,6 +75,29 @@ public:
/// \brief The file name of the module file.
std::string FileName;
+ /// \brief The original source file name that was used to build the
+ /// primary AST file, which may have been modified for
+ /// relocatable-pch support.
+ std::string OriginalSourceFileName;
+
+ /// \brief The actual original source file name that was used to
+ /// build this AST file.
+ std::string ActualOriginalSourceFileName;
+
+ /// \brief The file ID for the original source file that was used to
+ /// build this AST file.
+ FileID OriginalSourceFileID;
+
+ /// \brief The directory that the PCH was originally created in. Used to
+ /// allow resolving headers even after headers+PCH was moved to a new path.
+ std::string OriginalDir;
+
+ /// \brief Whether this precompiled header is a relocatable PCH file.
+ bool RelocatablePCH;
+
+ /// \brief The file entry for the module file.
+ const FileEntry *File;
+
/// \brief Whether this module has been directly imported by the
/// user.
bool DirectlyImported;
@@ -98,11 +122,24 @@ public:
llvm::BitstreamCursor Stream;
/// \brief The source location where this module was first imported.
+ /// FIXME: This is not properly initialized yet.
SourceLocation ImportLoc;
/// \brief The first source location in this module.
SourceLocation FirstLoc;
+ // === Input Files ===
+ /// \brief The cursor to the start of the input-files block.
+ llvm::BitstreamCursor InputFilesCursor;
+
+ /// \brief Offsets for all of the input file entries in the AST file.
+ const uint32_t *InputFileOffsets;
+
+ /// \brief The input files that have been loaded from this AST file, along
+ /// with a bool indicating whether this was an overridden buffer.
+ std::vector<llvm::PointerIntPair<const FileEntry *, 1, bool> >
+ InputFilesLoaded;
+
// === Source Locations ===
/// \brief Cursor used to read source location entries.
@@ -124,13 +161,6 @@ public:
/// \brief SLocEntries that we're going to preload.
SmallVector<uint64_t, 4> PreloadSLocEntries;
- /// \brief The number of source location file entries in this AST file.
- unsigned LocalNumSLocFileEntries;
-
- /// \brief Offsets for all of the source location file entries in the
- /// AST file.
- const uint32_t *SLocFileOffsets;
-
/// \brief Remapping table for source locations in this module.
ContinuousRangeMap<uint32_t, int, 2> SLocRemap;
@@ -168,6 +198,22 @@ public:
/// all of the macro definitions.
llvm::BitstreamCursor MacroCursor;
+ /// \brief The number of macros in this AST file.
+ unsigned LocalNumMacros;
+
+ /// \brief Offsets of macros in the preprocessor block.
+ ///
+ /// This array is indexed by the macro ID (-1), and provides
+ /// the offset into the preprocessor block where macro definitions are
+ /// stored.
+ const uint32_t *MacroOffsets;
+
+ /// \brief Base macro ID for macros local to this module.
+ serialization::MacroID BaseMacroID;
+
+ /// \brief Remapping table for macro IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> MacroRemap;
+
/// \brief The offset of the start of the set of defined macros.
uint64_t MacroStartOffset;
@@ -294,6 +340,7 @@ public:
/// \brief Array of file-level DeclIDs sorted by file.
const serialization::DeclID *FileSortedDecls;
+ unsigned NumFileSortedDecls;
/// \brief Array of redeclaration chain location information within this
/// module file, sorted by the first declaration ID.
@@ -338,11 +385,6 @@ public:
/// \brief Diagnostic IDs and their mappings that the user changed.
SmallVector<uint64_t, 8> PragmaDiagMappings;
- /// \brief The AST stat cache installed for this file, if any.
- ///
- /// The dynamic type of this stat cache is always ASTStatCache
- void *StatCache;
-
/// \brief List of modules which depend on this module
llvm::SetVector<ModuleFile *> ImportedBy;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 6ff0640b64d1..6dcaa210d2d8 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -34,7 +34,7 @@ class ModuleManager {
/// \brief FileManager that handles translating between filenames and
/// FileEntry *.
- FileManager FileMgr;
+ FileManager &FileMgr;
/// \brief A lookup of in-memory (virtual file) buffers
llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
@@ -45,7 +45,7 @@ public:
typedef SmallVector<ModuleFile*, 2>::reverse_iterator ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
- ModuleManager(const FileSystemOptions &FSO);
+ explicit ModuleManager(FileManager &FileMgr);
~ModuleManager();
/// \brief Forward iterator to traverse all loaded modules. This is reverse
@@ -105,7 +105,10 @@ public:
std::pair<ModuleFile *, bool>
addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy,
unsigned Generation, std::string &ErrorStr);
-
+
+ /// \brief Remove the given set of modules.
+ void removeModules(ModuleIterator first, ModuleIterator last);
+
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
diff --git a/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h b/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h
deleted file mode 100644
index f9cce9ca9c62..000000000000
--- a/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines NullDerefChecker and UndefDerefChecker, two builtin checks
-// in ExprEngine that check for null and undefined pointers at loads
-// and stores.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_DEREFCHECKER
-#define LLVM_CLANG_GR_DEREFCHECKER
-
-#include <utility>
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-class ExplodedNode;
-
-std::pair<ExplodedNode * const *, ExplodedNode * const *>
-GetImplicitNullDereferences(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 29ddc9e176b4..01a6ffd7142c 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -21,7 +21,6 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
#endif
-ANALYSIS_CONSTRAINTS(BasicConstraints, "basic", "Use basic constraint tracking", CreateBasicConstraintManager)
ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
#ifndef ANALYSIS_DIAGNOSTICS
@@ -47,6 +46,7 @@ ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constrain
#endif
ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis")
+ANALYSIS_IPA(BasicInlining, "basic-inlining", "Inline C functions and blocks when their definitions are available")
ANALYSIS_IPA(Inlining, "inlining", "Inline callees when their definitions are available")
ANALYSIS_IPA(DynamicDispatch, "dynamic", "Experimental: Enable inlining of dynamically dispatched methods")
ANALYSIS_IPA(DynamicDispatchBifurcate, "dynamic-bifurcate", "Experimental: Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailable")
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
new file mode 100644
index 000000000000..fa0754acb150
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -0,0 +1,308 @@
+//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines various options for the static analyzer that are set
+// by the frontend and are consulted throughout the analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYZEROPTIONS_H
+#define LLVM_CLANG_ANALYZEROPTIONS_H
+
+#include <string>
+#include <vector>
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+class ASTConsumer;
+class DiagnosticsEngine;
+class Preprocessor;
+class LangOptions;
+
+/// Analysis - Set of available source code analyses.
+enum Analyses {
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumAnalyses
+};
+
+/// AnalysisStores - Set of available analysis store models.
+enum AnalysisStores {
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumStores
+};
+
+/// AnalysisConstraints - Set of available constraint models.
+enum AnalysisConstraints {
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumConstraints
+};
+
+/// AnalysisDiagClients - Set of available diagnostic clients for rendering
+/// analysis results.
+enum AnalysisDiagClients {
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NUM_ANALYSIS_DIAG_CLIENTS
+};
+
+/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
+enum AnalysisPurgeMode {
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumPurgeModes
+};
+
+/// AnalysisIPAMode - Set of inter-procedural modes.
+enum AnalysisIPAMode {
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumIPAModes
+};
+
+/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
+enum AnalysisInliningMode {
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+NumInliningModes
+};
+
+/// \brief Describes the different kinds of C++ member functions which can be
+/// considered for inlining by the analyzer.
+///
+/// These options are cumulative; enabling one kind of member function will
+/// enable all kinds with lower enum values.
+enum CXXInlineableMemberKind {
+ // Uninitialized = 0,
+
+ /// A dummy mode in which no C++ inlining is enabled.
+ CIMK_None = 1,
+
+ /// Refers to regular member function and operator calls.
+ CIMK_MemberFunctions,
+
+ /// Refers to constructors (implicit or explicit).
+ ///
+ /// Note that a constructor will not be inlined if the corresponding
+ /// destructor is non-trivial.
+ CIMK_Constructors,
+
+ /// Refers to destructors (implicit or explicit).
+ CIMK_Destructors
+};
+
+
+class AnalyzerOptions : public llvm::RefCountedBase<AnalyzerOptions> {
+public:
+ typedef llvm::StringMap<std::string> ConfigTable;
+
+ /// \brief Pair of checker name and enable/disable.
+ std::vector<std::pair<std::string, bool> > CheckersControlList;
+
+ /// \brief A key-value table of use-specified configuration values.
+ ConfigTable Config;
+ AnalysisStores AnalysisStoreOpt;
+ AnalysisConstraints AnalysisConstraintsOpt;
+ AnalysisDiagClients AnalysisDiagOpt;
+ AnalysisPurgeMode AnalysisPurgeOpt;
+
+ // \brief The interprocedural analysis mode.
+ AnalysisIPAMode IPAMode;
+
+ std::string AnalyzeSpecificFunction;
+
+ /// \brief The maximum number of exploded nodes the analyzer will generate.
+ unsigned MaxNodes;
+
+ /// \brief The maximum number of times the analyzer visits a block.
+ unsigned maxBlockVisitOnPath;
+
+
+ unsigned ShowCheckerHelp : 1;
+ unsigned AnalyzeAll : 1;
+ unsigned AnalyzerDisplayProgress : 1;
+ unsigned AnalyzeNestedBlocks : 1;
+
+ /// \brief The flag regulates if we should eagerly assume evaluations of
+ /// conditionals, thus, bifurcating the path.
+ ///
+ /// This flag indicates how the engine should handle expressions such as: 'x =
+ /// (y != 0)'. When this flag is true then the subexpression 'y != 0' will be
+ /// eagerly assumed to be true or false, thus evaluating it to the integers 0
+ /// or 1 respectively. The upside is that this can increase analysis
+ /// precision until we have a better way to lazily evaluate such logic. The
+ /// downside is that it eagerly bifurcates paths.
+ unsigned eagerlyAssumeBinOpBifurcation : 1;
+
+ unsigned TrimGraph : 1;
+ unsigned visualizeExplodedGraphWithGraphViz : 1;
+ unsigned visualizeExplodedGraphWithUbiGraph : 1;
+ unsigned UnoptimizedCFG : 1;
+ unsigned PrintStats : 1;
+
+ /// \brief Do not re-analyze paths leading to exhausted nodes with a different
+ /// strategy. We get better code coverage when retry is enabled.
+ unsigned NoRetryExhausted : 1;
+
+ /// \brief The inlining stack depth limit.
+ unsigned InlineMaxStackDepth;
+
+ /// \brief The mode of function selection used during inlining.
+ unsigned InlineMaxFunctionSize;
+
+ /// \brief The mode of function selection used during inlining.
+ AnalysisInliningMode InliningMode;
+
+private:
+ /// Controls which C++ member functions will be considered for inlining.
+ CXXInlineableMemberKind CXXMemberInliningMode;
+
+ /// \sa includeTemporaryDtorsInCFG
+ llvm::Optional<bool> IncludeTemporaryDtorsInCFG;
+
+ /// \sa mayInlineCXXStandardLibrary
+ llvm::Optional<bool> InlineCXXStandardLibrary;
+
+ /// \sa mayInlineTemplateFunctions
+ llvm::Optional<bool> InlineTemplateFunctions;
+
+ /// \sa mayInlineObjCMethod
+ llvm::Optional<bool> ObjCInliningMode;
+
+ // Cache of the "ipa-always-inline-size" setting.
+ // \sa getAlwaysInlineSize
+ llvm::Optional<unsigned> AlwaysInlineSize;
+
+ /// \sa shouldPruneNullReturnPaths
+ llvm::Optional<bool> PruneNullReturnPaths;
+
+ /// \sa shouldAvoidSuppressingNullArgumentPaths
+ llvm::Optional<bool> AvoidSuppressingNullArgumentPaths;
+
+ /// \sa getGraphTrimInterval
+ llvm::Optional<unsigned> GraphTrimInterval;
+
+ /// Interprets an option's string value as a boolean.
+ ///
+ /// Accepts the strings "true" and "false".
+ /// If an option value is not provided, returns the given \p DefaultVal.
+ bool getBooleanOption(StringRef Name, bool DefaultVal);
+
+ /// Variant that accepts a Optional value to cache the result.
+ bool getBooleanOption(llvm::Optional<bool> &V, StringRef Name,
+ bool DefaultVal);
+
+ /// Interprets an option's string value as an integer value.
+ int getOptionAsInteger(llvm::StringRef Name, int DefaultVal);
+
+public:
+ /// Returns the option controlling which C++ member functions will be
+ /// considered for inlining.
+ ///
+ /// This is controlled by the 'c++-inlining' config option.
+ ///
+ /// \sa CXXMemberInliningMode
+ bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K);
+
+ /// Returns true if ObjectiveC inlining is enabled, false otherwise.
+ bool mayInlineObjCMethod();
+
+ /// Returns whether or not the destructors for C++ temporary objects should
+ /// be included in the CFG.
+ ///
+ /// This is controlled by the 'cfg-temporary-dtors' config option, which
+ /// accepts the values "true" and "false".
+ bool includeTemporaryDtorsInCFG();
+
+ /// Returns whether or not C++ standard library functions may be considered
+ /// for inlining.
+ ///
+ /// This is controlled by the 'c++-stdlib-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineCXXStandardLibrary();
+
+ /// Returns whether or not templated functions may be considered for inlining.
+ ///
+ /// This is controlled by the 'c++-template-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineTemplateFunctions();
+
+ /// Returns whether or not paths that go through null returns should be
+ /// suppressed.
+ ///
+ /// This is a heuristic for avoiding bug reports with paths that go through
+ /// inlined functions that are more defensive than their callers.
+ ///
+ /// This is controlled by the 'suppress-null-return-paths' config option,
+ /// which accepts the values "true" and "false".
+ bool shouldPruneNullReturnPaths();
+
+ /// Returns whether a bug report should \em not be suppressed if its path
+ /// includes a call with a null argument, even if that call has a null return.
+ ///
+ /// This option has no effect when #shouldPruneNullReturnPaths() is false.
+ ///
+ /// This is a counter-heuristic to avoid false negatives.
+ ///
+ /// This is controlled by the 'avoid-suppressing-null-argument-paths' config
+ /// option, which accepts the values "true" and "false".
+ bool shouldAvoidSuppressingNullArgumentPaths();
+
+ // Returns the size of the functions (in basic blocks), which should be
+ // considered to be small enough to always inline.
+ //
+ // This is controlled by "ipa-always-inline-size" analyzer-config option.
+ unsigned getAlwaysInlineSize();
+
+ /// Returns true if the analyzer engine should synthesize fake bodies
+ /// for well-known functions.
+ bool shouldSynthesizeBodies();
+
+ /// Returns how often nodes in the ExplodedGraph should be recycled to save
+ /// memory.
+ ///
+ /// This is controlled by the 'graph-trim-interval' config option. To disable
+ /// node reclamation, set the option to "0".
+ unsigned getGraphTrimInterval();
+
+public:
+ AnalyzerOptions() : CXXMemberInliningMode() {
+ AnalysisStoreOpt = RegionStoreModel;
+ AnalysisConstraintsOpt = RangeConstraintsModel;
+ AnalysisDiagOpt = PD_HTML;
+ AnalysisPurgeOpt = PurgeStmt;
+ IPAMode = DynamicDispatchBifurcate;
+ ShowCheckerHelp = 0;
+ AnalyzeAll = 0;
+ AnalyzerDisplayProgress = 0;
+ AnalyzeNestedBlocks = 0;
+ eagerlyAssumeBinOpBifurcation = 0;
+ TrimGraph = 0;
+ visualizeExplodedGraphWithGraphViz = 0;
+ visualizeExplodedGraphWithUbiGraph = 0;
+ UnoptimizedCFG = 0;
+ PrintStats = 0;
+ NoRetryExhausted = 0;
+ // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+ InlineMaxStackDepth = 5;
+ InlineMaxFunctionSize = 200;
+ InliningMode = NoRedundancy;
+ }
+};
+
+typedef llvm::IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
+
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 48393a379b39..b5a88ba9f6c6 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallSet.h"
namespace clang {
@@ -95,6 +96,10 @@ protected:
/// for multiple PathDiagnosticConsumers.
llvm::SmallVector<Regions *, 2> interestingRegions;
+ /// A set of location contexts that correspoind to call sites which should be
+ /// considered "interesting".
+ llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
+
/// A set of custom visitors which generate "event" diagnostics at
/// interesting points in the path.
VisitorList Callbacks;
@@ -111,6 +116,19 @@ protected:
/// when reporting an issue.
bool DoNotPrunePath;
+ /// Used to track unique reasons why a bug report might be invalid.
+ ///
+ /// \sa markInvalid
+ /// \sa removeInvalidation
+ typedef std::pair<const void *, const void *> InvalidationRecord;
+
+ /// If non-empty, this bug report is likely a false positive and should not be
+ /// shown to the user.
+ ///
+ /// \sa markInvalid
+ /// \sa removeInvalidation
+ llvm::SmallSet<InvalidationRecord, 4> Invalidations;
+
private:
// Used internally by BugReporter.
Symbols &getInterestingSymbols();
@@ -147,7 +165,8 @@ public:
PathDiagnosticLocation LocationToUnique)
: BT(bt), DeclWithIssue(0), Description(desc),
UniqueingLocation(LocationToUnique),
- ErrorNode(errornode), ConfigurationChangeToken(0) {}
+ ErrorNode(errornode), ConfigurationChangeToken(0),
+ DoNotPrunePath(false) {}
virtual ~BugReport();
@@ -158,8 +177,10 @@ public:
const StringRef getDescription() const { return Description; }
- const StringRef getShortDescription() const {
- return ShortDescription.empty() ? Description : ShortDescription;
+ const StringRef getShortDescription(bool UseFallback = true) const {
+ if (ShortDescription.empty() && UseFallback)
+ return Description;
+ return ShortDescription;
}
/// Indicates whether or not any path pruning should take place
@@ -172,14 +193,44 @@ public:
void markInteresting(SymbolRef sym);
void markInteresting(const MemRegion *R);
void markInteresting(SVal V);
+ void markInteresting(const LocationContext *LC);
bool isInteresting(SymbolRef sym);
bool isInteresting(const MemRegion *R);
bool isInteresting(SVal V);
+ bool isInteresting(const LocationContext *LC);
unsigned getConfigurationChangeToken() const {
return ConfigurationChangeToken;
}
+
+ /// Returns whether or not this report should be considered valid.
+ ///
+ /// Invalid reports are those that have been classified as likely false
+ /// positives after the fact.
+ bool isValid() const {
+ return Invalidations.empty();
+ }
+
+ /// Marks the current report as invalid, meaning that it is probably a false
+ /// positive and should not be reported to the user.
+ ///
+ /// The \p Tag and \p Data arguments are intended to be opaque identifiers for
+ /// this particular invalidation, where \p Tag represents the visitor
+ /// responsible for invalidation, and \p Data represents the reason this
+ /// visitor decided to invalidate the bug report.
+ ///
+ /// \sa removeInvalidation
+ void markInvalid(const void *Tag, const void *Data) {
+ Invalidations.insert(std::make_pair(Tag, Data));
+ }
+
+ /// Reverses the effects of a previous invalidation.
+ ///
+ /// \sa markInvalid
+ void removeInvalidation(const void *Tag, const void *Data) {
+ Invalidations.erase(std::make_pair(Tag, Data));
+ }
/// Return the canonical declaration, be it a method or class, where
/// this issue semantically occurred.
@@ -342,6 +393,11 @@ private:
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
+ /// A map from PathDiagnosticPiece to the LocationContext of the inlined
+ /// function call it represents.
+ llvm::DenseMap<const PathDiagnosticCallPiece*,
+ const LocationContext*> LocationContextMap;
+
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
D(d) {}
@@ -378,9 +434,14 @@ public:
SourceManager& getSourceManager() { return D.getSourceManager(); }
- virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
+ virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic,
PathDiagnosticConsumer &PC,
- ArrayRef<BugReport *> &bugReports) {}
+ ArrayRef<BugReport *> &bugReports) {
+ return true;
+ }
+
+ bool RemoveUneededCalls(PathPieces &pieces, BugReport *R,
+ PathDiagnosticCallPiece *CallWithLoc = 0);
void Register(BugType *BT);
@@ -389,7 +450,7 @@ public:
/// The reports are usually generated by the checkers. Further, they are
/// folded based on the profile value, which is done to coalesce similar
/// reports.
- void EmitReport(BugReport *R);
+ void emitReport(BugReport *R);
void EmitBasicReport(const Decl *DeclWithIssue,
StringRef BugName, StringRef BugCategory,
@@ -409,8 +470,10 @@ public:
EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
}
- static bool classof(const BugReporter* R) { return true; }
-
+ void addCallPieceLocationContextPair(const PathDiagnosticCallPiece *C,
+ const LocationContext *LC) {
+ LocationContextMap[C] = LC;
+ }
private:
llvm::StringMap<BugType *> StrBugTypes;
@@ -440,7 +503,15 @@ public:
/// engine.
ProgramStateManager &getStateManager();
- virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
+ /// Generates a path corresponding to one of the given bug reports.
+ ///
+ /// Which report is used for path generation is not specified. The
+ /// bug reporter will try to pick the shortest path, but this is not
+ /// guaranteed.
+ ///
+ /// \return True if the report was valid and a path was generated,
+ /// false if the reports should be considered invalid.
+ virtual bool generatePathDiagnostic(PathDiagnostic &PD,
PathDiagnosticConsumer &PC,
ArrayRef<BugReport*> &bugReports);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index f53c15f117c9..78e35ca82b89 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -100,7 +100,6 @@ class FindLastStoreBRVisitor
const MemRegion *R;
SVal V;
bool satisfied;
- const ExplodedNode *StoreSite;
public:
/// \brief Convenience method to create a visitor given only the MemRegion.
@@ -114,7 +113,7 @@ public:
static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
FindLastStoreBRVisitor(SVal v, const MemRegion *r)
- : R(r), V(v), satisfied(false), StoreSite(0) {
+ : R(r), V(v), satisfied(false) {
assert (!V.isUnknown() && "Cannot track unknown value.");
// TODO: Does it make sense to allow undef values here?
@@ -142,6 +141,10 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const;
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
+
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
@@ -171,6 +174,9 @@ public:
ID.AddPointer(&x);
}
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
@@ -223,15 +229,57 @@ public:
const ExplodedNode *N,
llvm::Optional<bool> &prunable);
};
-
+
+/// \brief When a region containing undefined value or '0' value is passed
+/// as an argument in a call, marks the call as interesting.
+///
+/// As a result, BugReporter will not prune the path through the function even
+/// if the region's contents are not modified/accessed by the call.
+class UndefOrNullArgVisitor
+ : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
+
+ /// The interesting memory region this visitor is tracking.
+ const MemRegion *R;
+
+public:
+ UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int Tag = 0;
+ ID.AddPointer(&Tag);
+ ID.AddPointer(R);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
namespace bugreporter {
-void addTrackNullOrUndefValueVisitor(const ExplodedNode *N, const Stmt *S,
- BugReport *R);
+/// Attempts to add visitors to trace a null or undefined value back to its
+/// point of origin, whether it is a symbol constrained to null or an explicit
+/// assignment.
+///
+/// \param N A node "downstream" from the evaluation of the statement.
+/// \param S The statement whose value is null or undefined.
+/// \param R The bug report to which visitors should be attached.
+/// \param IsArg Whether the statement is an argument to an inlined function.
+/// If this is the case, \p N \em must be the CallEnter node for
+/// the function.
+///
+/// \return Whether or not the function was able to add visitors for this
+/// statement. Note that returning \c true does not actually imply
+/// that any visitors were added.
+bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
+ bool IsArg = false);
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
+bool isDeclRefExprToReference(const Expr *E);
+
} // end namespace clang
} // end namespace ento
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 973cfb109c05..6dc26e670344 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -52,7 +52,31 @@ class PathDiagnostic;
class PathDiagnosticConsumer {
public:
- typedef std::vector<std::pair<StringRef, std::string> > FilesMade;
+ class PDFileEntry : public llvm::FoldingSetNode {
+ public:
+ PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
+
+ typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles;
+
+ /// \brief A vector of <consumer,file> pairs.
+ ConsumerFiles files;
+
+ /// \brief A precomputed hash tag used for uniquing PDFileEntry objects.
+ const llvm::FoldingSetNodeID NodeID;
+
+ /// \brief Used for profiling in the FoldingSet.
+ void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
+ };
+
+ struct FilesMade : public llvm::FoldingSet<PDFileEntry> {
+ llvm::BumpPtrAllocator Alloc;
+
+ void addDiagnostic(const PathDiagnostic &PD,
+ StringRef ConsumerName,
+ StringRef fileName);
+
+ PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
+ };
private:
virtual void anchor();
@@ -73,7 +97,6 @@ public:
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
- virtual bool useVerboseDescription() const { return true; }
/// Return true if the PathDiagnosticConsumer supports individual
/// PathDiagnostics that span multiple files.
@@ -114,8 +137,6 @@ private:
Kind kind)
: K(kind), S(0), D(0), SM(&sm),
Loc(genLocation(L)), Range(genRange()) {
- assert(Loc.isValid());
- assert(Range.isValid());
}
FullSourceLoc
@@ -134,12 +155,14 @@ public:
PathDiagnosticLocation(const Stmt *s,
const SourceManager &sm,
LocationOrAnalysisDeclContext lac)
- : K(StmtK), S(s), D(0), SM(&sm),
+ : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
+ S(K == StmtK ? s : 0),
+ D(0), SM(&sm),
Loc(genLocation(SourceLocation(), lac)),
Range(genRange(lac)) {
- assert(S);
- assert(Loc.isValid());
- assert(Range.isValid());
+ assert(K == SingleLocK || S);
+ assert(K == SingleLocK || Loc.isValid());
+ assert(K == SingleLocK || Range.isValid());
}
/// Create a location corresponding to the given declaration.
@@ -297,12 +320,18 @@ private:
const std::string str;
const Kind kind;
const DisplayHint Hint;
+
+ /// A constant string that can be used to tag the PathDiagnosticPiece,
+ /// typically with the identification of the creator. The actual pointer
+ /// value is meant to be an identifier; the string itself is useful for
+ /// debugging.
+ StringRef Tag;
+
std::vector<SourceRange> ranges;
- // Do not implement:
- PathDiagnosticPiece();
- PathDiagnosticPiece(const PathDiagnosticPiece &P);
- PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
+ PathDiagnosticPiece() LLVM_DELETED_FUNCTION;
+ PathDiagnosticPiece(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
+ void operator=(const PathDiagnosticPiece &P) LLVM_DELETED_FUNCTION;
protected:
PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
@@ -312,8 +341,18 @@ protected:
public:
virtual ~PathDiagnosticPiece();
- const std::string& getString() const { return str; }
+ llvm::StringRef getString() const { return str; }
+ /// Tag this PathDiagnosticPiece with the given C-string.
+ void setTag(const char *tag) { Tag = tag; }
+
+ /// Return the opaque tag (if any) on the PathDiagnosticPiece.
+ const void *getTag() const { return Tag.data(); }
+
+ /// Return the string representation of the tag. This is useful
+ /// for debugging.
+ StringRef getTagStr() const { return Tag; }
+
/// getDisplayHint - Return a hint indicating where the diagnostic should
/// be displayed by the PathDiagnosticConsumer.
DisplayHint getDisplayHint() const { return Hint; }
@@ -338,10 +377,6 @@ public:
/// Return the SourceRanges associated with this PathDiagnosticPiece.
ArrayRef<SourceRange> getRanges() const { return ranges; }
- static inline bool classof(const PathDiagnosticPiece *P) {
- return true;
- }
-
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
@@ -377,6 +412,10 @@ public:
virtual void flattenLocations() { Pos.flatten(); }
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static bool classof(const PathDiagnosticPiece *P) {
+ return P->getKind() == Event || P->getKind() == Macro;
+ }
};
/// \brief Interface for classes constructing Stack hints.
@@ -410,10 +449,6 @@ public:
/// 'getMessageForX()' methods to construct a specific message.
virtual std::string getMessage(const ExplodedNode *N);
- /// Prints the ordinal form of the given integer,
- /// only valid for ValNo : ValNo > 0.
- void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
-
/// Produces the message of the following form:
/// 'Msg via Nth parameter'
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
@@ -629,14 +664,22 @@ public:
class PathDiagnostic : public llvm::FoldingSetNode {
const Decl *DeclWithIssue;
std::string BugType;
- std::string Desc;
+ std::string VerboseDesc;
+ std::string ShortDesc;
std::string Category;
std::deque<std::string> OtherDesc;
+ PathDiagnosticLocation Loc;
PathPieces pathImpl;
llvm::SmallVector<PathPieces *, 3> pathStack;
PathDiagnostic(); // Do not implement.
public:
+ PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
+ StringRef verboseDesc, StringRef shortDesc,
+ StringRef category);
+
+ ~PathDiagnostic();
+
const PathPieces &path;
/// Return the path currently used by builders for constructing the
@@ -659,16 +702,24 @@ public:
void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
bool isWithinCall() const { return !pathStack.empty(); }
-
- // PathDiagnostic();
- PathDiagnostic(const Decl *DeclWithIssue,
- StringRef bugtype,
- StringRef desc,
- StringRef category);
- ~PathDiagnostic();
+ void setEndOfPath(PathDiagnosticPiece *EndPiece) {
+ assert(!Loc.isValid() && "End location already set!");
+ Loc = EndPiece->getLocation();
+ assert(Loc.isValid() && "Invalid location for end-of-path piece");
+ getActivePath().push_back(EndPiece);
+ }
- StringRef getDescription() const { return Desc; }
+ void resetPath() {
+ pathStack.clear();
+ pathImpl.clear();
+ Loc = PathDiagnosticLocation();
+ }
+
+ StringRef getVerboseDescription() const { return VerboseDesc; }
+ StringRef getShortDescription() const {
+ return ShortDesc.empty() ? VerboseDesc : ShortDesc;
+ }
StringRef getBugType() const { return BugType; }
StringRef getCategory() const { return Category; }
@@ -682,15 +733,27 @@ public:
meta_iterator meta_end() const { return OtherDesc.end(); }
void addMeta(StringRef s) { OtherDesc.push_back(s); }
- PathDiagnosticLocation getLocation() const;
+ PathDiagnosticLocation getLocation() const {
+ assert(Loc.isValid() && "No end-of-path location set yet!");
+ return Loc;
+ }
void flattenLocations() {
+ Loc.flatten();
for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
I != E; ++I) (*I)->flattenLocations();
}
-
+
+ /// Profiles the diagnostic, independent of the path it references.
+ ///
+ /// This can be used to merge diagnostics that refer to the same issue
+ /// along different paths.
void Profile(llvm::FoldingSetNodeID &ID) const;
-
+
+ /// Profiles the diagnostic, including its path.
+ ///
+ /// Two diagnostics with the same issue along different paths will generate
+ /// different profiles.
void FullProfile(llvm::FoldingSetNodeID &ID) const;
};
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 3214d96c5398..9eb1248f6a71 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -366,23 +366,6 @@ public:
}
};
-class InlineCall {
- template <typename CHECKER>
- static bool _inlineCall(void *checker, const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst);
- }
-
-public:
- template <typename CHECKER>
- static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForInlineCall(
- CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>));
- }
-};
-
} // end eval namespace
class CheckerBase : public ProgramPointTag {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index e11b6d518a4e..7ae8e53784bf 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -258,7 +258,7 @@ public:
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng,
- ProgramPoint::Kind PointKind);
+ const ProgramPoint &PP);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
@@ -267,6 +267,7 @@ public:
/// \brief Run checkers for end of path.
void runCheckersForEndPath(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
ExprEngine &Eng);
/// \brief Run checkers for branch condition.
@@ -407,11 +408,6 @@ public:
typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
EvalCallFunc;
- typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst)>
- InlineCallFunc;
-
typedef CheckerFn<void (const TranslationUnitDecl *,
AnalysisManager&, BugReporter &)>
CheckEndOfTranslationUnit;
@@ -449,8 +445,6 @@ public:
void _registerForEvalCall(EvalCallFunc checkfn);
- void _registerForInlineCall(InlineCallFunc checkfn);
-
void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
//===----------------------------------------------------------------------===//
@@ -576,8 +570,6 @@ private:
std::vector<EvalCallFunc> EvalCallCheckers;
- std::vector<InlineCallFunc> InlineCallCheckers;
-
std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
struct EventInfo {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index e1ff17b361aa..27f3677bba22 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -66,6 +66,10 @@ public:
return llvm::APSInt::getMaxValue(BitWidth, IsUnsigned);
}
+ llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY {
+ return (llvm::APSInt(BitWidth, IsUnsigned) = RawValue);
+ }
+
/// Used to classify whether a value is representable using this type.
///
/// \see testInRange
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 876196ba4f7f..9038ae5276a7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -16,7 +16,7 @@
#define LLVM_CLANG_GR_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
@@ -41,64 +41,16 @@ class AnalysisManager : public BugReporterData {
CheckerManager *CheckerMgr;
- /// \brief The maximum number of exploded nodes the analyzer will generate.
- unsigned MaxNodes;
-
- /// \brief The maximum number of times the analyzer visits a block.
- unsigned MaxVisit;
-
- bool VisualizeEGDot;
- bool VisualizeEGUbi;
- AnalysisPurgeMode PurgeDead;
-
- /// \brief The flag regulates if we should eagerly assume evaluations of
- /// conditionals, thus, bifurcating the path.
- ///
- /// EagerlyAssume - A flag indicating how the engine should handle
- /// expressions such as: 'x = (y != 0)'. When this flag is true then
- /// the subexpression 'y != 0' will be eagerly assumed to be true or false,
- /// thus evaluating it to the integers 0 or 1 respectively. The upside
- /// is that this can increase analysis precision until we have a better way
- /// to lazily evaluate such logic. The downside is that it eagerly
- /// bifurcates paths.
- bool EagerlyAssume;
- bool TrimGraph;
- bool EagerlyTrimEGraph;
-
-public:
- // \brief inter-procedural analysis mode.
- AnalysisIPAMode IPAMode;
-
- // Settings for inlining tuning.
- /// \brief The inlining stack depth limit.
- unsigned InlineMaxStackDepth;
- /// \brief The max number of basic blocks in a function being inlined.
- unsigned InlineMaxFunctionSize;
- /// \brief The mode of function selection used during inlining.
- AnalysisInliningMode InliningMode;
-
- /// \brief Do not re-analyze paths leading to exhausted nodes with a different
- /// strategy. We get better code coverage when retry is enabled.
- bool NoRetryExhausted;
-
public:
+ AnalyzerOptions &options;
+
AnalysisManager(ASTContext &ctx,DiagnosticsEngine &diags,
const LangOptions &lang,
const PathDiagnosticConsumers &Consumers,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi, AnalysisPurgeMode purge,
- bool eager, bool trim,
- bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool eagerlyTrimEGraph,
- AnalysisIPAMode ipa,
- unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize,
- AnalysisInliningMode inliningMode,
- bool NoRetry);
+ AnalyzerOptions &Options);
~AnalysisManager();
@@ -142,27 +94,14 @@ public:
void FlushDiagnostics();
- unsigned getMaxNodes() const { return MaxNodes; }
-
- unsigned getMaxVisit() const { return MaxVisit; }
-
- bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
-
- bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
-
bool shouldVisualize() const {
- return VisualizeEGDot || VisualizeEGUbi;
+ return options.visualizeExplodedGraphWithGraphViz ||
+ options.visualizeExplodedGraphWithUbiGraph;
}
- bool shouldEagerlyTrimExplodedGraph() const { return EagerlyTrimEGraph; }
-
- bool shouldTrimGraph() const { return TrimGraph; }
-
- AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }
-
- bool shouldEagerlyAssume() const { return EagerlyAssume; }
-
- bool shouldInlineCall() const { return (IPAMode != None); }
+ bool shouldInlineCall() const {
+ return options.IPAMode != None;
+ }
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
@@ -180,7 +119,6 @@ public:
AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
-
};
} // enAnaCtxMgrspace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index b4a9de76f4d1..fb393548b1af 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -73,6 +73,10 @@ class BasicValueFactory {
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+ // This is private because external clients should use the factory
+ // method that takes a QualType.
+ const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
+
public:
BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator& Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
@@ -84,7 +88,6 @@ public:
const llvm::APSInt& getValue(const llvm::APSInt& X);
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
- const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
const llvm::APSInt& getValue(uint64_t X, QualType T);
/// Returns the type of the APSInt used to store values of the given QualType.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index f6c5830c2955..a6a91e2b66df 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -68,15 +69,22 @@ public:
}
};
+/// \class RuntimeDefinition
/// \brief Defines the runtime definition of the called function.
+///
+/// Encapsulates the information we have about which Decl will be used
+/// when the call is executed on the given path. When dealing with dynamic
+/// dispatch, the information is based on DynamicTypeInfo and might not be
+/// precise.
class RuntimeDefinition {
- /// The Declaration of the function which will be called at runtime.
- /// 0 if not available.
+ /// The Declaration of the function which could be called at runtime.
+ /// NULL if not available.
const Decl *D;
/// The region representing an object (ObjC/C++) on which the method is
/// called. With dynamic dispatch, the method definition depends on the
- /// runtime type of this object. 0 when there is no dynamic dispatch.
+ /// runtime type of this object. NULL when the DynamicTypeInfo is
+ /// precise.
const MemRegion *R;
public:
@@ -84,8 +92,15 @@ public:
RuntimeDefinition(const Decl *InD): D(InD), R(0) {}
RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
const Decl *getDecl() { return D; }
- const MemRegion *getDispatchRegion() { return R; }
+
+ /// \brief Check if the definition we have is precise.
+ /// If not, it is possible that the call dispatches to another definition at
+ /// execution time.
bool mayHaveOtherDefinitions() { return R != 0; }
+
+ /// When other definitions are possible, returns the region whose runtime type
+ /// determines the method definition.
+ const MemRegion *getDispatchRegion() { return R; }
};
/// \brief Represents an abstract call to a function or method along a
@@ -106,8 +121,7 @@ private:
const LocationContext *LCtx;
llvm::PointerUnion<const Expr *, const Decl *> Origin;
- // DO NOT IMPLEMENT
- CallEvent &operator=(const CallEvent &);
+ void operator=(const CallEvent &) LLVM_DELETED_FUNCTION;
protected:
// This is user data for subclasses.
@@ -139,16 +153,6 @@ protected:
: State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
Data(Original.Data), Location(Original.Location), RefCount(0) {}
-
- ProgramStateRef getState() const {
- return State;
- }
-
- const LocationContext *getLocationContext() const {
- return LCtx;
- }
-
-
/// Copies this CallEvent, with vtable intact, into a new block of memory.
virtual void cloneTo(void *Dest) const = 0;
@@ -164,8 +168,6 @@ protected:
/// result of this call.
virtual void getExtraInvalidatedRegions(RegionList &Regions) const {}
- virtual QualType getDeclaredResultType() const = 0;
-
public:
virtual ~CallEvent() {}
@@ -178,6 +180,16 @@ public:
return Origin.dyn_cast<const Decl *>();
}
+ /// \brief The state in which the call is being evaluated.
+ ProgramStateRef getState() const {
+ return State;
+ }
+
+ /// \brief The context in which the call is being evaluated.
+ const LocationContext *getLocationContext() const {
+ return LCtx;
+ }
+
/// \brief Returns the definition of the function or method that will be
/// called.
virtual RuntimeDefinition getRuntimeDefinition() const = 0;
@@ -237,6 +249,12 @@ public:
/// \brief Returns the result type, adjusted for references.
QualType getResultType() const;
+ /// \brief Returns the return value of the call.
+ ///
+ /// This should only be called if the CallEvent was created using a state in
+ /// which the return value has already been bound to the origin expression.
+ SVal getReturnValue() const;
+
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
@@ -249,6 +267,38 @@ public:
return hasNonZeroCallbackArg();
}
+ /// \brief Returns true if the callee is an externally-visible function in the
+ /// top-level namespace, such as \c malloc.
+ ///
+ /// You can use this call to determine that a particular function really is
+ /// a library function and not, say, a C++ member function with the same name.
+ ///
+ /// If a name is provided, the function must additionally match the given
+ /// name.
+ ///
+ /// Note that this deliberately excludes C++ library functions in the \c std
+ /// namespace, but will include C library functions accessed through the
+ /// \c std namespace. This also does not check if the function is declared
+ /// as 'extern "C"', or if it uses C++ name mangling.
+ // FIXME: Add a helper for checking namespaces.
+ // FIXME: Move this down to AnyFunctionCall once checkers have more
+ // precise callbacks.
+ bool isGlobalCFunction(StringRef SpecificName = StringRef()) const;
+
+ /// \brief Returns the name of the callee, if its name is a simple identifier.
+ ///
+ /// Note that this will fail for Objective-C methods, blocks, and C++
+ /// overloaded operators. The former is named by a Selector rather than a
+ /// simple identifier, and the latter two do not have names.
+ // FIXME: Move this down to AnyFunctionCall once checkers have more
+ // precise callbacks.
+ const IdentifierInfo *getCalleeIdentifier() const {
+ const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDecl());
+ if (!ND)
+ return 0;
+ return ND->getIdentifier();
+ }
+
/// \brief Returns an appropriate ProgramPoint for this call.
ProgramPoint getProgramPoint(bool IsPreVisit = false,
const ProgramPointTag *Tag = 0) const;
@@ -277,12 +327,12 @@ public:
return cloneWithState<CallEvent>(NewState);
}
- /// \brief Returns true if this is a statement that can be considered for
- /// inlining.
- ///
- /// FIXME: This should go away once CallEvents are cheap and easy to
- /// construct from ExplodedNodes.
- static bool mayBeInlined(const Stmt *S);
+ /// \brief Returns true if this is a statement is a function or method call
+ /// of some kind.
+ static bool isCallStmt(const Stmt *S);
+
+ /// \brief Returns the result type of a function, method declaration.
+ static QualType getDeclaredResultType(const Decl *D);
// Iterator access to formal parameters and their types.
private:
@@ -329,8 +379,6 @@ public:
// For debugging purposes only
void dump(raw_ostream &Out) const;
LLVM_ATTRIBUTE_USED void dump() const;
-
- static bool classof(const CallEvent *) { return true; }
};
@@ -346,8 +394,6 @@ protected:
: CallEvent(D, St, LCtx) {}
AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {}
- virtual QualType getDeclaredResultType() const;
-
public:
// This function is overridden by subclasses, but they must return
// a FunctionDecl.
@@ -357,9 +403,16 @@ public:
virtual RuntimeDefinition getRuntimeDefinition() const {
const FunctionDecl *FD = getDecl();
- // Note that hasBody() will fill FD with the definition FunctionDecl.
- if (FD && FD->hasBody(FD))
- return RuntimeDefinition(FD);
+ // Note that the AnalysisDeclContext will have the FunctionDecl with
+ // the definition (if one exists).
+ if (FD) {
+ AnalysisDeclContext *AD =
+ getLocationContext()->getAnalysisDeclContext()->
+ getManager()->getContext(FD);
+ if (AD->getBody())
+ return RuntimeDefinition(AD->getDecl());
+ }
+
return RuntimeDefinition();
}
@@ -442,8 +495,6 @@ protected:
virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
- virtual QualType getDeclaredResultType() const;
-
public:
/// \brief Returns the region associated with this instance of the block.
///
@@ -499,13 +550,7 @@ public:
virtual const Expr *getCXXThisExpr() const { return 0; }
/// \brief Returns the value of the implicit 'this' object.
- virtual SVal getCXXThisVal() const {
- const Expr *Base = getCXXThisExpr();
- // FIXME: This doesn't handle an overloaded ->* operator.
- if (!Base)
- return UnknownVal();
- return getSVal(Base);
- }
+ virtual SVal getCXXThisVal() const;
virtual const FunctionDecl *getDecl() const;
@@ -550,6 +595,8 @@ public:
}
virtual const Expr *getCXXThisExpr() const;
+
+ virtual RuntimeDefinition getRuntimeDefinition() const;
virtual Kind getKind() const { return CE_CXXMember; }
@@ -605,6 +652,8 @@ class CXXDestructorCall : public CXXInstanceCall {
friend class CallEventManager;
protected:
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> DtorDataTy;
+
/// Creates an implicit destructor.
///
/// \param DD The destructor that will be called.
@@ -613,10 +662,10 @@ protected:
/// \param St The path-sensitive state at this point in the program.
/// \param LCtx The location context at this point in the program.
CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
- const MemRegion *Target, ProgramStateRef St,
- const LocationContext *LCtx)
+ const MemRegion *Target, bool IsBaseDestructor,
+ ProgramStateRef St, const LocationContext *LCtx)
: CXXInstanceCall(DD, St, LCtx) {
- Data = Target;
+ Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
Location = Trigger->getLocEnd();
}
@@ -627,9 +676,16 @@ public:
virtual SourceRange getSourceRange() const { return Location; }
virtual unsigned getNumArgs() const { return 0; }
+ virtual RuntimeDefinition getRuntimeDefinition() const;
+
/// \brief Returns the value of the implicit 'this' object.
virtual SVal getCXXThisVal() const;
+ /// Returns true if this is a call to a base class destructor.
+ bool isBaseDestructor() const {
+ return DtorDataTy::getFromOpaqueValue(Data).getInt();
+ }
+
virtual Kind getKind() const { return CE_CXXDestructor; }
static bool classof(const CallEvent *CA) {
@@ -651,10 +707,10 @@ protected:
/// a new symbolic region will be used.
/// \param St The path-sensitive state at this point in the program.
/// \param LCtx The location context at this point in the program.
- CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
+ CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *Target,
ProgramStateRef St, const LocationContext *LCtx)
: AnyFunctionCall(CE, St, LCtx) {
- Data = target;
+ Data = Target;
}
CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
@@ -761,8 +817,6 @@ protected:
virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
- virtual QualType getDeclaredResultType() const;
-
/// Check if the selector may have multiple definitions (may have overrides).
virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
Selector Sel) const;
@@ -796,6 +850,9 @@ public:
/// \brief Returns the value of the receiver at the time of this call.
SVal getReceiverSVal() const;
+ /// \brief Return the value of 'self' if available.
+ SVal getSelfSVal() const;
+
/// \brief Get the interface for the receiver.
///
/// This works whether this is an instance message or a class message.
@@ -804,6 +861,9 @@ public:
return getOriginExpr()->getReceiverInterface();
}
+ /// \brief Checks if the receiver refers to 'self' or 'super'.
+ bool isReceiverSelfOrSuper() const;
+
/// Returns how the message was written in the source (property access,
/// subscript, or explicit message send).
ObjCMessageKind getMessageKind() const;
@@ -879,6 +939,13 @@ class CallEventManager {
return new (allocate()) T(A1, A2, A3, St, LCtx);
}
+ template <typename T, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+ T *create(Arg1 A1, Arg2 A2, Arg3 A3, Arg4 A4, ProgramStateRef St,
+ const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, A3, A4, St, LCtx);
+ }
+
public:
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
@@ -905,9 +972,9 @@ public:
CallEventRef<CXXDestructorCall>
getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
- const MemRegion *Target, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<CXXDestructorCall>(DD, Trigger, Target, State, LCtx);
+ const MemRegion *Target, bool IsBase,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx);
}
CallEventRef<CXXAllocatorCall>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 8c8e82ce20dd..4558cd9c9480 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -16,10 +16,57 @@
#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
namespace clang {
namespace ento {
+ /// Declares an immutable map of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableMap.
+ ///
+ /// \code
+ /// State = State->set<Name>(K, V);
+ /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
+ /// State = State->remove<Name>(K);
+ /// NameTy Map = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
+ CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
+
+ /// Declares an immutable set of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableSet.
+ ///
+ /// \code
+ /// State = State->add<Name>(E);
+ /// State = State->remove<Name>(E);
+ /// bool Present = State->contains<Name>(E);
+ /// NameTy Set = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
+
+ /// Declares an immutable list of type \p NameTy, suitable for placement into
+ /// the ProgramState. This is implementing using llvm::ImmutableList.
+ ///
+ /// \code
+ /// State = State->add<Name>(E); // Adds to the /end/ of the list.
+ /// bool Present = State->contains<Name>(E);
+ /// NameTy List = State->get<Name>();
+ /// \endcode
+ ///
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
+
+
class CheckerContext {
ExprEngine &Eng;
/// The current exploded(symbolic execution) graph node.
@@ -64,6 +111,10 @@ public:
return Eng.getStoreManager();
}
+ const AnalyzerOptions::ConfigTable &getConfig() const {
+ return Eng.getAnalysisManager().options.Config;
+ }
+
/// \brief Returns the previous node in the exploded graph, which includes
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
@@ -76,8 +127,8 @@ public:
/// \brief Returns the number of times the current block has been visited
/// along the analyzed path.
- unsigned getCurrentBlockCount() const {
- return NB.getContext().getCurrentBlockCount();
+ unsigned blockCount() const {
+ return NB.getContext().blockCount();
}
ASTContext &getASTContext() {
@@ -96,6 +147,9 @@ public:
return Pred->getStackFrame();
}
+ /// Return true if the current LocationContext has no caller context.
+ bool inTopFrame() const { return getLocationContext()->inTopFrame(); }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
@@ -144,20 +198,15 @@ public:
/// \brief Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
- /// @param State The state of the generated node.
+ /// @param State The state of the generated node. If not specified, the state
+ /// will not be changed, but the new node will have the checker's tag.
/// @param Tag The tag is used to uniquely identify the creation site. If no
/// tag is specified, a default tag, unique to the given checker,
/// will be used. Tags are used to prevent states generated at
/// different sites from caching out.
- ExplodedNode *addTransition(ProgramStateRef State,
+ ExplodedNode *addTransition(ProgramStateRef State = 0,
const ProgramPointTag *Tag = 0) {
- return addTransitionImpl(State, false, 0, Tag);
- }
-
- /// \brief Generates a default transition (containing checker tag but no
- /// checker state changes).
- ExplodedNode *addTransition() {
- return addTransition(getState());
+ return addTransitionImpl(State ? State : getState(), false, 0, Tag);
}
/// \brief Generates a new transition with the given predecessor.
@@ -167,25 +216,24 @@ public:
/// @param Pred The transition will be generated from the specified Pred node
/// to the newly generated node.
/// @param Tag The tag to uniquely identify the creation site.
- /// @param IsSink Mark the new node as sink, which will stop exploration of
- /// the given path.
ExplodedNode *addTransition(ProgramStateRef State,
- ExplodedNode *Pred,
- const ProgramPointTag *Tag = 0,
- bool IsSink = false) {
- return addTransitionImpl(State, IsSink, Pred, Tag);
+ ExplodedNode *Pred,
+ const ProgramPointTag *Tag = 0) {
+ return addTransitionImpl(State, false, Pred, Tag);
}
- /// \brief Generate a sink node. Generating sink stops exploration of the
+ /// \brief Generate a sink node. Generating a sink stops exploration of the
/// given path.
- ExplodedNode *generateSink(ProgramStateRef state = 0) {
- return addTransitionImpl(state ? state : getState(), true);
+ ExplodedNode *generateSink(ProgramStateRef State = 0,
+ ExplodedNode *Pred = 0,
+ const ProgramPointTag *Tag = 0) {
+ return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
}
/// \brief Emit the diagnostics report.
- void EmitReport(BugReport *R) {
+ void emitReport(BugReport *R) {
Changed = true;
- Eng.getBugReporter().EmitReport(R);
+ Eng.getBugReporter().emitReport(R);
}
/// \brief Get the declaration of the called function (path-sensitive).
@@ -194,17 +242,33 @@ public:
/// \brief Get the name of the called function (path-sensitive).
StringRef getCalleeName(const FunctionDecl *FunDecl) const;
+ /// \brief Get the identifier of the called function (path-sensitive).
+ const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
+ const FunctionDecl *FunDecl = getCalleeDecl(CE);
+ if (FunDecl)
+ return FunDecl->getIdentifier();
+ else
+ return 0;
+ }
+
/// \brief Get the name of the called function (path-sensitive).
StringRef getCalleeName(const CallExpr *CE) const {
const FunctionDecl *FunDecl = getCalleeDecl(CE);
return getCalleeName(FunDecl);
}
- /// Given a function declaration and a name checks if this is a C lib
- /// function with the given name.
- bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name);
- static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name,
- ASTContext &Context);
+ /// \brief Returns true if the callee is an externally-visible function in the
+ /// top-level namespace, such as \c malloc.
+ ///
+ /// If a name is provided, the function must additionally match the given
+ /// name.
+ ///
+ /// Note that this deliberately excludes C++ library functions in the \c std
+ /// namespace, but will include C library functions accessed through the
+ /// \c std namespace. This also does not check if the function is declared
+ /// as 'extern "C"', or if it uses C++ name mangling.
+ static bool isCLibraryFunction(const FunctionDecl *FD,
+ StringRef Name = StringRef());
/// \brief Depending on wither the location corresponds to a macro, return
/// either the macro name or the token spelling.
@@ -226,9 +290,15 @@ private:
return Pred;
Changed = true;
- ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location,
- State,
- P ? P : Pred, MarkAsSink);
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ if (!P)
+ P = Pred;
+
+ ExplodedNode *node;
+ if (MarkAsSink)
+ node = NB.generateSink(LocalLoc, State, P);
+ else
+ node = NB.generateNode(LocalLoc, State, P);
return node;
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 631858dd7c5b..4a78849024ae 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/Support/SaveAndRestore.h"
namespace llvm {
class APSInt;
@@ -26,29 +27,83 @@ namespace ento {
class SubEngine;
+class ConditionTruthVal {
+ llvm::Optional<bool> Val;
+public:
+ /// Construct a ConditionTruthVal indicating the constraint is constrained
+ /// to either true or false, depending on the boolean value provided.
+ ConditionTruthVal(bool constraint) : Val(constraint) {}
+
+ /// Construct a ConstraintVal indicating the constraint is underconstrained.
+ ConditionTruthVal() {}
+
+ /// Return true if the constraint is perfectly constrained to 'true'.
+ bool isConstrainedTrue() const {
+ return Val.hasValue() && Val.getValue();
+ }
+
+ /// Return true if the constraint is perfectly constrained to 'false'.
+ bool isConstrainedFalse() const {
+ return Val.hasValue() && !Val.getValue();
+ }
+
+ /// Return true if the constrained is perfectly constrained.
+ bool isConstrained() const {
+ return Val.hasValue();
+ }
+
+ /// Return true if the constrained is underconstrained and we do not know
+ /// if the constraint is true of value.
+ bool isUnderconstrained() const {
+ return !Val.hasValue();
+ }
+};
+
class ConstraintManager {
public:
+ ConstraintManager() : NotifyAssumeClients(true) {}
+
virtual ~ConstraintManager();
virtual ProgramStateRef assume(ProgramStateRef state,
- DefinedSVal Cond,
- bool Assumption) = 0;
-
- std::pair<ProgramStateRef, ProgramStateRef >
- assumeDual(ProgramStateRef state, DefinedSVal Cond)
- {
- std::pair<ProgramStateRef, ProgramStateRef > res =
- std::make_pair(assume(state, Cond, true), assume(state, Cond, false));
-
- assert(!(!res.first && !res.second) && "System is over constrained.");
- return res;
+ DefinedSVal Cond,
+ bool Assumption) = 0;
+
+ typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair;
+
+ /// Returns a pair of states (StTrue, StFalse) where the given condition is
+ /// assumed to be true or false, respectively.
+ ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond) {
+ ProgramStateRef StTrue = assume(State, Cond, true);
+
+ // If StTrue is infeasible, asserting the falseness of Cond is unnecessary
+ // because the existing constraints already establish this.
+ if (!StTrue) {
+ // FIXME: This is fairly expensive and should be disabled even in
+ // Release+Asserts builds.
+ assert(assume(State, Cond, false) && "System is over constrained.");
+ return ProgramStatePair((ProgramStateRef)NULL, State);
+ }
+
+ ProgramStateRef StFalse = assume(State, Cond, false);
+ if (!StFalse) {
+ // We are careful to return the original state, /not/ StTrue,
+ // because we want to avoid having callers generate a new node
+ // in the ExplodedGraph.
+ return ProgramStatePair(State, (ProgramStateRef)NULL);
+ }
+
+ return ProgramStatePair(StTrue, StFalse);
}
+ /// \brief If a symbol is perfectly constrained to a constant, attempt
+ /// to return the concrete value.
+ ///
+ /// Note that a ConstraintManager is not obligated to return a concretized
+ /// value for a symbol, even if it is perfectly constrained.
virtual const llvm::APSInt* getSymVal(ProgramStateRef state,
- SymbolRef sym) const = 0;
-
- virtual bool isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const = 0;
+ SymbolRef sym) const {
+ return 0;
+ }
virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) = 0;
@@ -59,20 +114,38 @@ public:
const char *sep) = 0;
virtual void EndPath(ProgramStateRef state) {}
+
+ /// Convenience method to query the state to see if a symbol is null or
+ /// not null, or if neither assumption can be made.
+ ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
+ llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
+
+ return checkNull(State, Sym);
+ }
protected:
+ /// A flag to indicate that clients should be notified of assumptions.
+ /// By default this is the case, but sometimes this needs to be restricted
+ /// to avoid infinite recursions within the ConstraintManager.
+ ///
+ /// Note that this flag allows the ConstraintManager to be re-entrant,
+ /// but not thread-safe.
+ bool NotifyAssumeClients;
+
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
/// reasonably handle a given SVal value. This is typically queried by
/// ExprEngine to determine if the value should be replaced with a
/// conjured symbolic value in order to recover some precision.
virtual bool canReasonAbout(SVal X) const = 0;
+
+ /// Returns whether or not a symbol is known to be null ("true"), known to be
+ /// non-null ("false"), or may be either ("underconstrained").
+ virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
};
-ConstraintManager* CreateBasicConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine);
ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine);
+ SubEngine *subengine);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index e75cdd87596b..b6686409e5aa 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -80,10 +80,6 @@ private:
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
- /// The functions which have been analyzed through inlining. This is owned by
- /// AnalysisConsumer. It can be null.
- SetOfConstDecls *AnalyzedCallees;
-
/// The information about functions shared by the whole translation unit.
/// (This data is owned by AnalysisConsumer.)
FunctionSummariesTy *FunctionSummaries;
@@ -101,19 +97,18 @@ private:
ExplodedNode *Pred);
private:
- CoreEngine(const CoreEngine&); // Do not implement.
- CoreEngine& operator=(const CoreEngine&);
+ CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION;
+ void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION;
ExplodedNode *generateCallExitBeginNode(ExplodedNode *N);
public:
/// Construct a CoreEngine object to analyze the provided CFG.
- CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees,
+ CoreEngine(SubEngine& subengine,
FunctionSummariesTy *FS)
: SubEng(subengine), G(new ExplodedGraph()),
WList(WorkList::makeDFS()),
BCounterFactory(G->getAllocator()),
- AnalyzedCallees(VisitedCallees),
FunctionSummaries(FS){}
/// getGraph - Returns the exploded graph.
@@ -185,20 +180,18 @@ public:
struct NodeBuilderContext {
const CoreEngine &Eng;
const CFGBlock *Block;
- ExplodedNode *Pred;
+ const LocationContext *LC;
NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
- : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); }
-
- ExplodedNode *getPred() const { return Pred; }
+ : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
/// \brief Return the CFGBlock associated with this builder.
const CFGBlock *getBlock() const { return Block; }
/// \brief Returns the number of times the current basic block has been
/// visited on the exploded graph path.
- unsigned getCurrentBlockCount() const {
+ unsigned blockCount() const {
return Eng.WList->getBlockCounter().getNumVisited(
- Pred->getLocationContext()->getCurrentStackFrame(),
+ LC->getCurrentStackFrame(),
Block->getBlockID());
}
};
@@ -265,14 +258,21 @@ public:
virtual ~NodeBuilder() {}
/// \brief Generates a node in the ExplodedGraph.
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, false);
+ }
+
+ /// \brief Generates a sink in the ExplodedGraph.
///
/// When a node is marked as sink, the exploration from the node is stopped -
- /// the node becomes the last node on the path.
- ExplodedNode *generateNode(const ProgramPoint &PP,
+ /// the node becomes the last node on the path and certain kinds of bugs are
+ /// suppressed.
+ ExplodedNode *generateSink(const ProgramPoint &PP,
ProgramStateRef State,
- ExplodedNode *Pred,
- bool MarkAsSink = false) {
- return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ ExplodedNode *Pred) {
+ return generateNodeImpl(PP, State, Pred, true);
}
const ExplodedNodeSet &getResults() {
@@ -317,13 +317,18 @@ public:
NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, ProgramPoint &L)
: NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
+
ExplodedNode *generateNode(ProgramStateRef State,
ExplodedNode *Pred,
- const ProgramPointTag *Tag = 0,
- bool MarkAsSink = false) {
- ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location);
+ const ProgramPointTag *Tag = 0) {
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ return NodeBuilder::generateNode(LocalLoc, State, Pred);
+ }
- ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink);
+ ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
+ const ProgramPointTag *Tag = 0) {
+ const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
+ ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred);
if (N && N->isSink())
sinksGenerated.push_back(N);
return N;
@@ -336,7 +341,7 @@ public:
/// \class StmtNodeBuilder
/// \brief This builder class is useful for generating nodes that resulted from
-/// visiting a statement. The main difference from it's parent NodeBuilder is
+/// visiting a statement. The main difference from its parent NodeBuilder is
/// that it creates a statement specific ProgramPoint.
class StmtNodeBuilder: public NodeBuilder {
NodeBuilder *EnclosingBldr;
@@ -363,22 +368,27 @@ public:
virtual ~StmtNodeBuilder();
+ using NodeBuilder::generateNode;
+ using NodeBuilder::generateSink;
+
ExplodedNode *generateNode(const Stmt *S,
ExplodedNode *Pred,
ProgramStateRef St,
- bool MarkAsSink = false,
const ProgramPointTag *tag = 0,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), tag);
- return generateNodeImpl(L, St, Pred, MarkAsSink);
+ return NodeBuilder::generateNode(L, St, Pred);
}
- ExplodedNode *generateNode(const ProgramPoint &PP,
+ ExplodedNode *generateSink(const Stmt *S,
ExplodedNode *Pred,
- ProgramStateRef State,
- bool MarkAsSink = false) {
- return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ ProgramStateRef St,
+ const ProgramPointTag *tag = 0,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
+ return NodeBuilder::generateSink(L, St, Pred);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
new file mode 100644
index 000000000000..5ac97dbc3145
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -0,0 +1,52 @@
+//== DynamicTypeInfo.h - Runtime type information ----------------*- 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_SA_CORE_DYNAMICTYPEINFO_H
+#define LLVM_CLANG_SA_CORE_DYNAMICTYPEINFO_H
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Stores the currently inferred strictest bound on the runtime type
+/// of a region in a given state along the analysis path.
+class DynamicTypeInfo {
+private:
+ QualType T;
+ bool CanBeASubClass;
+
+public:
+
+ DynamicTypeInfo() : T(QualType()) {}
+ DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
+ : T(WithType), CanBeASubClass(CanBeSub) {}
+
+ /// \brief Return false if no dynamic type info is available.
+ bool isValid() const { return !T.isNull(); }
+
+ /// \brief Returns the currently inferred upper bound on the runtime type.
+ QualType getType() const { return T; }
+
+ /// \brief Returns false if the type information is precise (the type T is
+ /// the only type in the lattice), true otherwise.
+ bool canBeASubClass() const { return CanBeASubClass; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(T);
+ ID.AddInteger((unsigned)CanBeASubClass);
+ }
+ bool operator==(const DynamicTypeInfo &X) const {
+ return T == X.T && CanBeASubClass == X.CanBeASubClass;
+ }
+};
+
+} // end ento
+} // end clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index b80213e249a2..eb9bd85fe64d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -33,10 +33,11 @@ class SValBuilder;
/// other things.
class EnvironmentEntry : public std::pair<const Stmt*,
const StackFrameContext *> {
+ friend class EnvironmentManager;
+ EnvironmentEntry makeLocation() const;
+
public:
- EnvironmentEntry(const Stmt *s, const LocationContext *L)
- : std::pair<const Stmt*,
- const StackFrameContext*>(s, L ? L->getCurrentStackFrame():0) {}
+ EnvironmentEntry(const Stmt *s, const LocationContext *L);
const Stmt *getStmt() const { return first; }
const LocationContext *getLocationContext() const { return second; }
@@ -76,9 +77,7 @@ public:
/// Fetches the current binding of the expression in the
/// Environment.
- SVal getSVal(const EnvironmentEntry &E,
- SValBuilder &svalBuilder,
- bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const;
/// Profile - Profile the contents of an Environment object for use
/// in a FoldingSet.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index 1052d9491a96..b112e66d30d3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -60,45 +60,50 @@ class ExplodedNode : public llvm::FoldingSetNode {
friend class SwitchNodeBuilder;
friend class EndOfFunctionNodeBuilder;
+ /// Efficiently stores a list of ExplodedNodes, or an optional flag.
+ ///
+ /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing
+ /// for the case when there is only one node in the group. This is a fairly
+ /// common case in an ExplodedGraph, where most nodes have only one
+ /// predecessor and many have only one successor. It can also be used to
+ /// store a flag rather than a node list, which ExplodedNode uses to mark
+ /// whether a node is a sink. If the flag is set, the group is implicitly
+ /// empty and no nodes may be added.
class NodeGroup {
- enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
+ // Conceptually a discriminated union. If the low bit is set, the node is
+ // a sink. If the low bit is not set, the pointer refers to the storage
+ // for the nodes in the group.
+ // This is not a PointerIntPair in order to keep the storage type opaque.
uintptr_t P;
-
- unsigned getKind() const {
- return P & 0x1;
- }
-
- void *getPtr() const {
- assert (!getFlag());
- return reinterpret_cast<void*>(P & ~Mask);
- }
-
- ExplodedNode *getNode() const {
- return reinterpret_cast<ExplodedNode*>(getPtr());
- }
public:
- NodeGroup() : P(0) {}
+ NodeGroup(bool Flag = false) : P(Flag) {
+ assert(getFlag() == Flag);
+ }
- ExplodedNode **begin() const;
+ ExplodedNode * const *begin() const;
- ExplodedNode **end() const;
+ ExplodedNode * const *end() const;
unsigned size() const;
- bool empty() const { return (P & ~Mask) == 0; }
+ bool empty() const { return P == 0 || getFlag() != 0; }
+ /// Adds a node to the list.
+ ///
+ /// The group must not have been created with its flag set.
void addNode(ExplodedNode *N, ExplodedGraph &G);
+ /// Replaces the single node in this group with a new node.
+ ///
+ /// Note that this should only be used when you know the group was not
+ /// created with its flag set, and that the group is empty or contains
+ /// only a single node.
void replaceNode(ExplodedNode *node);
- void setFlag() {
- assert(P == 0);
- P = AuxFlag;
- }
-
+ /// Returns whether this group was created with its flag set.
bool getFlag() const {
- return P & AuxFlag ? true : false;
+ return (P & 1);
}
};
@@ -119,9 +124,8 @@ public:
explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
bool IsSink)
- : Location(loc), State(state) {
- if (IsSink)
- Succs.setFlag();
+ : Location(loc), State(state), Succs(IsSink) {
+ assert(isSink() == IsSink);
}
~ExplodedNode() {}
@@ -190,9 +194,9 @@ public:
}
// Iterators over successor and predecessor vertices.
- typedef ExplodedNode** succ_iterator;
+ typedef ExplodedNode* const * succ_iterator;
typedef const ExplodedNode* const * const_succ_iterator;
- typedef ExplodedNode** pred_iterator;
+ typedef ExplodedNode* const * pred_iterator;
typedef const ExplodedNode* const * const_pred_iterator;
pred_iterator pred_begin() { return Preds.begin(); }
@@ -278,11 +282,13 @@ protected:
/// A list of nodes that can be reused.
NodeVector FreeNodes;
- /// A flag that indicates whether nodes should be recycled.
- bool reclaimNodes;
+ /// Determines how often nodes are reclaimed.
+ ///
+ /// If this is 0, nodes will never be reclaimed.
+ unsigned ReclaimNodeInterval;
/// Counter to determine when to reclaim nodes.
- unsigned reclaimCounter;
+ unsigned ReclaimCounter;
public:
@@ -370,7 +376,9 @@ public:
/// Enable tracking of recently allocated nodes for potential reclamation
/// when calling reclaimRecentlyAllocatedNodes().
- void enableNodeReclamation() { reclaimNodes = true; }
+ void enableNodeReclamation(unsigned Interval) {
+ ReclaimCounter = ReclaimNodeInterval = Interval;
+ }
/// Reclaim "uninteresting" nodes created since the last time this method
/// was called.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 4addb9d4ec49..78b254222e9e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
@@ -70,17 +71,14 @@ class ExprEngine : public SubEngine {
/// variables and symbols (as determined by a liveness analysis).
ProgramStateRef CleanedState;
- /// currentStmt - The current block-level statement.
- const Stmt *currentStmt;
- unsigned int currentStmtIdx;
- const NodeBuilderContext *currentBuilderContext;
-
- /// Obj-C Class Identifiers.
- IdentifierInfo* NSExceptionII;
-
- /// Obj-C Selectors.
- Selector* NSExceptionInstanceRaiseSelectors;
- Selector RaiseSel;
+ /// currStmt - The current block-level statement.
+ const Stmt *currStmt;
+ unsigned int currStmtIdx;
+ const NodeBuilderContext *currBldrCtx;
+
+ /// Helper object to determine if an Objective-C message expression
+ /// implicitly never returns.
+ ObjCNoReturn ObjCNoRet;
/// Whether or not GC is enabled in this analysis.
bool ObjCGCEnabled;
@@ -90,9 +88,13 @@ class ExprEngine : public SubEngine {
/// destructor is called before the rest of the ExprEngine is destroyed.
GRBugReporter BR;
+ /// The functions which have been analyzed through inlining. This is owned by
+ /// AnalysisConsumer. It can be null.
+ SetOfConstDecls *VisitedCallees;
+
public:
ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS);
~ExprEngine();
@@ -126,8 +128,8 @@ public:
BugReporter& getBugReporter() { return BR; }
const NodeBuilderContext &getBuilderContext() {
- assert(currentBuilderContext);
- return *currentBuilderContext;
+ assert(currBldrCtx);
+ return *currBldrCtx;
}
bool isObjCGCEnabled() { return ObjCGCEnabled; }
@@ -165,8 +167,12 @@ public:
/// are usually reported here).
/// \param K - In some cases it is possible to use PreStmt kind. (Do
/// not use it unless you know what you are doing.)
+ /// If the ReferenceStmt is NULL, everything is this and parent contexts is
+ /// considered live.
+ /// If the stack frame context is NULL, everything on stack is considered
+ /// dead.
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
- const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *ReferenceStmt, const StackFrameContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
@@ -192,7 +198,8 @@ public:
/// Called by CoreEngine when processing the entrance of a CFGBlock.
virtual void processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder);
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred);
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
@@ -213,7 +220,13 @@ public:
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- void processEndOfFunction(NodeBuilderContext& BC);
+ void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred);
+
+ /// Remove dead bindings/symbols before exiting a function.
+ void removeDeadOnEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// Generate the entry node of the callee.
void processCallEnter(CallEnter CE, ExplodedNode *Pred);
@@ -258,9 +271,6 @@ public:
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
- const BasicValueFactory& getBasicVals() const {
- return StateMgr.getBasicVals();
- }
// FIXME: Remove when we migrate over to just using ValueManager.
SymbolManager& getSymbolManager() { return SymMgr; }
@@ -283,13 +293,14 @@ public:
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- /// VisitAsmStmt - Transfer function logic for inline asm.
- void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ /// VisitGCCAsmStmt - Transfer function logic for inline asm.
+ void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
/// VisitMSAsmStmt - Transfer function logic for MS inline asm.
void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
-
+
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -380,8 +391,8 @@ public:
void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- void VisitCXXDestructor(QualType ObjectType,
- const MemRegion *Dest, const Stmt *S,
+ void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest,
+ const Stmt *S, bool IsBaseDtor,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
@@ -395,14 +406,14 @@ public:
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
+ /// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
- void evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
std::pair<const ProgramPointTag *, const ProgramPointTag*>
- getEagerlyAssumeTags();
+ geteagerlyAssumeBinOpBifurcationTags();
SVal evalMinus(SVal X) {
return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
@@ -433,7 +444,8 @@ protected:
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit = false);
+ SVal location, SVal Val, bool atDeclInit = false,
+ const ProgramPoint *PP = 0);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
@@ -490,6 +502,10 @@ private:
ProgramStateRef St, SVal location,
const ProgramPointTag *tag, bool isLoad);
+ /// Count the stack depth and determine if the call is recursive.
+ void examineStackFrames(const Decl *D, const LocationContext *LCtx,
+ bool &IsRecursive, unsigned &StackDepth);
+
bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
@@ -510,6 +526,8 @@ private:
/// Traits for storing the call processing policy inside GDM.
/// The GDM stores the corresponding CallExpr pointer.
+// FIXME: This does not use the nice trait macros because it must be accessible
+// from multiple translation units.
struct ReplayWithoutInlining{};
template <>
struct ProgramStateTrait<ReplayWithoutInlining> :
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 8044ed839a75..34fbc3ca9e83 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -99,11 +99,11 @@ public:
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
- BlockDataRegionKind,
// Typed regions.
BEG_TYPED_REGIONS,
FunctionTextRegionKind = BEG_TYPED_REGIONS,
BlockTextRegionKind,
+ BlockDataRegionKind,
BEG_TYPED_VALUE_REGIONS,
CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
@@ -140,6 +140,9 @@ public:
const MemRegion *getBaseRegion() const;
+ /// Check if the region is a subregion of the given region.
+ virtual bool isSubRegionOf(const MemRegion *R) const;
+
const MemRegion *StripCasts(bool StripBaseCasts = true) const;
bool hasGlobalsOrParametersStorage() const;
@@ -171,8 +174,6 @@ public:
template<typename RegionTy> const RegionTy* getAs() const;
virtual bool isBoundable() const { return false; }
-
- static bool classof(const MemRegion*) { return true; }
};
/// MemSpaceRegion - A memory region that represents a "memory space";
@@ -416,7 +417,7 @@ public:
MemRegionManager* getMemRegionManager() const;
- bool isSubRegionOf(const MemRegion* R) const;
+ virtual bool isSubRegionOf(const MemRegion* R) const;
static bool classof(const MemRegion* R) {
return R->getKind() > END_MEMSPACES;
@@ -530,16 +531,28 @@ public:
/// FunctionTextRegion - A region that represents code texts of function.
class FunctionTextRegion : public CodeTextRegion {
- const FunctionDecl *FD;
+ const NamedDecl *FD;
public:
- FunctionTextRegion(const FunctionDecl *fd, const MemRegion* sreg)
- : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
+ FunctionTextRegion(const NamedDecl *fd, const MemRegion* sreg)
+ : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {
+ assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
+ }
QualType getLocationType() const {
- return getContext().getPointerType(FD->getType());
+ const ASTContext &Ctx = getContext();
+ if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) {
+ return Ctx.getPointerType(D->getType());
+ }
+
+ assert(isa<ObjCMethodDecl>(FD));
+ assert(false && "Getting the type of ObjCMethod is not supported yet");
+
+ // TODO: We might want to return a different type here (ex: id (*ty)(...))
+ // depending on how it is used.
+ return QualType();
}
-
- const FunctionDecl *getDecl() const {
+
+ const NamedDecl *getDecl() const {
return FD;
}
@@ -547,7 +560,7 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
const MemRegion*);
static bool classof(const MemRegion* R) {
@@ -603,7 +616,7 @@ public:
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
-class BlockDataRegion : public SubRegion {
+class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
const BlockTextRegion *BC;
const LocationContext *LC; // Can be null */
@@ -612,13 +625,15 @@ class BlockDataRegion : public SubRegion {
BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
const MemRegion *sreg)
- : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
ReferencedVars(0), OriginalVars(0) {}
public:
const BlockTextRegion *getCodeRegion() const { return BC; }
const BlockDecl *getDecl() const { return BC->getDecl(); }
+
+ QualType getLocationType() const { return BC->getLocationType(); }
class referenced_vars_iterator {
const MemRegion * const *R;
@@ -1212,7 +1227,7 @@ public:
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
}
- const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
+ const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
CanQualType locTy,
AnalysisDeclContext *AC);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index b0c51dd5b928..86c94deab5e8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SymbolRef, ExprBindKey, and ProgramState*.
+// This file defines the state of the program along the analysisa path.
//
//===----------------------------------------------------------------------===//
@@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
@@ -39,7 +40,7 @@ class CallEvent;
class CallEventManager;
typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
- SubEngine&);
+ SubEngine*);
typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&);
//===----------------------------------------------------------------------===//
@@ -56,32 +57,6 @@ template <typename T> struct ProgramStateTrait {
}
};
-/// \class Stores the dynamic type information.
-/// Information about type of an object at runtime. This is used by dynamic
-/// dispatch implementation.
-class DynamicTypeInfo {
- QualType T;
- bool CanBeASubClass;
-
-public:
- DynamicTypeInfo() : T(QualType()) {}
- DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
- : T(WithType), CanBeASubClass(CanBeSub) {}
-
- bool isValid() const { return !T.isNull(); }
-
- QualType getType() const { return T; }
- bool canBeASubClass() const { return CanBeASubClass; }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- T.Profile(ID);
- ID.AddInteger((unsigned)CanBeASubClass);
- }
- bool operator==(const DynamicTypeInfo &X) const {
- return T == X.T && CanBeASubClass == X.CanBeASubClass;
- }
-};
-
/// \class ProgramState
/// ProgramState - This class encapsulates:
///
@@ -100,7 +75,7 @@ public:
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
private:
- void operator=(const ProgramState& R) const; // Do not implement.
+ void operator=(const ProgramState& R) LLVM_DELETED_FUNCTION;
friend class ProgramStateManager;
friend class ExplodedGraph;
@@ -130,7 +105,12 @@ public:
~ProgramState();
/// Return the ProgramStateManager associated with this state.
- ProgramStateManager &getStateManager() const { return *stateMgr; }
+ ProgramStateManager &getStateManager() const {
+ return *stateMgr;
+ }
+
+ /// Return the ConstraintManager.
+ ConstraintManager &getConstraintManager() const;
/// getEnvironment - Return the environment associated with this state.
/// The environment is the mapping from expressions to values.
@@ -210,11 +190,13 @@ public:
// Binding and retrieving values to/from the environment and symbolic store.
//==---------------------------------------------------------------------==//
- /// BindCompoundLiteral - Return the state that has the bindings currently
- /// in this state plus the bindings for the CompoundLiteral.
+ /// \brief Create a new state with the specified CompoundLiteral binding.
+ /// \param CL the compound literal expression (the binding key)
+ /// \param LC the LocationContext of the binding
+ /// \param V the value to bind.
ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL,
- const LocationContext *LC,
- SVal V) const;
+ const LocationContext *LC,
+ SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
@@ -226,18 +208,16 @@ public:
ProgramStateRef bindExprAndLocation(const Stmt *S,
const LocationContext *LCtx,
SVal location, SVal V) const;
-
- ProgramStateRef bindDecl(const VarRegion *VR, SVal V) const;
- ProgramStateRef bindDeclWithNoInit(const VarRegion *VR) const;
-
- ProgramStateRef bindLoc(Loc location, SVal V) const;
+ ProgramStateRef bindLoc(Loc location,
+ SVal V,
+ bool notifyChanges = true) const;
ProgramStateRef bindLoc(SVal location, SVal V) const;
ProgramStateRef bindDefault(SVal loc, SVal V) const;
- ProgramStateRef unbindLoc(Loc LV) const;
+ ProgramStateRef killBinding(Loc LV) const;
/// invalidateRegions - Returns the state with bindings for the given regions
/// cleared from the store. The regions are provided as a continuous array
@@ -271,11 +251,8 @@ public:
/// Get the lvalue for an array index.
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
- const llvm::APSInt *getSymVal(SymbolRef sym) const;
-
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt *S, const LocationContext *LCtx,
- bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const Stmt *S, const LocationContext *LCtx) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
@@ -469,7 +446,7 @@ public:
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
llvm::BumpPtrAllocator& alloc,
- SubEngine &subeng);
+ SubEngine *subeng);
~ProgramStateManager();
@@ -481,9 +458,6 @@ public:
BasicValueFactory &getBasicVals() {
return svalBuilder->getBasicValueFactory();
}
- const BasicValueFactory& getBasicVals() const {
- return svalBuilder->getBasicValueFactory();
- }
SValBuilder &getSValBuilder() {
return *svalBuilder;
@@ -515,10 +489,6 @@ public:
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
- /// Marshal a new state for the callee in another translation unit.
- /// 'state' is owned by the caller's engine.
- ProgramStateRef MarshalState(ProgramStateRef state, const StackFrameContext *L);
-
public:
SVal ArrayToPointer(Loc Array) {
@@ -617,10 +587,6 @@ public:
return ProgramStateTrait<T>::MakeContext(p);
}
- const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) {
- return ConstraintMgr->getSymVal(St, sym);
- }
-
void EndPath(ProgramStateRef St) {
ConstraintMgr->EndPath(St);
}
@@ -631,6 +597,10 @@ public:
// Out-of-line method definitions for ProgramState.
//===----------------------------------------------------------------------===//
+inline ConstraintManager &ProgramState::getConstraintManager() const {
+ return stateMgr->getConstraintManager();
+}
+
inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
const LocationContext *LC) const
{
@@ -695,15 +665,10 @@ inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) c
return UnknownVal();
}
-inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const {
- return getStateManager().getSymVal(this, sym);
-}
-
-inline SVal ProgramState::getSVal(const Stmt *Ex, const LocationContext *LCtx,
- bool useOnlyDirectBindings) const{
+inline SVal ProgramState::getSVal(const Stmt *Ex,
+ const LocationContext *LCtx) const{
return Env.getSVal(EnvironmentEntry(Ex, LCtx),
- *getStateManager().svalBuilder,
- useOnlyDirectBindings);
+ *getStateManager().svalBuilder);
}
inline SVal
@@ -821,7 +786,7 @@ public:
bool scan(const SymExpr *sym);
};
-} // end GR namespace
+} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index 1c7bedb82f24..ea2a8525ba47 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -31,6 +31,26 @@ namespace clang {
namespace ento {
template <typename T> struct ProgramStatePartialTrait;
+ /// Declares a program state trait for type \p Type called \p Name, and
+ /// introduce a typedef named \c NameTy.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
+ namespace { \
+ class Name {}; \
+ typedef Type Name ## Ty; \
+ } \
+ namespace clang { \
+ namespace ento { \
+ template <> \
+ struct ProgramStateTrait<Name> \
+ : public ProgramStatePartialTrait<Name ## Ty> { \
+ static void *GDMIndex() { static int Index; return &Index; } \
+ }; \
+ } \
+ }
+
+
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
@@ -71,6 +91,15 @@ namespace ento {
}
};
+ /// Helper for registering a map trait.
+ ///
+ /// If the map type were written directly in the invocation of
+ /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
+ /// would be treated as a macro argument separator, which is wrong.
+ /// This allows the user to specify a map type in a way that the preprocessor
+ /// can deal with.
+ #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
+
// Partial-specialization for ImmutableSet.
@@ -113,6 +142,7 @@ namespace ento {
}
};
+
// Partial-specialization for ImmutableList.
template <typename T>
@@ -150,6 +180,7 @@ namespace ento {
delete (typename data_type::Factory*) Ctx;
}
};
+
// Partial specialization for bool.
template <> struct ProgramStatePartialTrait<bool> {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 83c3a5634586..5d72e73a3d94 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -72,7 +72,7 @@ public:
virtual ~SValBuilder() {}
bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
- return haveSameType(Sym1->getType(Context), Sym2->getType(Context));
+ return haveSameType(Sym1->getType(), Sym2->getType());
}
bool haveSameType(QualType Ty1, QualType Ty2) {
@@ -142,19 +142,19 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount,
- const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount, symbolTag);
+ const SymbolConjured* conjureSymbol(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount,
+ const void *symbolTag = 0) {
+ return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr *expr,
- const LocationContext *LCtx,
- unsigned visitCount,
- const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(expr, LCtx, visitCount, symbolTag);
+ const SymbolConjured* conjureSymbol(const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned visitCount,
+ const void *symbolTag = 0) {
+ return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
}
/// Construct an SVal representing '0' for the specified type.
@@ -169,20 +169,20 @@ public:
/// The advantage of symbols derived/built from other symbols is that we
/// preserve the relation between related(or even equivalent) expressions, so
/// conjured symbols should be used sparingly.
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- unsigned count);
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- QualType type,
- unsigned count);
+ DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count);
+ DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned count);
- DefinedOrUnknownSVal getConjuredSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount);
+ DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount);
/// \brief Conjure a symbol representing heap allocated memory region.
///
/// Note, the expression should represent a location.
@@ -227,7 +227,7 @@ public:
BasicVals.getValue(integer->getValue(),
integer->getType()->isUnsignedIntegerOrEnumerationType()));
}
-
+
nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
return makeTruthVal(boolean->getValue(), boolean->getType());
}
@@ -262,11 +262,6 @@ public:
BasicVals.getIntWithPtrWidth(integer, isUnsigned));
}
- NonLoc makeIntVal(uint64_t integer, unsigned bitWidth, bool isUnsigned) {
- return nonloc::ConcreteInt(
- BasicVals.getValue(integer, bitWidth, isUnsigned));
- }
-
NonLoc makeLocAsInteger(Loc loc, unsigned bits) {
return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits));
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index e0b5f64b900b..c2134cf04826 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -154,9 +154,6 @@ public:
SymExpr::symbol_iterator symbol_end() const {
return SymExpr::symbol_end();
}
-
- // Implement isa<T> support.
- static inline bool classof(const SVal*) { return true; }
};
@@ -257,7 +254,7 @@ public:
namespace nonloc {
-enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
+enum Kind { ConcreteIntKind, SymbolValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
/// \brief Represents symbolic expression.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 138a590b1b24..979546b6ed47 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -25,6 +25,7 @@ namespace clang {
class Stmt;
class Expr;
class ObjCIvarDecl;
+class CXXBasePath;
class StackFrameContext;
namespace ento {
@@ -67,15 +68,26 @@ public:
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V);
- virtual StoreRef Remove(Store St, Loc L) = 0;
- /// BindCompoundLiteral - Return the store that has the bindings currently
- /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
- /// for the compound literal and 'BegInit' and 'EndInit' represent an
- /// array of initializer values.
- virtual StoreRef BindCompoundLiteral(Store store,
- const CompoundLiteralExpr *cl,
- const LocationContext *LC, SVal v) = 0;
+ /// \brief Create a new store with the specified binding removed.
+ /// \param ST the original store, that is the basis for the new store.
+ /// \param L the location whose binding should be removed.
+ virtual StoreRef killBinding(Store ST, Loc L) = 0;
+
+ /// \brief Create a new store that binds a value to a compound literal.
+ ///
+ /// \param ST The original store whose bindings are the basis for the new
+ /// store.
+ ///
+ /// \param CL The compound literal to bind (the binding key).
+ ///
+ /// \param LC The LocationContext for the binding.
+ ///
+ /// \param V The value to bind to the compound literal.
+ virtual StoreRef bindCompoundLiteral(Store ST,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
+ SVal V) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
/// value bindings upon entry to an analyzed function.
@@ -114,11 +126,15 @@ public:
/// conversions between arrays and pointers.
virtual SVal ArrayToPointer(Loc Array) = 0;
- /// Evaluates DerivedToBase casts.
- SVal evalDerivedToBase(SVal derived, const CastExpr *Cast);
+ /// Evaluates a chain of derived-to-base casts through the path specified in
+ /// \p Cast.
+ SVal evalDerivedToBase(SVal Derived, const CastExpr *Cast);
+
+ /// Evaluates a chain of derived-to-base casts through the specified path.
+ SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath);
/// Evaluates a derived-to-base cast through a single level of derivation.
- virtual SVal evalDerivedToBase(SVal derived, QualType derivedPtrType) = 0;
+ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType);
/// \brief Evaluates C++ dynamic_cast cast.
/// The callback may result in the following 3 scenarios:
@@ -128,8 +144,7 @@ public:
/// enough info to determine if the cast will succeed at run time).
/// The function returns an SVal representing the derived class; it's
/// valid only if Failed flag is set to false.
- virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,
- bool &Failed) = 0;
+ SVal evalDynamicCast(SVal Base, QualType DerivedPtrType, bool &Failed);
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
@@ -141,10 +156,6 @@ public:
virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
SymbolReaper& SymReaper) = 0;
- virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
-
- virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
-
virtual bool includedInBindings(Store store,
const MemRegion *region) const = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 68b81f19a4fd..1e710778d9be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -60,7 +60,8 @@ public:
/// SubEngine is expected to populate dstNodes with new nodes representing
/// updated analysis state, or generate no nodes at all if it doesn't.
virtual void processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder) = 0;
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
@@ -81,7 +82,8 @@ public:
/// Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- virtual void processEndOfFunction(NodeBuilderContext& BC) = 0;
+ virtual void processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred) = 0;
// Generate the entry node of the callee.
virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 5d27f8654eb0..873f773b459d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -65,12 +65,9 @@ public:
virtual void dumpToStream(raw_ostream &os) const {}
- virtual QualType getType(ASTContext&) const = 0;
+ virtual QualType getType() const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
- // Implement isa<T> support.
- static inline bool classof(const SymExpr*) { return true; }
-
/// \brief Iterator over symbols that the current symbol depends on.
///
/// For SymbolData, it's the symbol itself; for expressions, it's the
@@ -144,7 +141,7 @@ public:
virtual void dumpToStream(raw_ostream &os) const;
- QualType getType(ASTContext&) const;
+ QualType getType() const;
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
@@ -173,7 +170,7 @@ public:
unsigned getCount() const { return Count; }
const void *getTag() const { return SymbolTag; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -211,7 +208,7 @@ public:
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -244,7 +241,7 @@ public:
const SubRegion *getRegion() const { return R; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -283,7 +280,7 @@ public:
unsigned getCount() const { return Count; }
const void *getTag() const { return Tag; }
- QualType getType(ASTContext&) const;
+ QualType getType() const;
virtual void dumpToStream(raw_ostream &os) const;
@@ -320,7 +317,7 @@ public:
SymbolCast(const SymExpr *In, QualType From, QualType To) :
SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
- QualType getType(ASTContext &C) const { return ToTy; }
+ QualType getType() const { return ToTy; }
const SymExpr *getOperand() const { return Operand; }
@@ -358,7 +355,7 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
@@ -399,7 +396,7 @@ public:
const SymExpr *rhs, QualType t)
: SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
BinaryOperator::Opcode getOpcode() const { return Op; }
@@ -446,7 +443,7 @@ public:
// FIXME: We probably need to make this out-of-line to avoid redundant
// generation of virtual functions.
- QualType getType(ASTContext &C) const { return T; }
+ QualType getType() const { return T; }
virtual void dumpToStream(raw_ostream &os) const;
@@ -495,18 +492,17 @@ public:
/// \brief Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
- const SymbolConjured* getConjuredSymbol(const Stmt *E,
- const LocationContext *LCtx,
- QualType T,
- unsigned VisitCount,
- const void *SymbolTag = 0);
+ const SymbolConjured* conjureSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
+ unsigned VisitCount,
+ const void *SymbolTag = 0);
- const SymbolConjured* getConjuredSymbol(const Expr *E,
- const LocationContext *LCtx,
- unsigned VisitCount,
- const void *SymbolTag = 0) {
- return getConjuredSymbol(E, LCtx, E->getType(),
- VisitCount, SymbolTag);
+ const SymbolConjured* conjureSymbol(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned VisitCount,
+ const void *SymbolTag = 0) {
+ return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
@@ -541,7 +537,7 @@ public:
const SymExpr *rhs, QualType t);
QualType getType(const SymExpr *SE) const {
- return SE->getType(Ctx);
+ return SE->getType();
}
/// \brief Add artificial symbol dependency.
@@ -584,9 +580,11 @@ public:
///
/// If the statement is NULL, everything is this and parent contexts is
/// considered live.
- SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr,
+ /// If the stack frame context is NULL, everything on stack is considered
+ /// dead.
+ SymbolReaper(const StackFrameContext *Ctx, const Stmt *s, SymbolManager& symmgr,
StoreManager &storeMgr)
- : LCtx(ctx->getCurrentStackFrame()), Loc(s), SymMgr(symmgr),
+ : LCtx(Ctx), Loc(s), SymMgr(symmgr),
reapedStore(0, storeMgr) {}
~SymbolReaper() {}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index 53205d3b720c..c274cea8413e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -22,6 +22,8 @@ namespace ento {
/// The GDM component containing the tainted root symbols. We lazily infer the
/// taint of the dependent symbols. Currently, this is a map from a symbol to
/// tag kind. TODO: Should support multiple tag kinds.
+// FIXME: This does not use the nice trait macros because it must be accessible
+// from multiple translation units.
struct TaintMap {};
typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl;
template<> struct ProgramStateTrait<TaintMap>
diff --git a/include/clang/Tooling/CommandLineClangTool.h b/include/clang/Tooling/CommandLineClangTool.h
deleted file mode 100644
index c29c30236416..000000000000
--- a/include/clang/Tooling/CommandLineClangTool.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//===- CommandLineClangTool.h - command-line clang tools driver -*- 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 CommandLineClangTool class used to run clang
-// tools as separate command-line applications with a consistent common
-// interface for handling compilation database and input files.
-//
-// It provides a common subset of command-line options, common algorithm
-// for locating a compilation database and source files, and help messages
-// for the basic command-line interface.
-//
-// It creates a CompilationDatabase, initializes a ClangTool and runs a
-// user-specified FrontendAction over all TUs in which the given files are
-// compiled.
-//
-// This class uses the Clang Tooling infrastructure, see
-// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
-// for details on setting it up with LLVM source tree.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H
-#define LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H
-
-#include "llvm/Support/CommandLine.h"
-#include "clang/Tooling/CompilationDatabase.h"
-
-namespace clang {
-
-namespace tooling {
-
-class CompilationDatabase;
-class FrontendActionFactory;
-
-/// \brief A common driver for command-line Clang tools.
-///
-/// Parses a common subset of command-line arguments, locates and loads a
-/// compilation commands database, runs a tool with user-specified action. It
-/// also contains a help message for the common command-line options.
-/// An example of usage:
-/// @code
-/// int main(int argc, const char **argv) {
-/// CommandLineClangTool Tool;
-/// cl::extrahelp MoreHelp("\nMore help text...");
-/// Tool.initialize(argc, argv);
-/// return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
-/// }
-/// @endcode
-///
-class CommandLineClangTool {
-public:
- /// Sets up command-line options and help messages.
- /// Add your own help messages after constructing this tool.
- CommandLineClangTool();
-
- /// Parses command-line, initializes a compilation database.
- /// This method exits program in case of error.
- void initialize(int argc, const char **argv);
-
- /// Runs a clang tool with an action created by \c ActionFactory.
- int run(FrontendActionFactory *ActionFactory);
-
-private:
- llvm::OwningPtr<CompilationDatabase> Compilations;
- llvm::cl::opt<std::string> BuildPath;
- llvm::cl::list<std::string> SourcePaths;
- llvm::cl::extrahelp MoreHelp;
-};
-
-} // namespace tooling
-
-} // namespace clang
-
-#endif // LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMANDLINECLANGTOOL_H
diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h
new file mode 100644
index 000000000000..a1bad1269d80
--- /dev/null
+++ b/include/clang/Tooling/CommonOptionsParser.h
@@ -0,0 +1,89 @@
+//===- CommonOptionsParser.h - common options for clang tools -*- 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 CommonOptionsParser class used to parse common
+// command-line options for clang tools, so that they can be run as separate
+// command-line applications with a consistent common interface for handling
+// compilation database and input files.
+//
+// It provides a common subset of command-line options, common algorithm
+// for locating a compilation database and source files, and help messages
+// for the basic command-line interface.
+//
+// It creates a CompilationDatabase and reads common command-line options.
+//
+// This class uses the Clang Tooling infrastructure, see
+// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+// for details on setting it up with LLVM source tree.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H
+#define LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H
+
+#include "clang/Tooling/CompilationDatabase.h"
+
+namespace clang {
+namespace tooling {
+/// \brief A parser for options common to all command-line Clang tools.
+///
+/// Parses a common subset of command-line arguments, locates and loads a
+/// compilation commands database and runs a tool with user-specified action. It
+/// also contains a help message for the common command-line options.
+///
+/// An example of usage:
+/// \code
+/// #include "clang/Frontend/FrontendActions.h"
+/// #include "clang/Tooling/CommonOptionsParser.h"
+/// #include "llvm/Support/CommandLine.h"
+///
+/// using namespace clang::tooling;
+/// using namespace llvm;
+///
+/// static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+/// static cl::extrahelp MoreHelp("\nMore help text...");
+/// static cl:opt<bool> YourOwnOption(...);
+/// ...
+///
+/// int main(int argc, const char **argv) {
+/// CommonOptionsParser OptionsParser(argc, argv);
+/// ClangTool Tool(OptionsParser.GetCompilations(),
+/// OptionsParser.GetSourcePathListi());
+/// return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+/// }
+/// \endcode
+class CommonOptionsParser {
+public:
+ /// \brief Parses command-line, initializes a compilation database.
+ /// 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);
+
+ /// Returns a reference to the loaded compilations database.
+ CompilationDatabase &GetCompilations() {
+ return *Compilations;
+ }
+
+ /// Returns a list of source file paths to process.
+ std::vector<std::string> GetSourcePathList() {
+ return SourcePathList;
+ }
+
+ static const char *const HelpMessage;
+
+private:
+ llvm::OwningPtr<CompilationDatabase> Compilations;
+ std::vector<std::string> SourcePathList;
+};
+
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_TOOLS_CLANG_INCLUDE_CLANG_TOOLING_COMMONOPTIONSPARSER_H
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index f78ffaed284c..a40bffec78ba 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -31,12 +31,9 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/YAMLParser.h"
+
#include <string>
#include <vector>
@@ -111,6 +108,27 @@ public:
virtual std::vector<std::string> getAllFiles() const = 0;
};
+/// \brief Interface for compilation database plugins.
+///
+/// A compilation database plugin allows the user to register custom compilation
+/// databases that are picked up as compilation database if the corresponding
+/// library is linked in. To register a plugin, declare a static variable like:
+///
+/// \code
+/// static CompilationDatabasePluginRegistry::Add<MyDatabasePlugin>
+/// X("my-compilation-database", "Reads my own compilation database");
+/// \endcode
+class CompilationDatabasePlugin {
+public:
+ virtual ~CompilationDatabasePlugin();
+
+ /// \brief Loads a compilation database from a build directory.
+ ///
+ /// \see CompilationDatabase::loadFromDirectory().
+ virtual CompilationDatabase *loadFromDirectory(StringRef Directory,
+ std::string &ErrorMessage) = 0;
+};
+
/// \brief A compilation database that returns a single compile command line.
///
/// Useful when we want a tool to behave more like a compiler invocation.
@@ -169,75 +187,6 @@ private:
std::vector<CompileCommand> CompileCommands;
};
-/// \brief A JSON based compilation database.
-///
-/// JSON compilation database files must contain a list of JSON objects which
-/// provide the command lines in the attributes 'directory', 'command' and
-/// 'file':
-/// [
-/// { "directory": "<working directory of the compile>",
-/// "command": "<compile command line>",
-/// "file": "<path to source file>"
-/// },
-/// ...
-/// ]
-/// Each object entry defines one compile action. The specified file is
-/// considered to be the main source file for the translation unit.
-///
-/// JSON compilation databases can for example be generated in CMake projects
-/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS.
-class JSONCompilationDatabase : public CompilationDatabase {
-public:
- /// \brief Loads a JSON compilation database from the specified file.
- ///
- /// Returns NULL and sets ErrorMessage if the database could not be
- /// loaded from the given file.
- static JSONCompilationDatabase *loadFromFile(StringRef FilePath,
- std::string &ErrorMessage);
-
- /// \brief Loads a JSON compilation database from a data buffer.
- ///
- /// Returns NULL and sets ErrorMessage if the database could not be loaded.
- static JSONCompilationDatabase *loadFromBuffer(StringRef DatabaseString,
- std::string &ErrorMessage);
-
- /// \brief Returns all compile comamnds in which the specified file was
- /// compiled.
- ///
- /// FIXME: Currently FilePath must be an absolute path inside the
- /// source directory which does not have symlinks resolved.
- virtual std::vector<CompileCommand> getCompileCommands(
- StringRef FilePath) const;
-
- /// \brief Returns the list of all files available in the compilation database.
- ///
- /// These are the 'file' entries of the JSON objects.
- virtual std::vector<std::string> getAllFiles() const;
-
-private:
- /// \brief Constructs a JSON compilation database on a memory buffer.
- JSONCompilationDatabase(llvm::MemoryBuffer *Database)
- : Database(Database), YAMLStream(Database->getBuffer(), SM) {}
-
- /// \brief Parses the database file and creates the index.
- ///
- /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
- /// failed.
- bool parse(std::string &ErrorMessage);
-
- // Tuple (directory, commandline) where 'commandline' pointing to the
- // corresponding nodes in the YAML stream.
- typedef std::pair<llvm::yaml::ScalarNode*,
- llvm::yaml::ScalarNode*> CompileCommandRef;
-
- // Maps file paths to the compile command lines for that file.
- llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
-
- llvm::OwningPtr<llvm::MemoryBuffer> Database;
- llvm::SourceMgr SM;
- llvm::yaml::Stream YAMLStream;
-};
-
} // end namespace tooling
} // end namespace clang
diff --git a/include/clang/Tooling/CompilationDatabasePluginRegistry.h b/include/clang/Tooling/CompilationDatabasePluginRegistry.h
new file mode 100644
index 000000000000..84fcd24b4a12
--- /dev/null
+++ b/include/clang/Tooling/CompilationDatabasePluginRegistry.h
@@ -0,0 +1,27 @@
+//===--- CompilationDatabasePluginRegistry.h - ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
+#define LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace tooling {
+
+class CompilationDatabasePlugin;
+
+typedef llvm::Registry<CompilationDatabasePlugin>
+ CompilationDatabasePluginRegistry;
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_PLUGIN_REGISTRY_H
diff --git a/include/clang/Tooling/FileMatchTrie.h b/include/clang/Tooling/FileMatchTrie.h
new file mode 100644
index 000000000000..ff988bebf2ca
--- /dev/null
+++ b/include/clang/Tooling/FileMatchTrie.h
@@ -0,0 +1,90 @@
+//===--- FileMatchTrie.h - --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a match trie to find the matching file in a compilation
+// database based on a given path in the presence of symlinks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
+#define LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+struct PathComparator {
+ virtual ~PathComparator() {}
+ virtual bool equivalent(StringRef FileA, StringRef FileB) const = 0;
+};
+class FileMatchTrieNode;
+
+/// \brief A trie to efficiently match against the entries of the compilation
+/// database in order of matching suffix length.
+///
+/// When a clang tool is supposed to operate on a specific file, we have to
+/// find the corresponding file in the compilation database. Although entries
+/// in the compilation database are keyed by filename, a simple string match
+/// is insufficient because of symlinks. Commonly, a project hierarchy looks
+/// like this:
+/// /<project-root>/src/<path>/<somefile>.cc (used as input for the tool)
+/// /<project-root>/build/<symlink-to-src>/<path>/<somefile>.cc (stored in DB)
+///
+/// Furthermore, there might be symlinks inside the source folder or inside the
+/// database, so that the same source file is translated with different build
+/// options.
+///
+/// For a given input file, the \c FileMatchTrie finds its entries in order
+/// of matching suffix length. For each suffix length, there might be one or
+/// more entries in the database. For each of those entries, it calls
+/// \c llvm::sys::fs::equivalent() (injected as \c PathComparator). There might
+/// be zero or more entries with the same matching suffix length that are
+/// equivalent to the input file. Three cases are distinguished:
+/// 0 equivalent files: Continue with the next suffix length.
+/// 1 equivalent file: Best match found, return it.
+/// >1 equivalent files: Match is ambiguous, return error.
+class FileMatchTrie {
+public:
+ FileMatchTrie();
+
+ /// \brief Construct a new \c FileMatchTrie with the given \c PathComparator.
+ ///
+ /// The \c FileMatchTrie takes ownership of 'Comparator'. Used for testing.
+ FileMatchTrie(PathComparator* Comparator);
+
+ ~FileMatchTrie();
+
+ /// \brief Insert a new absolute path. Relative paths are ignored.
+ void insert(StringRef NewPath);
+
+ /// \brief Finds the corresponding file in this trie.
+ ///
+ /// Returns file name stored in this trie that is equivalent to 'FileName'
+ /// according to 'Comparator', if it can be uniquely identified. If there
+ /// are no matches an empty \c StringRef is returned. If there are ambigious
+ /// matches, an empty \c StringRef is returned and a corresponding message
+ /// written to 'Error'.
+ StringRef findEquivalent(StringRef FileName,
+ llvm::raw_ostream &Error) const;
+private:
+ FileMatchTrieNode *Root;
+ OwningPtr<PathComparator> Comparator;
+};
+
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_FILE_MATCH_TRIE_H
diff --git a/include/clang/Tooling/JSONCompilationDatabase.h b/include/clang/Tooling/JSONCompilationDatabase.h
new file mode 100644
index 000000000000..d62ab5c5036e
--- /dev/null
+++ b/include/clang/Tooling/JSONCompilationDatabase.h
@@ -0,0 +1,107 @@
+//===--- JSONCompilationDatabase.h - ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The JSONCompilationDatabase finds compilation databases supplied as a file
+// 'compile_commands.json'.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
+#define LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/FileMatchTrie.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// \brief A JSON based compilation database.
+///
+/// JSON compilation database files must contain a list of JSON objects which
+/// provide the command lines in the attributes 'directory', 'command' and
+/// 'file':
+/// [
+/// { "directory": "<working directory of the compile>",
+/// "command": "<compile command line>",
+/// "file": "<path to source file>"
+/// },
+/// ...
+/// ]
+/// Each object entry defines one compile action. The specified file is
+/// considered to be the main source file for the translation unit.
+///
+/// JSON compilation databases can for example be generated in CMake projects
+/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS.
+class JSONCompilationDatabase : public CompilationDatabase {
+public:
+ /// \brief Loads a JSON compilation database from the specified file.
+ ///
+ /// Returns NULL and sets ErrorMessage if the database could not be
+ /// loaded from the given file.
+ static JSONCompilationDatabase *loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage);
+
+ /// \brief Loads a JSON compilation database from a data buffer.
+ ///
+ /// Returns NULL and sets ErrorMessage if the database could not be loaded.
+ static JSONCompilationDatabase *loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage);
+
+ /// \brief Returns all compile comamnds in which the specified file was
+ /// compiled.
+ ///
+ /// FIXME: Currently FilePath must be an absolute path inside the
+ /// source directory which does not have symlinks resolved.
+ virtual std::vector<CompileCommand> getCompileCommands(
+ StringRef FilePath) const;
+
+ /// \brief Returns the list of all files available in the compilation database.
+ ///
+ /// These are the 'file' entries of the JSON objects.
+ virtual std::vector<std::string> getAllFiles() const;
+
+private:
+ /// \brief Constructs a JSON compilation database on a memory buffer.
+ JSONCompilationDatabase(llvm::MemoryBuffer *Database)
+ : Database(Database), YAMLStream(Database->getBuffer(), SM) {}
+
+ /// \brief Parses the database file and creates the index.
+ ///
+ /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
+ /// failed.
+ bool parse(std::string &ErrorMessage);
+
+ // Tuple (directory, commandline) where 'commandline' pointing to the
+ // corresponding nodes in the YAML stream.
+ typedef std::pair<llvm::yaml::ScalarNode*,
+ llvm::yaml::ScalarNode*> CompileCommandRef;
+
+ // Maps file paths to the compile command lines for that file.
+ llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
+
+ FileMatchTrie MatchTrie;
+
+ llvm::OwningPtr<llvm::MemoryBuffer> Database;
+ llvm::SourceMgr SM;
+ llvm::yaml::Stream YAMLStream;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_JSON_COMPILATION_DATABASE_H
diff --git a/include/clang/Tooling/Refactoring.h b/include/clang/Tooling/Refactoring.h
index 0e42a0ec64fc..aaffc1a29e06 100644
--- a/include/clang/Tooling/Refactoring.h
+++ b/include/clang/Tooling/Refactoring.h
@@ -74,6 +74,7 @@ public:
StringRef getFilePath() const { return FilePath; }
unsigned getOffset() const { return Offset; }
unsigned getLength() const { return Length; }
+ StringRef getReplacementText() const { return ReplacementText; }
/// @}
/// \brief Applies the replacement on the Rewriter.
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index e06705f0279b..a03bcb1bbb84 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -74,6 +74,14 @@ public:
template <typename T>
FrontendActionFactory *newFrontendActionFactory();
+/// \brief Called at the end of each source file when used with
+/// \c newFrontendActionFactory.
+class EndOfSourceFileCallback {
+public:
+ virtual ~EndOfSourceFileCallback() {}
+ virtual void run() = 0;
+};
+
/// \brief Returns a new FrontendActionFactory for any type that provides an
/// implementation of newASTConsumer().
///
@@ -87,7 +95,7 @@ FrontendActionFactory *newFrontendActionFactory();
/// newFrontendActionFactory(&Factory);
template <typename FactoryT>
inline FrontendActionFactory *newFrontendActionFactory(
- FactoryT *ConsumerFactory);
+ FactoryT *ConsumerFactory, EndOfSourceFileCallback *EndCallback = NULL);
/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag.
///
@@ -99,6 +107,19 @@ inline FrontendActionFactory *newFrontendActionFactory(
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName = "input.cc");
+/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag and
+/// with additional other flags.
+///
+/// \param ToolAction The action to run over the code.
+/// \param Code C++ code.
+/// \param Args Additional flags to pass on.
+/// \param FileName The file name which 'Code' will be mapped as.
+///
+/// \return - True if 'ToolAction' was successfully executed.
+bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, 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:
@@ -204,34 +225,45 @@ FrontendActionFactory *newFrontendActionFactory() {
template <typename FactoryT>
inline FrontendActionFactory *newFrontendActionFactory(
- FactoryT *ConsumerFactory) {
+ FactoryT *ConsumerFactory, EndOfSourceFileCallback *EndCallback) {
class FrontendActionFactoryAdapter : public FrontendActionFactory {
public:
- explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory)
- : ConsumerFactory(ConsumerFactory) {}
+ explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory,
+ EndOfSourceFileCallback *EndCallback)
+ : ConsumerFactory(ConsumerFactory), EndCallback(EndCallback) {}
virtual clang::FrontendAction *create() {
- return new ConsumerFactoryAdaptor(ConsumerFactory);
+ return new ConsumerFactoryAdaptor(ConsumerFactory, EndCallback);
}
private:
class ConsumerFactoryAdaptor : public clang::ASTFrontendAction {
public:
- ConsumerFactoryAdaptor(FactoryT *ConsumerFactory)
- : ConsumerFactory(ConsumerFactory) {}
+ ConsumerFactoryAdaptor(FactoryT *ConsumerFactory,
+ EndOfSourceFileCallback *EndCallback)
+ : ConsumerFactory(ConsumerFactory), EndCallback(EndCallback) {}
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &,
llvm::StringRef) {
return ConsumerFactory->newASTConsumer();
}
+ protected:
+ virtual void EndSourceFileAction() {
+ if (EndCallback != NULL)
+ EndCallback->run();
+ clang::ASTFrontendAction::EndSourceFileAction();
+ }
+
private:
FactoryT *ConsumerFactory;
+ EndOfSourceFileCallback *EndCallback;
};
FactoryT *ConsumerFactory;
+ EndOfSourceFileCallback *EndCallback;
};
- return new FrontendActionFactoryAdapter(ConsumerFactory);
+ return new FrontendActionFactoryAdapter(ConsumerFactory, EndCallback);
}
/// \brief Returns the absolute path of \c File, by prepending it with
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index f291dec21fda..b57d9964736f 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -14,7 +14,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Lex/Preprocessor.h"
@@ -42,7 +42,7 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
++I;
// Clear the diagnostic and any notes following it.
- List.erase(eraseS, I);
+ I = List.erase(eraseS, I);
continue;
}
@@ -147,54 +147,10 @@ public:
} // end anonymous namespace
-static inline StringRef SimulatorVersionDefineName() {
- return "__IPHONE_OS_VERSION_MIN_REQUIRED=";
-}
-
-/// \brief Parse the simulator version define:
-/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
-// and return the grouped values as integers, e.g:
-// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
-// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(StringRef define,
- unsigned &Major, unsigned &Minor,
- unsigned &Micro) {
- assert(define.startswith(SimulatorVersionDefineName()));
- StringRef name, version;
- llvm::tie(name, version) = define.split('=');
- if (version.empty())
- return false;
- std::string verstr = version.str();
- char *end;
- unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
- if (*end != '\0')
- return false;
- Major = num / 10000;
- num = num % 10000;
- Minor = num / 100;
- Micro = num % 100;
- return true;
-}
-
static bool HasARCRuntime(CompilerInvocation &origCI) {
// This duplicates some functionality from Darwin::AddDeploymentTarget
// but this function is well defined, so keep it decoupled from the driver
// and avoid unrelated complications.
-
- for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size();
- i != e; ++i) {
- StringRef define = origCI.getPreprocessorOpts().Macros[i].first;
- bool isUndef = origCI.getPreprocessorOpts().Macros[i].second;
- if (isUndef)
- continue;
- if (!define.startswith(SimulatorVersionDefineName()))
- continue;
- unsigned Major = 0, Minor = 0, Micro = 0;
- if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
- Major < 10 && Minor < 100 && Micro < 100)
- return Major >= 5;
- }
-
llvm::Triple triple(origCI.getTargetOpts().Triple);
if (triple.getOS() == llvm::Triple::IOS)
@@ -237,18 +193,19 @@ createInvocationForMigration(CompilerInvocation &origCI) {
WarnOpts.push_back("error=arc-unsafe-retained-assign");
CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts);
- CInvok->getLangOpts()->ObjCRuntimeHasWeak = HasARCRuntime(origCI);
+ CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI);
return CInvok.take();
}
static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
- const DiagnosticOptions &diagOpts,
+ DiagnosticOptions *diagOpts,
Preprocessor &PP) {
TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, diagOpts, &printer,
+ /*ShouldOwnClient=*/false));
Diags->setSourceManager(&PP.getSourceManager());
printer.BeginSourceFile(PP.getLangOpts(), &PP);
@@ -286,7 +243,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
assert(DiagClient);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
@@ -314,7 +272,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
}
if (emitPremigrationARCErrors)
- emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(),
+ emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
Unit->getPreprocessor());
if (!plistOut.empty()) {
SmallVector<StoredDiagnostic, 8> arcDiags;
@@ -395,7 +353,8 @@ static bool applyTransforms(CompilerInvocation &origCI,
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
if (outputDir.empty()) {
origCI.getLangOpts()->ObjCAutoRefCount = true;
@@ -434,7 +393,8 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
FileRemapper remapper;
bool err = remapper.initFromDisk(outputDir, *Diags,
@@ -458,7 +418,8 @@ bool arcmt::getFileRemappingsFromFileList(
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
for (ArrayRef<StringRef>::iterator
I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
@@ -574,7 +535,8 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
if (!outputDir.empty()) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
}
}
@@ -593,7 +555,8 @@ bool MigrationProcess::applyTransform(TransformFn trans,
assert(DiagClient);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index f602fc8e5f88..731bcb4fc7f9 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -37,5 +37,6 @@ target_link_libraries(clangARCMigrate
clangAST
clangParse
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
)
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index e9b49b3039ba..28ca9a56b20e 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Frontend/PreprocessorOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/MemoryBuffer.h"
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 935fc9b52535..1966a9823b92 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -11,8 +11,10 @@
#define LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H
#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include <list>
namespace clang {
class Sema;
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 0098f973e63d..dfe14e2b5dd7 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -18,7 +18,7 @@
#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 1175c363163b..805a67d9d188 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -40,7 +40,7 @@ bool MigrationPass::CFBridgingFunctionsDefined() {
bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
bool AllowOnUnknownClass) {
- if (!Ctx.getLangOpts().ObjCRuntimeHasWeak)
+ if (!Ctx.getLangOpts().ObjCARCWeak)
return false;
QualType T = type;
@@ -59,7 +59,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
return false; // id/NSObject is not safe for weak.
if (!AllowOnUnknownClass && !Class->hasDefinition())
return false; // forward classes are not verifiable, therefore not safe.
- if (Class->isArcWeakrefUnavailable())
+ if (Class && Class->isArcWeakrefUnavailable())
return false;
}
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index 1672bc8aed7c..a4e17c03e4e3 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Decl.h"
using namespace clang;
bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
@@ -24,3 +25,7 @@ void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
}
void ASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {}
+
+void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
+ HandleTopLevelDecl(DeclGroupRef(D));
+}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c02132329e6d..74c68ae627ce 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/Comment.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -72,6 +73,22 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return NULL;
}
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ return NULL;
+ }
+
// TODO: handle comments for function parameters properly.
if (isa<ParmVarDecl>(D))
return NULL;
@@ -196,15 +213,72 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
namespace {
/// If we have a 'templated' declaration for a template, adjust 'D' to
/// refer to the actual template.
+/// If we have an implicit instantiation, adjust 'D' to refer to template.
const Decl *adjustDeclToTemplate(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Is this function declaration part of a function template?
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
- D = FTD;
- } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (const ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
- D = CTD;
+ return FTD;
+
+ // Nothing to do if function is not an implicit instantiation.
+ if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+ return D;
+
+ // Function is an implicit instantiation of a function template?
+ if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
+ return FTD;
+
+ // Function is instantiated from a member definition of a class template?
+ if (const FunctionDecl *MemberDecl =
+ FD->getInstantiatedFromMemberFunction())
+ return MemberDecl;
+
+ return D;
}
- // FIXME: Alias templates?
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // Static data member is instantiated from a member definition of a class
+ // template?
+ if (VD->isStaticDataMember())
+ if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
+ return MemberDecl;
+
+ return D;
+ }
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ // Is this class declaration part of a class template?
+ if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
+ return CTD;
+
+ // Class is an implicit instantiation of a class template or partial
+ // specialization?
+ if (const ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
+ if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation)
+ return D;
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ PU = CTSD->getSpecializedTemplateOrPartial();
+ return PU.is<ClassTemplateDecl*>() ?
+ static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) :
+ static_cast<const Decl*>(
+ PU.get<ClassTemplatePartialSpecializationDecl *>());
+ }
+
+ // Class is instantiated from a member definition of a class template?
+ if (const MemberSpecializationInfo *Info =
+ CRD->getMemberSpecializationInfo())
+ return Info->getInstantiatedFrom();
+
+ return D;
+ }
+ if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ // Enum is instantiated from a member definition of a class template?
+ if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
+ return MemberDecl;
+
+ return D;
+ }
+ // FIXME: Adjust alias templates?
return D;
}
} // unnamed namespace
@@ -282,23 +356,83 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
return RC;
}
-comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const {
+static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
+ SmallVectorImpl<const NamedDecl *> &Redeclared) {
+ const DeclContext *DC = ObjCMethod->getDeclContext();
+ if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(DC)) {
+ const ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // Add redeclared method here.
+ for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension();
+ ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ if (ObjCMethodDecl *RedeclaredMethod =
+ ClsExtDecl->getMethod(ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod()))
+ Redeclared.push_back(RedeclaredMethod);
+ }
+ }
+}
+
+comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
+ const Decl *D) const {
+ comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo;
+ ThisDeclInfo->CommentDecl = D;
+ ThisDeclInfo->IsFilled = false;
+ ThisDeclInfo->fill();
+ ThisDeclInfo->CommentDecl = FC->getDecl();
+ comments::FullComment *CFC =
+ new (*this) comments::FullComment(FC->getBlocks(),
+ ThisDeclInfo);
+ return CFC;
+
+}
+
+comments::FullComment *ASTContext::getCommentForDecl(
+ const Decl *D,
+ const Preprocessor *PP) const {
D = adjustDeclToTemplate(D);
+
const Decl *Canonical = D->getCanonicalDecl();
llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos =
ParsedComments.find(Canonical);
- if (Pos != ParsedComments.end())
+
+ if (Pos != ParsedComments.end()) {
+ if (Canonical != D) {
+ comments::FullComment *FC = Pos->second;
+ comments::FullComment *CFC = cloneFullComment(FC, D);
+ return CFC;
+ }
return Pos->second;
-
+ }
+
const Decl *OriginalDecl;
+
const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl);
- if (!RC)
+ if (!RC) {
+ if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
+ SmallVector<const NamedDecl*, 8> Overridden;
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ addRedeclaredMethods(OMD, Overridden);
+ getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden);
+ for (unsigned i = 0, e = Overridden.size(); i < e; i++) {
+ if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) {
+ comments::FullComment *CFC = cloneFullComment(FC, D);
+ return CFC;
+ }
+ }
+ }
return NULL;
-
+ }
+
+ // If the RawComment was attached to other redeclaration of this Decl, we
+ // should parse the comment in context of that other Decl. This is important
+ // because comments can contain references to parameter names which can be
+ // different across redeclarations.
if (D != OriginalDecl)
- return getCommentForDecl(OriginalDecl);
+ return getCommentForDecl(OriginalDecl, PP);
- comments::FullComment *FC = RC->parse(*this, D);
+ comments::FullComment *FC = RC->parse(*this, PP, D);
ParsedComments[Canonical] = FC;
return FC;
}
@@ -481,6 +615,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
Int128Decl(0), UInt128Decl(0),
BuiltinVaListDecl(0),
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
+ BOOLDecl(0),
CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
FILEDecl(0),
jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0),
@@ -495,6 +630,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
+ CommentCommandTraits(BumpAlloc),
LastSDM(0, 0),
UniqueBlockByRefTypeID(0)
{
@@ -683,12 +819,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus) { // C++ 3.9.1p5
+ 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
+ } else // C99 (or C++ using -fno-wchar)
WCharTy = getFromTargetType(Target.getWCharType());
WIntTy = getFromTargetType(Target.getWIntType());
@@ -725,6 +861,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
// Placeholder type for unbridged ARC casts.
InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast);
+ // Placeholder type for builtin functions.
+ InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -909,7 +1048,7 @@ bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -919,7 +1058,7 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -929,7 +1068,7 @@ ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
unsigned
ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method);
+ = OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
return 0;
@@ -938,9 +1077,30 @@ ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const {
void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden) {
+ assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl());
OverriddenMethods[Method].push_back(Overridden);
}
+void ASTContext::getOverriddenMethods(
+ const NamedDecl *D,
+ SmallVectorImpl<const NamedDecl *> &Overridden) const {
+ assert(D);
+
+ if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
+ Overridden.append(CXXMethod->begin_overridden_methods(),
+ CXXMethod->end_overridden_methods());
+ return;
+ }
+
+ const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
+ if (!Method)
+ return;
+
+ SmallVector<const ObjCMethodDecl *, 8> OverDecls;
+ Method->getOverriddenMethods(OverDecls);
+ Overridden.append(OverDecls.begin(), OverDecls.end());
+}
+
void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
assert(!Import->NextLocalImport && "Import declaration already in the chain");
assert(!Import->isFromASTFile() && "Non-local import declaration");
@@ -1062,6 +1222,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
return toCharUnitsFromBits(Align);
}
+// getTypeInfoDataSizeInChars - Return the size of a type, in
+// chars. If the type is a record, its data size is returned. This is
+// the size of the memcpy that's performed when assigning this type
+// using a trivial copy/move assignment operator.
+std::pair<CharUnits, CharUnits>
+ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
+ std::pair<CharUnits, CharUnits> sizeAndAlign = getTypeInfoInChars(T);
+
+ // In C++, objects can sometimes be allocated into the tail padding
+ // of a base-class subobject. We decide whether that's possible
+ // during class layout, so here we can just trust the layout results.
+ if (getLangOpts().CPlusPlus) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl());
+ sizeAndAlign.first = layout.getDataSize();
+ }
+ }
+
+ return sizeAndAlign;
+}
+
std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
@@ -3353,6 +3534,12 @@ QualType ASTContext::getPointerDiffType() const {
return getFromTargetType(Target->getPtrDiffType(0));
}
+/// \brief Return the unique type for "pid_t" defined in
+/// <sys/types.h>. We need this to compute the correct type for vfork().
+QualType ASTContext::getProcessIDType() const {
+ return getFromTargetType(Target->getProcessIDType());
+}
+
//===----------------------------------------------------------------------===//
// Type Operators
//===----------------------------------------------------------------------===//
@@ -3581,11 +3768,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
return Arg;
case TemplateArgument::Declaration: {
- if (Decl *D = Arg.getAsDecl())
- return TemplateArgument(D->getCanonicalDecl());
- return TemplateArgument((Decl*)0);
+ ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
+ return TemplateArgument(D, Arg.isDeclForReferenceParam());
}
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(getCanonicalType(Arg.getNullPtrType()),
+ /*isNullPtr*/true);
+
case TemplateArgument::Template:
return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
@@ -4297,7 +4487,13 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
QualType BlockTy =
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
// Encode result type.
- getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S);
+ if (getLangOpts().EncodeExtendedBlockSig)
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None,
+ BlockTy->getAs<FunctionType>()->getResultType(),
+ S, true /*Extended*/);
+ else
+ getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(),
+ S);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
@@ -4332,7 +4528,11 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
PType = PVDecl->getType();
} else if (PType->isFunctionType())
PType = PVDecl->getType();
- getObjCEncodingForType(PType, S);
+ if (getLangOpts().EncodeExtendedBlockSig)
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, PType,
+ S, true /*Extended*/);
+ else
+ getObjCEncodingForType(PType, S);
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
@@ -5393,6 +5593,65 @@ static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypedefDecl;
}
+static TypedefDecl *
+CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
+ RecordDecl *VaListDecl;
+ if (Context->getLangOpts().CPlusPlus) {
+ // namespace std { struct __va_list {
+ NamespaceDecl *NS;
+ NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ /*Inline*/false, SourceLocation(),
+ SourceLocation(), &Context->Idents.get("std"),
+ /*PrevDecl*/0);
+
+ VaListDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__va_list"));
+
+ VaListDecl->setDeclContext(NS);
+
+ } else {
+ // struct __va_list {
+ VaListDecl = CreateRecordDecl(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ &Context->Idents.get("__va_list"));
+ }
+
+ VaListDecl->startDefinition();
+
+ // void * __ap;
+ FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+ VaListDecl,
+ SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("__ap"),
+ Context->getPointerType(Context->VoidTy),
+ /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ ICIS_NoInit);
+ Field->setAccess(AS_public);
+ VaListDecl->addDecl(Field);
+
+ // };
+ VaListDecl->completeDefinition();
+
+ // typedef struct __va_list __builtin_va_list;
+ TypeSourceInfo *TInfo
+ = Context->getTrivialTypeSourceInfo(Context->getRecordType(VaListDecl));
+
+ TypedefDecl *VaListTypeDecl
+ = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__builtin_va_list"),
+ TInfo);
+
+ return VaListTypeDecl;
+}
+
static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
TargetInfo::BuiltinVaListKind Kind) {
switch (Kind) {
@@ -5406,6 +5665,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateX86_64ABIBuiltinVaListDecl(Context);
case TargetInfo::PNaClABIBuiltinVaList:
return CreatePNaClABIBuiltinVaListDecl(Context);
+ case TargetInfo::AAPCSABIBuiltinVaList:
+ return CreateAAPCSABIBuiltinVaListDecl(Context);
}
llvm_unreachable("Unhandled __builtin_va_list type kind");
@@ -5702,7 +5963,7 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
return false;
}
-/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
+/// 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) {
@@ -5711,8 +5972,8 @@ bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
return false;
}
-/// ObjCQualifiedClassTypesAreCompatible - compare Class<p,...> and
-/// Class<p1, ...>.
+/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
+/// Class<pr1, ...>.
bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
QualType rhs) {
const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>();
@@ -6315,10 +6576,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
for (unsigned i = 0; i < proto_nargs; ++i) {
QualType argTy = proto->getArgType(i);
- // Look at the promotion type of enum types, since that is the type used
+ // Look at the converted type of enum types, since that is the type used
// to pass enum values.
- if (const EnumType *Enum = argTy->getAs<EnumType>())
- argTy = Enum->getDecl()->getPromotionType();
+ if (const EnumType *Enum = argTy->getAs<EnumType>()) {
+ argTy = Enum->getDecl()->getIntegerType();
+ if (argTy.isNull())
+ return QualType();
+ }
if (argTy->isPromotableIntegerType() ||
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
@@ -6725,7 +6989,7 @@ unsigned ASTContext::getIntWidth(QualType T) const {
return (unsigned)getTypeSize(T);
}
-QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
+QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
assert(T->hasSignedIntegerRepresentation() && "Unexpected type");
// Turn <4 x signed int> -> <4 x unsigned int>
@@ -6959,6 +7223,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
return QualType();
}
break;
+ case 'p':
+ Type = Context.getProcessIDType();
+ break;
}
// If there are modifiers and if we're allowed to parse them, go for it.
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index a605f1a40cb3..0b9c5249448f 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -430,6 +430,15 @@ class TemplateDiff {
/// arguments or the type arguments that are templates.
TemplateDecl *FromTD, *ToTD;
+ /// FromQual, ToQual - Qualifiers for template types.
+ Qualifiers FromQual, ToQual;
+
+ /// FromInt, ToInt - APSInt's for integral arguments.
+ llvm::APSInt FromInt, ToInt;
+
+ /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
+ bool IsValidFromInt, IsValidToInt;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -480,6 +489,21 @@ class TemplateDiff {
FlatTree[CurrentNode].ToExpr = ToExpr;
}
+ /// SetNode - Set FromInt and ToInt of the current node.
+ void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt,
+ bool IsValidFromInt, bool IsValidToInt) {
+ FlatTree[CurrentNode].FromInt = FromInt;
+ FlatTree[CurrentNode].ToInt = ToInt;
+ FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt;
+ FlatTree[CurrentNode].IsValidToInt = IsValidToInt;
+ }
+
+ /// SetNode - Set FromQual and ToQual of the current node.
+ void SetNode(Qualifiers FromQual, Qualifiers ToQual) {
+ FlatTree[CurrentNode].FromQual = FromQual;
+ FlatTree[CurrentNode].ToQual = ToQual;
+ }
+
/// SetSame - Sets the same flag of the current node.
void SetSame(bool Same) {
FlatTree[CurrentNode].Same = Same;
@@ -557,6 +581,12 @@ class TemplateDiff {
(FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD);
}
+ /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's.
+ bool NodeIsAPSInt() {
+ return FlatTree[ReadNode].IsValidFromInt ||
+ FlatTree[ReadNode].IsValidToInt;
+ }
+
/// GetNode - Gets the FromType and ToType.
void GetNode(QualType &FromType, QualType &ToType) {
FromType = FlatTree[ReadNode].FromType;
@@ -575,6 +605,21 @@ class TemplateDiff {
ToTD = FlatTree[ReadNode].ToTD;
}
+ /// GetNode - Gets the FromInt and ToInt.
+ void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
+ bool &IsValidFromInt, bool &IsValidToInt) {
+ FromInt = FlatTree[ReadNode].FromInt;
+ ToInt = FlatTree[ReadNode].ToInt;
+ IsValidFromInt = FlatTree[ReadNode].IsValidFromInt;
+ IsValidToInt = FlatTree[ReadNode].IsValidToInt;
+ }
+
+ /// GetNode - Gets the FromQual and ToQual.
+ void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) {
+ FromQual = FlatTree[ReadNode].FromQual;
+ ToQual = FlatTree[ReadNode].ToQual;
+ }
+
/// NodeIsSame - Returns true the arguments are the same.
bool NodeIsSame() {
return FlatTree[ReadNode].Same;
@@ -778,18 +823,21 @@ class TemplateDiff {
if (Context.hasSameType(FromType, ToType)) {
Tree.SetSame(true);
} else {
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
const TemplateSpecializationType *FromArgTST =
GetTemplateSpecializationType(Context, FromType);
const TemplateSpecializationType *ToArgTST =
GetTemplateSpecializationType(Context, ToType);
- if (FromArgTST && ToArgTST) {
- bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST);
- if (SameTemplate) {
- Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
- ToArgTST->getTemplateName().getAsTemplateDecl());
- DiffTemplate(FromArgTST, ToArgTST);
- }
+ if (FromArgTST && ToArgTST &&
+ hasSameTemplate(FromArgTST, ToArgTST)) {
+ FromQual -= QualType(FromArgTST, 0).getQualifiers();
+ ToQual -= QualType(ToArgTST, 0).getQualifiers();
+ Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
+ ToArgTST->getTemplateName().getAsTemplateDecl());
+ Tree.SetNode(FromQual, ToQual);
+ DiffTemplate(FromArgTST, ToArgTST);
}
}
}
@@ -799,12 +847,41 @@ class TemplateDiff {
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
Expr *FromExpr, *ToExpr;
- GetExpr(FromIter, DefaultNTTPD, FromExpr);
- GetExpr(ToIter, DefaultNTTPD, ToExpr);
- Tree.SetNode(FromExpr, ToExpr);
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
- Tree.SetDefault(FromIter.isEnd() && FromExpr,
- ToIter.isEnd() && ToExpr);
+ llvm::APSInt FromInt, ToInt;
+ bool HasFromInt = !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::Integral;
+ bool HasToInt = !ToIter.isEnd() &&
+ ToIter->getKind() == TemplateArgument::Integral;
+ //bool IsValidFromInt = false, IsValidToInt = false;
+ if (HasFromInt)
+ FromInt = FromIter->getAsIntegral();
+ else
+ GetExpr(FromIter, DefaultNTTPD, FromExpr);
+
+ if (HasToInt)
+ ToInt = ToIter->getAsIntegral();
+ else
+ GetExpr(ToIter, DefaultNTTPD, ToExpr);
+
+ if (!HasFromInt && !HasToInt) {
+ Tree.SetNode(FromExpr, ToExpr);
+ Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
+ Tree.SetDefault(FromIter.isEnd() && FromExpr,
+ ToIter.isEnd() && ToExpr);
+ } else {
+ if (!HasFromInt && FromExpr) {
+ FromInt = FromExpr->EvaluateKnownConstInt(Context);
+ HasFromInt = true;
+ }
+ if (!HasToInt && ToExpr) {
+ ToInt = ToExpr->EvaluateKnownConstInt(Context);
+ HasToInt = true;
+ }
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt));
+ Tree.SetDefault(FromIter.isEnd() && HasFromInt,
+ ToIter.isEnd() && HasToInt);
+ }
}
// Handle Templates
@@ -824,6 +901,26 @@ class TemplateDiff {
}
}
+ /// makeTemplateList - Dump every template alias into the vector.
+ static void makeTemplateList(
+ SmallVector<const TemplateSpecializationType*, 1> &TemplateList,
+ const TemplateSpecializationType *TST) {
+ while (TST) {
+ TemplateList.push_back(TST);
+ if (!TST->isTypeAlias())
+ return;
+ TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
+ }
+ }
+
+ /// hasSameBaseTemplate - Returns true when the base templates are the same,
+ /// even if the template arguments are not.
+ static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
+ const TemplateSpecializationType *ToTST) {
+ return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
+ ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier();
+ }
+
/// hasSameTemplate - Returns true if both types are specialized from the
/// same template declaration. If they come from different template aliases,
/// do a parallel ascension search to determine the highest template alias in
@@ -831,49 +928,29 @@ class TemplateDiff {
static bool hasSameTemplate(const TemplateSpecializationType *&FromTST,
const TemplateSpecializationType *&ToTST) {
// Check the top templates if they are the same.
- if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (hasSameBaseTemplate(FromTST, ToTST))
return true;
// Create vectors of template aliases.
SmallVector<const TemplateSpecializationType*, 1> FromTemplateList,
ToTemplateList;
- const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST;
- FromTemplateList.push_back(FromTST);
- ToTemplateList.push_back(ToTST);
-
- // Dump every template alias into the vectors.
- while (TempFromTST->isTypeAlias()) {
- TempFromTST =
- TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>();
- if (!TempFromTST)
- break;
- FromTemplateList.push_back(TempFromTST);
- }
- while (TempToTST->isTypeAlias()) {
- TempToTST =
- TempToTST->getAliasedType()->getAs<TemplateSpecializationType>();
- if (!TempToTST)
- break;
- ToTemplateList.push_back(TempToTST);
- }
+ makeTemplateList(FromTemplateList, FromTST);
+ makeTemplateList(ToTemplateList, ToTST);
SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
// Check if the lowest template types are the same. If not, return.
- if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
- (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (!hasSameBaseTemplate(*FromIter, *ToIter))
return false;
// Begin searching up the template aliases. The bottom most template
// matches so move up until one pair does not match. Use the template
// right before that one.
for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {
- if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() !=
- (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier())
+ if (!hasSameBaseTemplate(*FromIter, *ToIter))
break;
}
@@ -923,7 +1000,9 @@ class TemplateDiff {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
- TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
+ TemplateDecl *DefaultTD = 0;
+ if (TA.getKind() != TemplateArgument::Null)
+ DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
if (!Iter.isEnd())
ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();
@@ -1018,6 +1097,15 @@ class TemplateDiff {
Tree.ToDefault(), Tree.NodeIsSame());
return;
}
+
+ if (Tree.NodeIsAPSInt()) {
+ llvm::APSInt FromInt, ToInt;
+ bool IsValidFromInt, IsValidToInt;
+ Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
+ PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
llvm_unreachable("Unable to deduce template difference.");
}
@@ -1027,6 +1115,10 @@ class TemplateDiff {
assert(Tree.HasChildren() && "Template difference not found in diff tree.");
+ Qualifiers FromQual, ToQual;
+ Tree.GetNode(FromQual, ToQual);
+ PrintQualifiers(FromQual, ToQual);
+
OS << FromTD->getNameAsString() << '<';
Tree.MoveToChild();
unsigned NumElideArgs = 0;
@@ -1088,6 +1180,17 @@ class TemplateDiff {
return;
}
+ if (!FromType.isNull() && !ToType.isNull() &&
+ FromType.getLocalUnqualifiedType() ==
+ ToType.getLocalUnqualifiedType()) {
+ Qualifiers FromQual = FromType.getLocalQualifiers(),
+ ToQual = ToType.getLocalQualifiers(),
+ CommonQual;
+ PrintQualifiers(FromQual, ToQual);
+ FromType.getLocalUnqualifiedType().print(OS, Policy);
+ return;
+ }
+
std::string FromTypeStr = FromType.isNull() ? "(no argument)"
: FromType.getAsString();
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
@@ -1177,6 +1280,34 @@ class TemplateDiff {
}
}
+ /// PrintAPSInt - Handles printing of integral arguments, highlighting
+ /// argument differences.
+ void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
+ bool IsValidFromInt, bool IsValidToInt, bool FromDefault,
+ bool ToDefault, bool Same) {
+ assert((IsValidFromInt || IsValidToInt) &&
+ "Only one integral argument may be missing.");
+
+ if (Same) {
+ OS << FromInt.toString(10);
+ } else if (!PrintTree) {
+ OS << (FromDefault ? "(default) " : "");
+ Bold();
+ OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ Unbold();
+ } else {
+ OS << (FromDefault ? "[(default) " : "[");
+ Bold();
+ OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ Unbold();
+ OS << " != " << (ToDefault ? "(default) " : "");
+ Bold();
+ OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)");
+ Unbold();
+ OS << ']';
+ }
+ }
+
// Prints the appropriate placeholder for elided template arguments.
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {
if (PrintTree) {
@@ -1191,6 +1322,68 @@ class TemplateDiff {
OS << "[" << NumElideArgs << " * ...]";
}
+ // Prints and highlights differences in Qualifiers.
+ void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) {
+ // Both types have no qualifiers
+ if (FromQual.empty() && ToQual.empty())
+ return;
+
+ // Both types have same qualifiers
+ if (FromQual == ToQual) {
+ PrintQualifier(FromQual, /*ApplyBold*/false);
+ return;
+ }
+
+ // Find common qualifiers and strip them from FromQual and ToQual.
+ Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual,
+ ToQual);
+
+ // The qualifiers are printed before the template name.
+ // Inline printing:
+ // The common qualifiers are printed. Then, qualifiers only in this type
+ // are printed and highlighted. Finally, qualifiers only in the other
+ // type are printed and highlighted inside parentheses after "missing".
+ // Tree printing:
+ // Qualifiers are printed next to each other, inside brackets, and
+ // separated by "!=". The printing order is:
+ // common qualifiers, highlighted from qualifiers, "!=",
+ // common qualifiers, highlighted to qualifiers
+ if (PrintTree) {
+ OS << "[";
+ if (CommonQual.empty() && FromQual.empty()) {
+ Bold();
+ OS << "(no qualifiers) ";
+ Unbold();
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false);
+ PrintQualifier(FromQual, /*ApplyBold*/true);
+ }
+ OS << "!= ";
+ if (CommonQual.empty() && ToQual.empty()) {
+ Bold();
+ OS << "(no qualifiers)";
+ Unbold();
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false,
+ /*appendSpaceIfNonEmpty*/!ToQual.empty());
+ PrintQualifier(ToQual, /*ApplyBold*/true,
+ /*appendSpaceIfNonEmpty*/false);
+ }
+ OS << "] ";
+ } else {
+ PrintQualifier(CommonQual, /*ApplyBold*/false);
+ PrintQualifier(FromQual, /*ApplyBold*/true);
+ }
+ }
+
+ void PrintQualifier(Qualifiers Q, bool ApplyBold,
+ bool AppendSpaceIfNonEmpty = true) {
+ if (Q.empty()) return;
+ if (ApplyBold) Bold();
+ Q.print(OS, Policy, AppendSpaceIfNonEmpty);
+ if (ApplyBold) Unbold();
+ }
+
public:
TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
@@ -1210,6 +1403,9 @@ public:
/// DiffTemplate - Start the template type diffing.
void DiffTemplate() {
+ Qualifiers FromQual = FromType.getQualifiers(),
+ ToQual = ToType.getQualifiers();
+
const TemplateSpecializationType *FromOrigTST =
GetTemplateSpecializationType(Context, FromType);
const TemplateSpecializationType *ToOrigTST =
@@ -1224,7 +1420,10 @@ public:
return;
}
+ FromQual -= QualType(FromOrigTST, 0).getQualifiers();
+ ToQual -= QualType(ToOrigTST, 0).getQualifiers();
Tree.SetNode(FromType, ToType);
+ Tree.SetNode(FromQual, ToQual);
// Same base template, but different arguments.
Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 3e952acdcb42..0d4f303af2b5 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -228,16 +228,12 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
- if (!Complain)
- return DiagnosticBuilder::getEmpty();
-
+ assert(Complain && "Not allowed to complain");
return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
- if (!Complain)
- return DiagnosticBuilder::getEmpty();
-
+ assert(Complain && "Not allowed to complain");
return C2.getDiagnostics().Report(Loc, DiagID);
}
};
@@ -288,7 +284,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case TemplateArgument::Type:
return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
-
+
case TemplateArgument::Integral:
if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
Arg2.getIntegralType()))
@@ -297,10 +293,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
case TemplateArgument::Declaration:
- if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
- return !Arg1.getAsDecl() && !Arg2.getAsDecl();
return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
-
+
+ case TemplateArgument::NullPtr:
+ return true; // FIXME: Is this correct?
+
case TemplateArgument::Template:
return IsStructurallyEquivalent(Context,
Arg1.getAsTemplate(),
@@ -822,33 +819,47 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
FieldDecl *Field1, FieldDecl *Field2) {
RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
-
- if (!IsStructurallyEquivalent(Context,
+
+ // For anonymous structs/unions, match up the anonymous struct/union type
+ // declarations directly, so that we don't go off searching for anonymous
+ // types
+ if (Field1->isAnonymousStructOrUnion() &&
+ Field2->isAnonymousStructOrUnion()) {
+ RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+ return IsStructurallyEquivalent(Context, D1, D2);
+ }
+
+ if (!IsStructurallyEquivalent(Context,
Field1->getType(), Field2->getType())) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ }
return false;
}
if (Field1->isBitField() != Field2->isBitField()) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- if (Field1->isBitField()) {
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Field1->getBitWidthValue(Context.C1);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Field2->getBitWidthValue(Context.C2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
- << Field1->getDeclName();
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ if (Field1->isBitField()) {
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Field1->getBitWidthValue(Context.C1);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Field2->getBitWidthValue(Context.C2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
}
return false;
}
@@ -859,12 +870,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
unsigned Bits2 = Field2->getBitWidthValue(Context.C2);
if (Bits1 != Bits2) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType() << Bits2;
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType() << Bits1;
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType() << Bits2;
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType() << Bits1;
+ }
return false;
}
}
@@ -872,17 +885,65 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+/// \brief Find the index of the given anonymous struct/union within its
+/// context.
+///
+/// \returns Returns the index of this anonymous struct/union in its context,
+/// including the next assigned index (if none of them match). Returns an
+/// empty option if the context is not a record, i.e.. if the anonymous
+/// struct/union is at namespace or block scope.
+static llvm::Optional<unsigned>
+findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
+ ASTContext &Context = Anon->getASTContext();
+ QualType AnonTy = Context.getRecordType(Anon);
+
+ RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
+ if (!Owner)
+ return llvm::Optional<unsigned>();
+
+ unsigned Index = 0;
+ for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+ DEnd = Owner->noload_decls_end();
+ D != DEnd; ++D) {
+ FieldDecl *F = dyn_cast<FieldDecl>(*D);
+ if (!F || !F->isAnonymousStructOrUnion())
+ continue;
+
+ if (Context.hasSameType(F->getType(), AnonTy))
+ break;
+
+ ++Index;
+ }
+
+ return Index;
+}
+
/// \brief Determine structural equivalence of two records.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
RecordDecl *D1, RecordDecl *D2) {
if (D1->isUnion() != D2->isUnion()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
- << D1->getDeclName() << (unsigned)D1->getTagKind();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ }
return false;
}
-
+
+ if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
+ // If both anonymous structs/unions are in a record context, make sure
+ // they occur in the same location in the context records.
+ if (llvm::Optional<unsigned> Index1
+ = findAnonymousStructOrUnionIndex(D1)) {
+ if (llvm::Optional<unsigned> Index2
+ = findAnonymousStructOrUnionIndex(D2)) {
+ if (*Index1 != *Index2)
+ return false;
+ }
+ }
+ }
+
// If both declarations are class template specializations, we know
// the ODR applies, so check the template and template arguments.
ClassTemplateSpecializationDecl *Spec1
@@ -920,12 +981,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
- Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ }
return false;
}
@@ -937,38 +1000,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
++Base1, ++Base2) {
if (!IsStructurallyEquivalent(Context,
Base1->getType(), Base2->getType())) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
- << Base2->getType()
- << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
+ << Base2->getType()
+ << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ }
return false;
}
// Check virtual vs. non-virtual inheritance mismatch.
if (Base1->isVirtual() != Base2->isVirtual()) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(),
- diag::note_odr_virtual_base)
- << Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->isVirtual()
- << Base1->getSourceRange();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(),
+ diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->isVirtual()
+ << Base1->getSourceRange();
+ }
return false;
}
}
} else if (D1CXX->getNumBases() > 0) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ }
return false;
}
}
@@ -981,11 +1050,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Field1 != Field1End;
++Field1, ++Field2) {
if (Field2 == Field2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ }
return false;
}
@@ -994,11 +1065,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
if (Field2 != Field2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ }
return false;
}
@@ -1014,12 +1087,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
EC1End = D1->enumerator_end();
EC1 != EC1End; ++EC1, ++EC2) {
if (EC2 == EC2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ }
return false;
}
@@ -1027,25 +1102,29 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
llvm::APSInt Val2 = EC2->getInitVal();
if (!llvm::APSInt::isSameValue(Val1, Val2) ||
!IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ }
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ if (Context.Complain) {
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
<< Context.C2.getTypeDeclType(D2);
Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
<< EC2->getDeclName()
<< EC2->getInitVal().toString(10);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- return false;
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
}
- }
-
- if (EC2 != EC2End) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
return false;
}
@@ -1056,20 +1135,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateParameterList *Params1,
TemplateParameterList *Params2) {
if (Params1->size() != Params2->size()) {
- Context.Diag2(Params2->getTemplateLoc(),
- diag::err_odr_different_num_template_parameters)
- << Params1->size() << Params2->size();
- Context.Diag1(Params1->getTemplateLoc(),
- diag::note_odr_template_parameter_list);
+ if (Context.Complain) {
+ Context.Diag2(Params2->getTemplateLoc(),
+ diag::err_odr_different_num_template_parameters)
+ << Params1->size() << Params2->size();
+ Context.Diag1(Params1->getTemplateLoc(),
+ diag::note_odr_template_parameter_list);
+ }
return false;
}
for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
- Context.Diag2(Params2->getParam(I)->getLocation(),
- diag::err_odr_different_template_parameter_kind);
- Context.Diag1(Params1->getParam(I)->getLocation(),
- diag::note_odr_template_parameter_here);
+ if (Context.Complain) {
+ Context.Diag2(Params2->getParam(I)->getLocation(),
+ diag::err_odr_different_template_parameter_kind);
+ Context.Diag1(Params1->getParam(I)->getLocation(),
+ diag::note_odr_template_parameter_here);
+ }
return false;
}
@@ -1087,10 +1170,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTypeParmDecl *D1,
TemplateTypeParmDecl *D2) {
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
@@ -1100,24 +1185,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NonTypeTemplateParmDecl *D1,
NonTypeTemplateParmDecl *D2) {
- // FIXME: Enable once we have variadic templates.
-#if 0
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
-#endif
// Check types.
if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
- Context.Diag2(D2->getLocation(),
- diag::err_odr_non_type_parameter_type_inconsistent)
- << D2->getType() << D1->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
- << D1->getType();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::err_odr_non_type_parameter_type_inconsistent)
+ << D2->getType() << D1->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
+ << D1->getType();
+ }
return false;
}
@@ -1127,17 +1213,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TemplateTemplateParmDecl *D1,
TemplateTemplateParmDecl *D2) {
- // FIXME: Enable once we have variadic templates.
-#if 0
if (D1->isParameterPack() != D2->isParameterPack()) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
return false;
}
-#endif
-
+
// Check template parameter lists.
return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
D2->getTemplateParameters());
@@ -1509,11 +1594,26 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ExceptionTypes.push_back(ExceptionType);
}
- FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo();
- EPI.Exceptions = ExceptionTypes.data();
-
+ FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo ToEPI;
+
+ ToEPI.ExtInfo = FromEPI.ExtInfo;
+ ToEPI.Variadic = FromEPI.Variadic;
+ ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn;
+ ToEPI.TypeQuals = FromEPI.TypeQuals;
+ ToEPI.RefQualifier = FromEPI.RefQualifier;
+ ToEPI.NumExceptions = ExceptionTypes.size();
+ ToEPI.Exceptions = ExceptionTypes.data();
+ ToEPI.ConsumedArguments = FromEPI.ConsumedArguments;
+ ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType;
+ ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr);
+ ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpecDecl));
+ ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
+ Importer.Import(FromEPI.ExceptionSpecTemplate));
+
return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), EPI);
+ ArgTypes.size(), ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1961,11 +2061,20 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
return TemplateArgument(From, ToType);
}
- case TemplateArgument::Declaration:
- if (Decl *To = Importer.Import(From.getAsDecl()))
- return TemplateArgument(To);
+ case TemplateArgument::Declaration: {
+ ValueDecl *FromD = From.getAsDecl();
+ if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD)))
+ return TemplateArgument(To, From.isDeclForReferenceParam());
return TemplateArgument();
-
+ }
+
+ case TemplateArgument::NullPtr: {
+ QualType ToType = Importer.Import(From.getNullPtrType());
+ if (ToType.isNull())
+ return TemplateArgument();
+ return TemplateArgument(ToType, /*isNullPtr*/true);
+ }
+
case TemplateArgument::Template: {
TemplateName ToTemplate = Importer.Import(From.getAsTemplate());
if (ToTemplate.isNull())
@@ -2318,6 +2427,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+ if (D->isAnonymousStructOrUnion() &&
+ FoundRecord->isAnonymousStructOrUnion()) {
+ // If both anonymous structs/unions are in a record context, make sure
+ // they occur in the same location in the context records.
+ if (llvm::Optional<unsigned> Index1
+ = findAnonymousStructOrUnionIndex(D)) {
+ if (llvm::Optional<unsigned> Index2
+ = findAnonymousStructOrUnionIndex(FoundRecord)) {
+ if (*Index1 != *Index2)
+ continue;
+ }
+ }
+ }
+
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
if ((SearchName && !D->isCompleteDefinition())
|| (D->isCompleteDefinition() &&
@@ -2491,8 +2614,30 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import additional name location/type info.
ImportDeclarationNameLoc(D->getNameInfo(), NameInfo);
+ QualType FromTy = D->getType();
+ bool usedDifferentExceptionSpec = false;
+
+ if (const FunctionProtoType *
+ FromFPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
+ // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
+ // FunctionDecl that we are importing the FunctionProtoType for.
+ // To avoid an infinite recursion when importing, create the FunctionDecl
+ // with a simplified function type and update it afterwards.
+ if (FromEPI.ExceptionSpecDecl || FromEPI.ExceptionSpecTemplate ||
+ FromEPI.NoexceptExpr) {
+ FunctionProtoType::ExtProtoInfo DefaultEPI;
+ FromTy = Importer.getFromContext().getFunctionType(
+ FromFPT->getResultType(),
+ FromFPT->arg_type_begin(),
+ FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ DefaultEPI);
+ usedDifferentExceptionSpec = true;
+ }
+ }
+
// Import the type.
- QualType T = Importer.Import(D->getType());
+ QualType T = Importer.Import(FromTy);
if (T.isNull())
return 0;
@@ -2572,6 +2717,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
ToFunction->setParams(Parameters);
+ if (usedDifferentExceptionSpec) {
+ // Update FunctionProtoType::ExtProtoInfo.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ ToFunction->setType(T);
+ }
+
// FIXME: Other bits to merge?
// Add this function to the lexical context.
@@ -2596,6 +2749,25 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) {
return VisitCXXMethodDecl(D);
}
+static unsigned getFieldIndex(Decl *F) {
+ RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
+ if (!Owner)
+ return 0;
+
+ unsigned Index = 1;
+ for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+ DEnd = Owner->noload_decls_end();
+ D != DEnd; ++D) {
+ if (*D == F)
+ return Index;
+
+ if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
+ ++Index;
+ }
+
+ return Index;
+}
+
Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
// Import the major distinguishing characteristics of a variable.
DeclContext *DC, *LexicalDC;
@@ -2609,6 +2781,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
+ // For anonymous fields, match up by index.
+ if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ continue;
+
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType())) {
Importer.Imported(D, FoundField);
@@ -2642,6 +2818,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
ToField->setLexicalDeclContext(LexicalDC);
if (ToField->hasInClassInitializer())
ToField->setInClassInitializer(D->getInClassInitializer());
+ ToField->setImplicit(D->isImplicit());
Importer.Imported(D, ToField);
LexicalDC->addDeclInternal(ToField);
return ToField;
@@ -2661,6 +2838,10 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
= dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
+ // For anonymous indirect fields, match up by index.
+ if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ continue;
+
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
Name)) {
@@ -3025,7 +3206,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ResultTy, ResultTInfo, DC,
D->isInstanceMethod(),
D->isVariadic(),
- D->isSynthesized(),
+ D->isPropertyAccessor(),
D->isImplicit(),
D->isDefined(),
D->getImplementationControl(),
@@ -4027,7 +4208,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(),
T, E->getValueKind(),
E->getObjectKind(),
- Importer.Import(E->getOperatorLoc()));
+ Importer.Import(E->getOperatorLoc()),
+ E->isFPContractable());
}
Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -4056,7 +4238,8 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
T, E->getValueKind(),
E->getObjectKind(),
CompLHSType, CompResultType,
- Importer.Import(E->getOperatorLoc()));
+ Importer.Import(E->getOperatorLoc()),
+ E->isFPContractable());
}
static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
@@ -4479,7 +4662,8 @@ FileID ASTImporter::Import(FileID FromID) {
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
- ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+ ToID = ToSM.createFileIDForMemBuffer(ToBuf,
+ FromSLoc.getFile().getFileCharacteristic());
}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index bcc96f912e28..d20d77ef7ea5 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -64,7 +64,10 @@ add_dependencies(clangAST
ClangAttrClasses
ClangAttrList
ClangAttrImpl
+ ClangCommentCommandInfo
ClangCommentNodes
+ ClangCommentHTMLTags
+ ClangCommentHTMLTagsProperties
ClangDeclNodes
ClangDiagnosticAST
ClangDiagnosticComment
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index cf3913bac008..213b214a4e4c 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/SetVector.h"
#include <algorithm>
#include <set>
@@ -25,13 +26,9 @@ void CXXBasePaths::ComputeDeclsFound() {
assert(NumDeclsFound == 0 && !DeclsFound &&
"Already computed the set of declarations");
- SmallVector<NamedDecl *, 8> Decls;
+ llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls;
for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.push_back(*Path->Decls.first);
-
- // Eliminate duplicated decls.
- llvm::array_pod_sort(Decls.begin(), Decls.end());
- Decls.erase(std::unique(Decls.begin(), Decls.end()), Decls.end());
+ Decls.insert(*Path->Decls.first);
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
@@ -258,7 +255,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
}
} else if (VisitBase) {
CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>()
+ = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>()
->getDecl());
if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) {
// C++ [class.member.lookup]p2:
@@ -365,8 +362,8 @@ bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
void *BaseRecord) {
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
"User data for FindBaseClass is not canonical!");
- return Specifier->getType()->getAs<RecordType>()->getDecl()
- ->getCanonicalDecl() == BaseRecord;
+ return Specifier->getType()->castAs<RecordType>()->getDecl()
+ ->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
@@ -375,14 +372,15 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
"User data for FindBaseClass is not canonical!");
return Specifier->isVirtual() &&
- Specifier->getType()->getAs<RecordType>()->getDecl()
- ->getCanonicalDecl() == BaseRecord;
+ Specifier->getType()->castAs<RecordType>()->getDecl()
+ ->getCanonicalDecl() == BaseRecord;
}
bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
@@ -398,7 +396,8 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
@@ -416,7 +415,8 @@ bool CXXRecordDecl::
FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
@@ -694,7 +694,7 @@ AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
@@ -717,7 +717,7 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 8a711f0c1f80..361f8ac61c2a 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -37,11 +38,12 @@ void Comment::dump() const {
// in CommentDumper.cpp, that object file would be removed by linker because
// none of its functions are referenced by other object files, despite the
// LLVM_ATTRIBUTE_USED.
- dump(llvm::errs(), NULL);
+ dump(llvm::errs(), NULL, NULL);
}
-void Comment::dump(SourceManager &SM) const {
- dump(llvm::errs(), &SM);
+void Comment::dump(const ASTContext &Context) const {
+ dump(llvm::errs(), &Context.getCommentCommandTraits(),
+ &Context.getSourceManager());
}
namespace {
@@ -149,13 +151,14 @@ void DeclInfo::fill() {
ParamVars = ArrayRef<const ParmVarDecl *>();
TemplateParameters = NULL;
- if (!ThisDecl) {
+ if (!CommentDecl) {
// If there is no declaration, the defaults is our only guess.
IsFilled = true;
return;
}
-
- Decl::Kind K = ThisDecl->getKind();
+ CurrentDecl = CommentDecl;
+
+ Decl::Kind K = CommentDecl->getKind();
switch (K) {
default:
// Defaults are should be good for declarations we don't handle explicitly.
@@ -165,7 +168,7 @@ void DeclInfo::fill() {
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion: {
- const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
+ const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
@@ -179,14 +182,14 @@ void DeclInfo::fill() {
if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
K == Decl::CXXDestructor || K == Decl::CXXConversion) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl);
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
IsInstanceMethod = MD->isInstance();
IsClassMethod = !IsInstanceMethod;
}
break;
}
case Decl::ObjCMethod: {
- const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl);
+ const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
MD->param_size());
@@ -197,7 +200,7 @@ void DeclInfo::fill() {
break;
}
case Decl::FunctionTemplate: {
- const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
+ const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
Kind = FunctionKind;
TemplateKind = Template;
const FunctionDecl *FD = FTD->getTemplatedDecl();
@@ -208,7 +211,7 @@ void DeclInfo::fill() {
break;
}
case Decl::ClassTemplate: {
- const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
+ const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
Kind = ClassKind;
TemplateKind = Template;
TemplateParameters = CTD->getTemplateParameters();
@@ -216,7 +219,7 @@ void DeclInfo::fill() {
}
case Decl::ClassTemplatePartialSpecialization: {
const ClassTemplatePartialSpecializationDecl *CTPSD =
- cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
+ cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
Kind = ClassKind;
TemplateKind = TemplatePartialSpecialization;
TemplateParameters = CTPSD->getTemplateParameters();
@@ -240,12 +243,55 @@ void DeclInfo::fill() {
case Decl::Namespace:
Kind = NamespaceKind;
break;
- case Decl::Typedef:
+ case Decl::Typedef: {
+ Kind = TypedefKind;
+ // If this is a typedef to something we consider a function, extract
+ // arguments and return type.
+ const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
+ const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
+ if (!TSI)
+ break;
+ TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
+ while (true) {
+ TL = TL.IgnoreParens();
+ // Look through qualified types.
+ if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
+ TL = QualifiedTL->getUnqualifiedLoc();
+ continue;
+ }
+ // Look through pointer types.
+ if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
+ TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ if (BlockPointerTypeLoc *BlockPointerTL =
+ dyn_cast<BlockPointerTypeLoc>(&TL)) {
+ TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ if (MemberPointerTypeLoc *MemberPointerTL =
+ dyn_cast<MemberPointerTypeLoc>(&TL)) {
+ TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ // Is this a typedef for a function type?
+ if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ Kind = FunctionKind;
+ ArrayRef<ParmVarDecl *> Params = FTL->getParams();
+ ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
+ Params.size());
+ ResultType = FTL->getResultLoc().getType();
+ break;
+ }
+ break;
+ }
+ break;
+ }
case Decl::TypeAlias:
Kind = TypedefKind;
break;
case Decl::TypeAliasTemplate: {
- const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
+ const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
Kind = TypedefKind;
TemplateKind = Template;
TemplateParameters = TAT->getTemplateParameters();
@@ -259,6 +305,25 @@ void DeclInfo::fill() {
IsFilled = true;
}
+StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
+ assert(isParamIndexValid());
+ return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
+}
+
+StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
+ assert(isPositionValid());
+ const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
+ for (unsigned i = 0, e = getDepth(); i != e; ++i) {
+ if (i == e-1)
+ return TPL->getParam(getIndex(i))->getName();
+ const NamedDecl *Param = TPL->getParam(getIndex(i));
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Param))
+ TPL = TTP->getTemplateParameters();
+ }
+ return "";
+}
+
} // end namespace comments
} // end namespace clang
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 0aebc1e4e3dd..95daa7e3f809 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -15,6 +15,11 @@ namespace clang {
namespace comments {
namespace {
+inline bool isWhitespace(char C) {
+ return C == ' ' || C == '\n' || C == '\r' ||
+ C == '\t' || C == '\f' || C == '\v';
+}
+
/// Convert all whitespace into spaces, remove leading and trailing spaces,
/// compress multiple spaces into one.
void cleanupBrief(std::string &S) {
@@ -23,8 +28,7 @@ void cleanupBrief(std::string &S) {
for (std::string::iterator I = S.begin(), E = S.end();
I != E; ++I) {
const char C = *I;
- if (C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\v' || C == '\f') {
+ if (isWhitespace(C)) {
if (!PrevWasSpace) {
*O++ = ' ';
PrevWasSpace = true;
@@ -40,6 +44,15 @@ void cleanupBrief(std::string &S) {
S.resize(O - S.begin());
}
+
+bool isWhitespace(StringRef Text) {
+ for (StringRef::const_iterator I = Text.begin(), E = Text.end();
+ I != E; ++I) {
+ if (!isWhitespace(*I))
+ return false;
+ }
+ return true;
+}
} // unnamed namespace
BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
@@ -66,19 +79,23 @@ std::string BriefParser::Parse() {
}
if (Tok.is(tok::command)) {
- StringRef Name = Tok.getCommandName();
- if (Traits.isBriefCommand(Name)) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
InBrief = true;
ConsumeToken();
continue;
}
- if (Traits.isReturnsCommand(Name)) {
+ if (Info->IsReturnsCommand) {
InReturns = true;
+ InBrief = false;
+ InFirstParagraph = false;
ReturnsParagraph += "Returns ";
+ ConsumeToken();
+ continue;
}
// Block commands implicitly start a new paragraph.
- if (Traits.isBlockCommand(Name)) {
+ if (Info->IsBlockCommand) {
// We found an implicit paragraph end.
InFirstParagraph = false;
if (InBrief)
@@ -93,13 +110,29 @@ std::string BriefParser::Parse() {
ReturnsParagraph += ' ';
ConsumeToken();
+ // If the next token is a whitespace only text, ignore it. Thus we allow
+ // two paragraphs to be separated by line that has only whitespace in it.
+ //
+ // We don't need to add a space to the parsed text because we just added
+ // a space for the newline.
+ if (Tok.is(tok::text)) {
+ if (isWhitespace(Tok.getText()))
+ ConsumeToken();
+ }
+
if (Tok.is(tok::newline)) {
ConsumeToken();
- // We found a paragraph end.
- InFirstParagraph = false;
- InReturns = false;
+ // We found a paragraph end. This ends the brief description if
+ // \\brief command or its equivalent was explicitly used.
+ // Stop scanning text because an explicit \\brief paragraph is the
+ // preffered one.
if (InBrief)
break;
+ // End first paragraph if we found some non-whitespace text.
+ if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
+ InFirstParagraph = false;
+ // End the \\returns paragraph because we found the paragraph end.
+ InReturns = false;
}
continue;
}
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index dc7a0bd17532..e7e40fd1090f 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -8,125 +8,64 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentCommandTraits.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
namespace clang {
namespace comments {
-// TODO: tablegen
+#include "clang/AST/CommentCommandInfo.inc"
-bool CommandTraits::isVerbatimBlockCommand(StringRef StartName,
- StringRef &EndName) const {
- const char *Result = llvm::StringSwitch<const char *>(StartName)
- .Case("code", "endcode")
- .Case("verbatim", "endverbatim")
- .Case("htmlonly", "endhtmlonly")
- .Case("latexonly", "endlatexonly")
- .Case("xmlonly", "endxmlonly")
- .Case("manonly", "endmanonly")
- .Case("rtfonly", "endrtfonly")
+CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) :
+ NextID(llvm::array_lengthof(Commands)), Allocator(Allocator)
+{ }
- .Case("dot", "enddot")
- .Case("msc", "endmsc")
-
- .Case("f$", "f$") // Inline LaTeX formula
- .Case("f[", "f]") // Displayed LaTeX formula
- .Case("f{", "f}") // LaTeX environment
-
- .Default(NULL);
-
- if (Result) {
- EndName = Result;
- return true;
- }
-
- for (VerbatimBlockCommandVector::const_iterator
- I = VerbatimBlockCommands.begin(),
- E = VerbatimBlockCommands.end();
- I != E; ++I)
- if (I->StartName == StartName) {
- EndName = I->EndName;
- return true;
- }
-
- return false;
+const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
+ if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
+ return Info;
+ return getRegisteredCommandInfo(Name);
}
-bool CommandTraits::isVerbatimLineCommand(StringRef Name) const {
- bool Result = isDeclarationCommand(Name) || llvm::StringSwitch<bool>(Name)
- .Case("defgroup", true)
- .Case("ingroup", true)
- .Case("addtogroup", true)
- .Case("weakgroup", true)
- .Case("name", true)
-
- .Case("section", true)
- .Case("subsection", true)
- .Case("subsubsection", true)
- .Case("paragraph", true)
-
- .Case("mainpage", true)
- .Case("subpage", true)
- .Case("ref", true)
+const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
+ if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID))
+ return Info;
+ return getRegisteredCommandInfo(CommandID);
+}
- .Default(false);
+const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) {
+ char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
+ memcpy(Name, CommandName.data(), CommandName.size());
+ Name[CommandName.size()] = '\0';
- if (Result)
- return true;
+ // Value-initialize (=zero-initialize in this case) a new CommandInfo.
+ CommandInfo *Info = new (Allocator) CommandInfo();
+ Info->Name = Name;
+ Info->ID = NextID++;
+ Info->IsUnknownCommand = true;
- for (VerbatimLineCommandVector::const_iterator
- I = VerbatimLineCommands.begin(),
- E = VerbatimLineCommands.end();
- I != E; ++I)
- if (I->Name == Name)
- return true;
+ RegisteredCommands.push_back(Info);
- return false;
+ return Info;
}
-bool CommandTraits::isDeclarationCommand(StringRef Name) const {
- return llvm::StringSwitch<bool>(Name)
- // Doxygen commands.
- .Case("fn", true)
- .Case("var", true)
- .Case("property", true)
- .Case("typedef", true)
-
- .Case("overload", true)
-
- // HeaderDoc commands.
- .Case("class", true)
- .Case("interface", true)
- .Case("protocol", true)
- .Case("category", true)
- .Case("template", true)
- .Case("function", true)
- .Case("method", true)
- .Case("callback", true)
- .Case("var", true)
- .Case("const", true)
- .Case("constant", true)
- .Case("property", true)
- .Case("struct", true)
- .Case("union", true)
- .Case("typedef", true)
- .Case("enum", true)
-
- .Default(false);
+const CommandInfo *CommandTraits::getBuiltinCommandInfo(
+ unsigned CommandID) {
+ if (CommandID < llvm::array_lengthof(Commands))
+ return &Commands[CommandID];
+ return NULL;
}
-void CommandTraits::addVerbatimBlockCommand(StringRef StartName,
- StringRef EndName) {
- VerbatimBlockCommand VBC;
- VBC.StartName = StartName;
- VBC.EndName = EndName;
- VerbatimBlockCommands.push_back(VBC);
+const CommandInfo *CommandTraits::getRegisteredCommandInfo(
+ StringRef Name) const {
+ for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) {
+ if (RegisteredCommands[i]->Name == Name)
+ return RegisteredCommands[i];
+ }
+ return NULL;
}
-void CommandTraits::addVerbatimLineCommand(StringRef Name) {
- VerbatimLineCommand VLC;
- VLC.Name = Name;
- VerbatimLineCommands.push_back(VLC);
+const CommandInfo *CommandTraits::getRegisteredCommandInfo(
+ unsigned CommandID) const {
+ return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
}
} // end namespace comments
diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp
index dffc8233a0ca..19d24b2f3a03 100644
--- a/lib/AST/CommentDumper.cpp
+++ b/lib/AST/CommentDumper.cpp
@@ -16,12 +16,20 @@ namespace comments {
namespace {
class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
raw_ostream &OS;
- SourceManager *SM;
+ const CommandTraits *Traits;
+ const SourceManager *SM;
+
+ /// The \c FullComment parent of the comment being dumped.
+ const FullComment *FC;
+
unsigned IndentLevel;
public:
- CommentDumper(raw_ostream &OS, SourceManager *SM) :
- OS(OS), SM(SM), IndentLevel(0)
+ CommentDumper(raw_ostream &OS,
+ const CommandTraits *Traits,
+ const SourceManager *SM,
+ const FullComment *FC) :
+ OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0)
{ }
void dumpIndent() const {
@@ -56,6 +64,15 @@ public:
void visitVerbatimLineComment(const VerbatimLineComment *C);
void visitFullComment(const FullComment *C);
+
+ const char *getCommandName(unsigned CommandID) {
+ if (Traits)
+ return Traits->getCommandInfo(CommandID)->Name;
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ return "<not a builtin command>";
+ }
};
void CommentDumper::dumpSourceRange(const Comment *C) {
@@ -107,7 +124,7 @@ void CommentDumper::visitTextComment(const TextComment *C) {
void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\"";
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
switch (C->getRenderKind()) {
case InlineCommandComment::RenderNormal:
OS << " RenderNormal";
@@ -155,7 +172,7 @@ void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\"";
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}
@@ -170,8 +187,12 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
else
OS << " implicitly";
- if (C->hasParamName())
- OS << " Param=\"" << C->getParamName() << "\"";
+ if (C->hasParamName()) {
+ if (C->isParamIndexValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
if (C->isParamIndexValid())
OS << " ParamIndex=" << C->getParamIndex();
@@ -181,7 +202,10 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
dumpComment(C);
if (C->hasParamName()) {
- OS << " Param=\"" << C->getParamName() << "\"";
+ if (C->isPositionValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
}
if (C->isPositionValid()) {
@@ -198,7 +222,7 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
dumpComment(C);
- OS << " Name=\"" << C->getCommandName() << "\""
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
" CloseName=\"" << C->getCloseName() << "\"";
}
@@ -220,8 +244,10 @@ void CommentDumper::visitFullComment(const FullComment *C) {
} // unnamed namespace
-void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const {
- CommentDumper D(llvm::errs(), SM);
+void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM) const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ CommentDumper D(llvm::errs(), Traits, SM, FC);
D.dumpSubtree(this);
llvm::errs() << '\n';
}
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index b6516ec126f6..31a09f71d993 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -28,6 +28,9 @@ bool isHTMLHexCharacterReferenceCharacter(char C) {
(C >= 'a' && C <= 'f') ||
(C >= 'A' && C <= 'F');
}
+
+#include "clang/AST/CommentHTMLTags.inc"
+
} // unnamed namespace
StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
@@ -223,6 +226,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd;
}
+bool isCommandNameStartCharacter(char C) {
+ return (C >= 'a' && C <= 'z') ||
+ (C >= 'A' && C <= 'Z');
+}
+
bool isCommandNameCharacter(char C) {
return (C >= 'a' && C <= 'z') ||
(C >= 'A' && C <= 'Z') ||
@@ -337,7 +345,7 @@ void Lexer::lexCommentText(Token &T) {
}
// Don't make zero-length commands.
- if (!isCommandNameCharacter(*TokenPtr)) {
+ if (!isCommandNameStartCharacter(*TokenPtr)) {
formTextToken(T, TokenPtr);
return;
}
@@ -356,18 +364,23 @@ void Lexer::lexCommentText(Token &T) {
}
const StringRef CommandName(BufferPtr + 1, Length);
- StringRef EndName;
- if (Traits.isVerbatimBlockCommand(CommandName, EndName)) {
- setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName);
+ const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
+ if (!Info) {
+ formTokenWithChars(T, TokenPtr, tok::unknown_command);
+ T.setUnknownCommandName(CommandName);
+ return;
+ }
+ if (Info->IsVerbatimBlockCommand) {
+ setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
return;
}
- if (Traits.isVerbatimLineCommand(CommandName)) {
- setupAndLexVerbatimLine(T, TokenPtr);
+ if (Info->IsVerbatimLineCommand) {
+ setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
formTokenWithChars(T, TokenPtr, tok::command);
- T.setCommandName(CommandName);
+ T.setCommandID(Info->getID());
return;
}
@@ -420,14 +433,15 @@ void Lexer::lexCommentText(Token &T) {
void Lexer::setupAndLexVerbatimBlock(Token &T,
const char *TextBegin,
- char Marker, StringRef EndName) {
+ char Marker, const CommandInfo *Info) {
+ assert(Info->IsVerbatimBlockCommand);
+
VerbatimBlockEndCommandName.clear();
VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@");
- VerbatimBlockEndCommandName.append(EndName);
+ VerbatimBlockEndCommandName.append(Info->EndCommandName);
- StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1));
formTokenWithChars(T, TextBegin, tok::verbatim_block_begin);
- T.setVerbatimBlockName(Name);
+ T.setVerbatimBlockID(Info->getID());
// If there is a newline following the verbatim opening command, skip the
// newline so that we don't create an tok::verbatim_block_line with empty
@@ -468,7 +482,7 @@ again:
const char *End = BufferPtr + VerbatimBlockEndCommandName.size();
StringRef Name(BufferPtr + 1, End - (BufferPtr + 1));
formTokenWithChars(T, End, tok::verbatim_block_end);
- T.setVerbatimBlockName(Name);
+ T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID());
State = LS_Normal;
return;
} else {
@@ -498,10 +512,11 @@ void Lexer::lexVerbatimBlockBody(Token &T) {
lexVerbatimBlockFirstLine(T);
}
-void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) {
- const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1);
+void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin,
+ const CommandInfo *Info) {
+ assert(Info->IsVerbatimLineCommand);
formTokenWithChars(T, TextBegin, tok::verbatim_line_name);
- T.setVerbatimLineName(Name);
+ T.setVerbatimLineID(Info->getID());
State = LS_VerbatimLineText;
}
@@ -585,8 +600,12 @@ void Lexer::setupAndLexHTMLStartTag(Token &T) {
assert(BufferPtr[0] == '<' &&
isHTMLIdentifierStartingCharacter(BufferPtr[1]));
const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd);
-
StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1));
+ if (!isHTMLTagName(Name)) {
+ formTextToken(T, TagNameEnd);
+ return;
+ }
+
formTokenWithChars(T, TagNameEnd, tok::html_start_tag);
T.setHTMLTagStartName(Name);
@@ -665,11 +684,16 @@ void Lexer::setupAndLexHTMLEndTag(Token &T) {
const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd);
const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd);
+ StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin);
+ if (!isHTMLTagName(Name)) {
+ formTextToken(T, TagNameEnd);
+ return;
+ }
const char *End = skipWhitespace(TagNameEnd, CommentEnd);
formTokenWithChars(T, End, tok::html_end_tag);
- T.setHTMLTagEndName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin));
+ T.setHTMLTagEndName(Name);
if (BufferPtr != CommentEnd && *BufferPtr == '>')
State = LS_HTMLEndTag;
@@ -683,11 +707,11 @@ void Lexer::lexHTMLEndTag(Token &T) {
}
Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
- SourceLocation FileLoc, const CommentOptions &CommOpts,
+ SourceLocation FileLoc,
const char *BufferStart, const char *BufferEnd):
Allocator(Allocator), Traits(Traits),
BufferStart(BufferStart), BufferEnd(BufferEnd),
- FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart),
+ FileLoc(FileLoc), BufferPtr(BufferStart),
CommentState(LCS_BeforeComment), State(LS_Normal) {
}
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index 43abf6a476a8..d0a84741b6f2 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -132,8 +132,8 @@ class TextTokenRetokenizer {
Result.setKind(tok::text);
Result.setLength(TokLength);
#ifndef NDEBUG
- Result.TextPtr1 = "<UNSET>";
- Result.TextLen1 = 7;
+ Result.TextPtr = "<UNSET>";
+ Result.IntVal = 7;
#endif
Result.setText(Text);
}
@@ -312,26 +312,26 @@ BlockCommandComment *Parser::parseBlockCommand() {
BlockCommandComment *BC;
bool IsParam = false;
bool IsTParam = false;
- unsigned NumArgs = 0;
- if (Traits.isParamCommand(Tok.getCommandName())) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
- } if (Traits.isTParamCommand(Tok.getCommandName())) {
+ Tok.getCommandID());
+ } if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
+ Tok.getCommandID());
} else {
- NumArgs = Traits.getBlockCommandNumArgs(Tok.getCommandName());
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandName());
+ Tok.getCommandID());
}
consumeToken();
- if (Tok.is(tok::command) && Traits.isBlockCommand(Tok.getCommandName())) {
+ if (Tok.is(tok::command) &&
+ Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -348,7 +348,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
}
- if (IsParam || IsTParam || NumArgs > 0) {
+ if (IsParam || IsTParam || Info->NumArgs > 0) {
// In order to parse command arguments we need to retokenize a few
// following text tokens.
TextTokenRetokenizer Retokenizer(Allocator, *this);
@@ -358,7 +358,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
else if (IsTParam)
parseTParamCommandArgs(TPC, Retokenizer);
else
- parseBlockCommandArgs(BC, Retokenizer, NumArgs);
+ parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs);
Retokenizer.putBackLeftoverTokens();
}
@@ -394,14 +394,14 @@ InlineCommandComment *Parser::parseInlineCommand() {
if (ArgTokValid) {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
- CommandTok.getCommandName(),
+ CommandTok.getCommandID(),
ArgTok.getLocation(),
ArgTok.getEndLocation(),
ArgTok.getText());
} else {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
- CommandTok.getCommandName());
+ CommandTok.getCommandID());
}
Retokenizer.putBackLeftoverTokens();
@@ -540,23 +540,39 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
assert(Content.size() != 0);
break; // Block content or EOF ahead, finish this parapgaph.
- case tok::command:
- if (Traits.isBlockCommand(Tok.getCommandName())) {
+ case tok::unknown_command:
+ Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
+ Tok.getEndLocation(),
+ Tok.getUnknownCommandName()));
+ consumeToken();
+ continue;
+
+ case tok::command: {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ if (Info->IsBlockCommand) {
if (Content.size() == 0)
return parseBlockCommand();
break; // Block command ahead, finish this parapgaph.
}
- if (Traits.isInlineCommand(Tok.getCommandName())) {
- Content.push_back(parseInlineCommand());
+ if (Info->IsVerbatimBlockEndCommand) {
+ Diag(Tok.getLocation(),
+ diag::warn_verbatim_block_end_without_start)
+ << Info->Name
+ << SourceRange(Tok.getLocation(), Tok.getEndLocation());
+ consumeToken();
continue;
}
-
- // Not a block command, not an inline command ==> an unknown command.
- Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
- Tok.getEndLocation(),
- Tok.getCommandName()));
- consumeToken();
+ if (Info->IsUnknownCommand) {
+ Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
+ Tok.getEndLocation(),
+ Info->getID()));
+ consumeToken();
+ continue;
+ }
+ assert(Info->IsInlineCommand);
+ Content.push_back(parseInlineCommand());
continue;
+ }
case tok::newline: {
consumeToken();
@@ -606,7 +622,7 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
VerbatimBlockComment *VB =
S.actOnVerbatimBlockStart(Tok.getLocation(),
- Tok.getVerbatimBlockName());
+ Tok.getVerbatimBlockID());
consumeToken();
// Don't create an empty line if verbatim opening command is followed
@@ -634,8 +650,9 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
}
if (Tok.is(tok::verbatim_block_end)) {
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
- Tok.getVerbatimBlockName(),
+ Info->Name,
S.copyArray(llvm::makeArrayRef(Lines)));
consumeToken();
} else {
@@ -666,7 +683,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() {
}
VerbatimLineComment *VL = S.actOnVerbatimLine(NameTok.getLocation(),
- NameTok.getVerbatimLineName(),
+ NameTok.getVerbatimLineID(),
TextBegin,
Text);
consumeToken();
@@ -676,6 +693,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() {
BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
+ case tok::unknown_command:
case tok::command:
case tok::html_start_tag:
case tok::html_end_tag:
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index c39ee573ef6f..08ecb3a994d7 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -13,15 +13,22 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallString.h"
namespace clang {
namespace comments {
+namespace {
+#include "clang/AST/CommentHTMLTagsProperties.inc"
+} // unnamed namespace
+
Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
- DiagnosticsEngine &Diags, const CommandTraits &Traits) :
+ DiagnosticsEngine &Diags, CommandTraits &Traits,
+ const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -29,7 +36,7 @@ void Sema::setDecl(const Decl *D) {
return;
ThisDeclInfo = new (Allocator) DeclInfo;
- ThisDeclInfo->ThisDecl = D;
+ ThisDeclInfo->CommentDecl = D;
ThisDeclInfo->IsFilled = false;
}
@@ -40,8 +47,8 @@ ParagraphComment *Sema::actOnParagraphComment(
BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name);
+ unsigned CommandID) {
+ return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -55,18 +62,19 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
checkBlockCommandDuplicate(Command);
checkReturnsCommand(Command);
+ checkDeprecatedCommand(Command);
}
ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ unsigned CommandID) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
- << Command->getCommandNameRange();
+ << Command->getCommandNameRange(Traits);
return Command;
}
@@ -142,56 +150,6 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
ArgLocEnd),
Arg);
Command->setArgs(llvm::makeArrayRef(A, 1));
-
- if (!isFunctionDecl()) {
- // We already warned that this \\param is not attached to a function decl.
- return;
- }
-
- ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
-
- // Check that referenced parameter name is in the function decl.
- const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars);
- if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
- Command->setParamIndex(ResolvedParamIndex);
- if (ParamVarDocs[ResolvedParamIndex]) {
- SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- Diag(ArgLocBegin, diag::warn_doc_param_duplicate)
- << Arg << ArgRange;
- ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
- Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
- << PrevCommand->getParamNameRange();
- }
- ParamVarDocs[ResolvedParamIndex] = Command;
- return;
- }
-
- SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- Diag(ArgLocBegin, diag::warn_doc_param_not_found)
- << Arg << ArgRange;
-
- // No parameters -- can't suggest a correction.
- if (ParamVars.size() == 0)
- return;
-
- unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
- if (ParamVars.size() == 1) {
- // If function has only one parameter then only that parameter
- // can be documented.
- CorrectedParamIndex = 0;
- } else {
- // Do typo correction.
- CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars);
- }
- if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
- const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
- if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
- Diag(ArgLocBegin, diag::note_doc_param_name_suggestion)
- << CorrectedII->getName()
- << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
- }
-
- return;
}
void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
@@ -202,14 +160,14 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ unsigned CommandID) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
- << Command->getCommandNameRange();
+ << Command->getCommandNameRange(Traits);
return Command;
}
@@ -285,19 +243,20 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName) {
+ unsigned CommandID) {
ArrayRef<InlineCommandComment::Argument> Args;
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) InlineCommandComment(
CommandLocBegin,
CommandLocEnd,
- CommandName,
+ CommandID,
getInlineCommandRenderKind(CommandName),
Args);
}
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
- StringRef CommandName,
+ unsigned CommandID,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
@@ -305,21 +264,29 @@ InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
ArgLocEnd),
Arg);
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) InlineCommandComment(
CommandLocBegin,
CommandLocEnd,
- CommandName,
+ CommandID,
getInlineCommandRenderKind(CommandName),
llvm::makeArrayRef(A, 1));
}
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
- StringRef Name) {
+ StringRef CommandName) {
+ unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
+ return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
+}
+
+InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID) {
ArrayRef<InlineCommandComment::Argument> Args;
return new (Allocator) InlineCommandComment(
- LocBegin, LocEnd, Name,
+ LocBegin, LocEnd, CommandID,
InlineCommandComment::RenderNormal,
Args);
}
@@ -331,11 +298,12 @@ TextComment *Sema::actOnText(SourceLocation LocBegin,
}
VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
- StringRef Name) {
+ unsigned CommandID) {
+ StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
return new (Allocator) VerbatimBlockComment(
Loc,
- Loc.getLocWithOffset(1 + Name.size()),
- Name);
+ Loc.getLocWithOffset(1 + CommandName.size()),
+ CommandID);
}
VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
@@ -353,13 +321,13 @@ void Sema::actOnVerbatimBlockFinish(
}
VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
- StringRef Name,
+ unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
return new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
- Name,
+ CommandID,
TextBegin,
Text);
}
@@ -445,30 +413,35 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
- return new (Allocator) FullComment(Blocks, ThisDeclInfo);
+ FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
+ resolveParamCommandIndexes(FC);
+ return FC;
}
void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
+ if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
+ return;
+
ParagraphComment *Paragraph = Command->getParagraph();
if (Paragraph->isWhitespace()) {
SourceLocation DiagLoc;
if (Command->getNumArgs() > 0)
DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
if (!DiagLoc.isValid())
- DiagLoc = Command->getCommandNameRange().getEnd();
+ DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< Command->getSourceRange();
}
}
void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
- if (!Traits.isReturnsCommand(Command->getCommandName()))
+ if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
return;
if (isFunctionDecl()) {
if (ThisDeclInfo->ResultType->isVoidType()) {
unsigned DiagKind;
- switch (ThisDeclInfo->ThisDecl->getKind()) {
+ switch (ThisDeclInfo->CommentDecl->getKind()) {
default:
if (ThisDeclInfo->IsObjCMethod)
DiagKind = 3;
@@ -484,7 +457,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
}
@@ -492,20 +465,20 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
- << Command->getCommandName()
+ << Command->getCommandName(Traits)
<< Command->getSourceRange();
}
void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
- StringRef Name = Command->getCommandName();
+ const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
const BlockCommandComment *PrevCommand = NULL;
- if (Traits.isBriefCommand(Name)) {
+ if (Info->IsBriefCommand) {
if (!BriefCommand) {
BriefCommand = Command;
return;
}
PrevCommand = BriefCommand;
- } else if (Traits.isReturnsCommand(Name)) {
+ } else if (Info->IsReturnsCommand) {
if (!ReturnsCommand) {
ReturnsCommand = Command;
return;
@@ -515,18 +488,153 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
// We don't want to check this command for duplicates.
return;
}
+ StringRef CommandName = Command->getCommandName(Traits);
+ StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
- << Name
+ << CommandName
<< Command->getSourceRange();
- if (Name == PrevCommand->getCommandName())
+ if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
- << PrevCommand->getCommandName()
- << Command->getSourceRange();
+ << PrevCommandName
+ << PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
- << PrevCommand->getCommandName()
- << Name;
+ << PrevCommandName
+ << CommandName;
+}
+
+void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
+ if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
+ return;
+
+ const Decl *D = ThisDeclInfo->CommentDecl;
+ if (!D)
+ return;
+
+ if (D->hasAttr<DeprecatedAttr>() ||
+ D->hasAttr<AvailabilityAttr>() ||
+ D->hasAttr<UnavailableAttr>())
+ return;
+
+ Diag(Command->getLocation(),
+ diag::warn_doc_deprecated_not_sync)
+ << Command->getSourceRange();
+
+ // Try to emit a fixit with a deprecation attribute.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Don't emit a Fix-It for non-member function definitions. GCC does not
+ // accept attributes on them.
+ const DeclContext *Ctx = FD->getDeclContext();
+ if ((!Ctx || !Ctx->isRecord()) &&
+ FD->doesThisDeclarationHaveABody())
+ return;
+
+ StringRef AttributeSpelling = "__attribute__((deprecated))";
+ if (PP) {
+ TokenValue Tokens[] = {
+ tok::kw___attribute, tok::l_paren, tok::l_paren,
+ PP->getIdentifierInfo("deprecated"),
+ tok::r_paren, tok::r_paren
+ };
+ StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
+ Tokens);
+ if (!MacroName.empty())
+ AttributeSpelling = MacroName;
+ }
+
+ SmallString<64> TextToInsert(" ");
+ TextToInsert += AttributeSpelling;
+ Diag(FD->getLocEnd(),
+ diag::note_add_deprecation_attr)
+ << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
+ TextToInsert);
+ }
+}
+
+void Sema::resolveParamCommandIndexes(const FullComment *FC) {
+ if (!isFunctionDecl()) {
+ // We already warned that \\param commands are not attached to a function
+ // decl.
+ return;
+ }
+
+ llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
+
+ // Comment AST nodes that correspond to \c ParamVars for which we have
+ // found a \\param command or NULL if no documentation was found so far.
+ llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
+
+ ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
+ ParamVarDocs.resize(ParamVars.size(), NULL);
+
+ // First pass over all \\param commands: resolve all parameter names.
+ for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
+ I != E; ++I) {
+ ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
+ if (!PCC || !PCC->hasParamName())
+ continue;
+ StringRef ParamName = PCC->getParamNameAsWritten();
+
+ // Check that referenced parameter name is in the function decl.
+ const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
+ ParamVars);
+ if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
+ UnresolvedParamCommands.push_back(PCC);
+ continue;
+ }
+ PCC->setParamIndex(ResolvedParamIndex);
+ if (ParamVarDocs[ResolvedParamIndex]) {
+ SourceRange ArgRange = PCC->getParamNameRange();
+ Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
+ << ParamName << ArgRange;
+ ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
+ Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
+ << PrevCommand->getParamNameRange();
+ }
+ ParamVarDocs[ResolvedParamIndex] = PCC;
+ }
+
+ // Find parameter declarations that have no corresponding \\param.
+ llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
+ for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
+ if (!ParamVarDocs[i])
+ OrphanedParamDecls.push_back(ParamVars[i]);
+ }
+
+ // Second pass over unresolved \\param commands: do typo correction.
+ // Suggest corrections from a set of parameter declarations that have no
+ // corresponding \\param.
+ for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
+ const ParamCommandComment *PCC = UnresolvedParamCommands[i];
+
+ SourceRange ArgRange = PCC->getParamNameRange();
+ StringRef ParamName = PCC->getParamNameAsWritten();
+ Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
+ << ParamName << ArgRange;
+
+ // All parameters documented -- can't suggest a correction.
+ if (OrphanedParamDecls.size() == 0)
+ continue;
+
+ unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
+ if (OrphanedParamDecls.size() == 1) {
+ // If one parameter is not documented then that parameter is the only
+ // possible suggestion.
+ CorrectedParamIndex = 0;
+ } else {
+ // Do typo correction.
+ CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
+ OrphanedParamDecls);
+ }
+ if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
+ const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
+ if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
+ Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
+ << CorrectedII->getName()
+ << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
+ }
+ }
}
bool Sema::isFunctionDecl() {
@@ -553,7 +661,6 @@ ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
void Sema::inspectThisDecl() {
ThisDeclInfo->fill();
- ParamVarDocs.resize(ThisDeclInfo->ParamVars.size(), NULL);
}
unsigned Sema::resolveParmVarReference(StringRef Name,
@@ -629,7 +736,7 @@ unsigned Sema::correctTypoInParmVarReference(
if (Corrector.getBestDecl())
return Corrector.getBestDeclIndex();
else
- return ParamCommandComment::InvalidParamIndex;;
+ return ParamCommandComment::InvalidParamIndex;
}
namespace {
@@ -700,7 +807,7 @@ StringRef Sema::correctTypoInTParamReference(
InlineCommandComment::RenderKind
Sema::getInlineCommandRenderKind(StringRef Name) const {
- assert(Traits.isInlineCommand(Name));
+ assert(Traits.getCommandInfo(Name)->IsInlineCommand);
return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
.Case("b", InlineCommandComment::RenderBold)
@@ -709,31 +816,6 @@ Sema::getInlineCommandRenderKind(StringRef Name) const {
.Default(InlineCommandComment::RenderNormal);
}
-bool Sema::isHTMLEndTagOptional(StringRef Name) {
- return llvm::StringSwitch<bool>(Name)
- .Case("p", true)
- .Case("li", true)
- .Case("dt", true)
- .Case("dd", true)
- .Case("tr", true)
- .Case("th", true)
- .Case("td", true)
- .Case("thead", true)
- .Case("tfoot", true)
- .Case("tbody", true)
- .Case("colgroup", true)
- .Default(false);
-}
-
-bool Sema::isHTMLEndTagForbidden(StringRef Name) {
- return llvm::StringSwitch<bool>(Name)
- .Case("br", true)
- .Case("hr", true)
- .Case("img", true)
- .Case("col", true)
- .Default(false);
-}
-
} // end namespace comments
} // end namespace clang
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index d5b0be3ba4b1..7b13755979f1 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -126,12 +126,12 @@ static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
break;
case TemplateArgument::Declaration:
- // The decl can validly be null as the representation of nullptr
- // arguments, valid only in C++0x.
- if (Decl *D = Args[I].getAsDecl()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
- }
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
+ LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
+ break;
+
+ case TemplateArgument::NullPtr:
+ LV.mergeWithMin(getLVForType(Args[I].getNullPtrType()));
break;
case TemplateArgument::Template:
@@ -193,7 +193,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
// anyway.
return TSK != TSK_ExplicitInstantiationDeclaration &&
TSK != TSK_ExplicitInstantiationDefinition &&
- FD->hasBody(Def) && Def->isInlined();
+ FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
@@ -213,12 +213,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_Static)
return LinkageInfo::internal();
- // - an object or reference that is explicitly declared const
- // and neither explicitly declared extern nor previously
- // declared to have external linkage; or
- // (there is no equivalent in C99)
+ // - a non-volatile object or reference that is explicitly declared const
+ // or constexpr and neither explicitly declared extern nor previously
+ // declared to have external linkage; or (there is no equivalent in C99)
if (Context.getLangOpts().CPlusPlus &&
- Var->getType().isConstant(Context) &&
+ Var->getType().isConstQualified() &&
+ !Var->getType().isVolatileQualified() &&
Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern) {
bool FoundExtern = false;
@@ -236,8 +236,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
if (PrevVar->getStorageClass() == SC_PrivateExtern)
break;
- if (PrevVar)
- return PrevVar->getLinkageAndVisibility();
+ if (PrevVar)
+ return PrevVar->getLinkageAndVisibility();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -341,25 +341,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- if (!Context.getLangOpts().CPlusPlus &&
- (Var->getStorageClass() == SC_Extern ||
- Var->getStorageClass() == SC_PrivateExtern)) {
-
- // C99 6.2.2p4:
- // For an identifier declared with the storage-class specifier
- // extern in a scope in which a prior declaration of that
- // identifier is visible, if the prior declaration specifies
- // internal or external linkage, the linkage of the identifier
- // at the later declaration is the same as the linkage
- // specified at the prior declaration. If no prior declaration
- // is visible, or if the prior declaration specifies no
- // linkage, then the identifier has external linkage.
- if (const VarDecl *PrevVar = Var->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(PrevVar, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
- }
+ // Note that Sema::MergeVarDecl already takes care of implementing
+ // C99 6.2.2p4 and propagating the visibility attribute, so we don't have
+ // to do it here.
// - a function, unless it has internal linkage; or
} else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -841,13 +825,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
LV.mergeVisibility(*Vis, true);
}
-
- if (const VarDecl *Prev = Var->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
+ // Note that Sema::MergeVarDecl already takes care of implementing
+ // C99 6.2.2p4 and propagating the visibility attribute, so we don't
+ // have to do it here.
return LV;
}
}
@@ -903,7 +884,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
- FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>());
OS << *FD << '(';
if (FT) {
@@ -1204,8 +1185,11 @@ void VarDecl::setStorageClass(StorageClass SC) {
}
SourceRange VarDecl::getSourceRange() const {
- if (getInit())
- return SourceRange(getOuterLocStart(), getInit()->getLocEnd());
+ if (const Expr *Init = getInit()) {
+ SourceLocation InitEnd = Init->getLocEnd();
+ if (InitEnd.isValid())
+ return SourceRange(getOuterLocStart(), InitEnd);
+ }
return DeclaratorDecl::getSourceRange();
}
@@ -1859,7 +1843,7 @@ unsigned FunctionDecl::getBuiltinID() const {
/// based on its FunctionType. This is the length of the ParamInfo array
/// after it has been created.
unsigned FunctionDecl::getNumParams() const {
- const FunctionType *FT = getType()->getAs<FunctionType>();
+ const FunctionType *FT = getType()->castAs<FunctionType>();
if (isa<FunctionNoProtoType>(FT))
return 0;
return cast<FunctionProtoType>(FT)->getNumArgs();
@@ -2514,7 +2498,7 @@ unsigned FieldDecl::getFieldIndex() const {
unsigned Index = 0;
const RecordDecl *RD = getParent();
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(getASTContext());
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++Index) {
@@ -2762,6 +2746,17 @@ void RecordDecl::completeDefinition() {
TagDecl::completeDefinition();
}
+/// isMsStruct - Get whether or not this record uses ms_struct layout.
+/// This which can be turned on with an attribute, pragma, or the
+/// -mms-bitfields command-line option.
+bool RecordDecl::isMsStruct(const ASTContext &C) const {
+ return hasAttr<MsStructAttr>() || C.getLangOpts().MSBitfields == 1;
+}
+
+static bool isFieldOrIndirectField(Decl::Kind K) {
+ return FieldDecl::classofKind(K) || IndirectFieldDecl::classofKind(K);
+}
+
void RecordDecl::LoadFieldsFromExternalStorage() const {
ExternalASTSource *Source = getASTContext().getExternalSource();
assert(hasExternalLexicalStorage() && Source && "No external storage?");
@@ -2771,7 +2766,8 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
SmallVector<Decl*, 64> Decls;
LoadedFieldsFromExternalStorage = true;
- switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) {
+ switch (Source->FindExternalLexicalDecls(this, isFieldOrIndirectField,
+ Decls)) {
case ELR_Success:
break;
@@ -2783,7 +2779,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
#ifndef NDEBUG
// Check that all decls we got were FieldDecls.
for (unsigned i=0, e=Decls.size(); i != e; ++i)
- assert(isa<FieldDecl>(Decls[i]));
+ assert(isa<FieldDecl>(Decls[i]) || isa<IndirectFieldDecl>(Decls[i]));
#endif
if (Decls.empty())
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index f9ce46def5b9..4400d503f263 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -961,7 +961,7 @@ DeclContext::lookup_result
ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
- ASTContext &Context = DC->getParentASTContext();;
+ ASTContext &Context = DC->getParentASTContext();
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 2f21e4cbd652..82e630acefba 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -90,11 +90,12 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
}
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
- SourceLocation Loc, bool Dependent) {
+ TypeSourceInfo *Info, SourceLocation Loc,
+ bool Dependent) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
0, 0);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -239,10 +240,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// -- the constructor selected to copy/move each direct base class
// subobject is trivial, and
// FIXME: C++0x: We need to only consider the selected constructor
- // instead of all of them.
+ // instead of all of them. For now, we treat a move constructor as being
+ // non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
- if (!BaseClassDecl->hasTrivialMoveConstructor())
+ if (!BaseClassDecl->hasTrivialMoveConstructor() ||
+ !(BaseClassDecl->hasDeclaredMoveConstructor() ||
+ BaseClassDecl->needsImplicitMoveConstructor()))
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
@@ -254,7 +258,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment())
+ if (!BaseClassDecl->hasTrivialMoveAssignment() ||
+ !(BaseClassDecl->hasDeclaredMoveAssignment() ||
+ BaseClassDecl->needsImplicitMoveAssignment()))
data().HasTrivialMoveAssignment = false;
// C++11 [class.ctor]p6:
@@ -466,7 +472,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
!isa<IndirectFieldDecl>(D) &&
- (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class))
+ (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class ||
+ cast<TagDecl>(D)->getTagKind() == TTK_Interface))
data().HasOnlyCMembers = false;
// Ignore friends and invalid declarations.
@@ -828,7 +835,9 @@ NotASpecialMember:;
// FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor())
+ if (!FieldRec->hasTrivialMoveConstructor() ||
+ !(FieldRec->hasDeclaredMoveConstructor() ||
+ FieldRec->needsImplicitMoveConstructor()))
data().HasTrivialMoveConstructor = false;
// C++0x [class.copy]p27:
@@ -840,7 +849,9 @@ NotASpecialMember:;
// FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment())
+ if (!FieldRec->hasTrivialMoveAssignment() ||
+ !(FieldRec->hasDeclaredMoveAssignment() ||
+ FieldRec->needsImplicitMoveAssignment()))
data().HasTrivialMoveAssignment = false;
if (!FieldRec->hasTrivialDestructor())
@@ -936,7 +947,8 @@ NotASpecialMember:;
}
bool CXXRecordDecl::isCLike() const {
- if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull())
+ if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
+ !TemplateOrInstantiation.isNull())
return false;
if (!hasDefinition())
return true;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 4d48ad8e4f5a..65a987836ff8 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/ASTMutationListener.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -93,6 +94,16 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
return 0;
}
+IdentifierInfo *
+ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
+ SmallString<128> ivarName;
+ {
+ llvm::raw_svector_ostream os(ivarName);
+ os << '_' << getIdentifier()->getName();
+ }
+ return &Ctx.Idents.get(ivarName.str());
+}
+
/// FindPropertyDeclaration - Finds declaration of the property given its name
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *
@@ -179,6 +190,21 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return 0;
}
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+ for (ObjCContainerDecl::prop_iterator P = prop_begin(),
+ E = prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ PM[Prop->getIdentifier()] = Prop;
+ }
+ for (ObjCInterfaceDecl::all_protocol_iterator
+ PI = all_referenced_protocol_begin(),
+ E = all_referenced_protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM);
+ // Note, the properties declared only in class extensions are still copied
+ // into the main @interface's property list, and therefore we don't
+ // explicitly, have to search class extension properties.
+}
+
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
@@ -414,16 +440,15 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
DeclContext *contextDecl,
bool isInstance,
bool isVariadic,
- bool isSynthesized,
+ bool isPropertyAccessor,
bool isImplicitlyDeclared,
bool isDefined,
ImplementationControl impControl,
bool HasRelatedResultType) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
- isInstance,
- isVariadic, isSynthesized, isImplicitlyDeclared,
- isDefined,
+ isInstance, isVariadic, isPropertyAccessor,
+ isImplicitlyDeclared, isDefined,
impControl,
HasRelatedResultType);
}
@@ -434,6 +459,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
Selector(), QualType(), 0, 0);
}
+Stmt *ObjCMethodDecl::getBody() const {
+ return Body.get(getASTContext().getExternalSource());
+}
+
void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
assert(PrevMethod);
getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
@@ -707,6 +736,224 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
llvm_unreachable("unknown method context");
}
+static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods,
+ bool MovedToSuper) {
+ if (!Container)
+ return;
+
+ // In categories look for overriden methods from protocols. A method from
+ // category is not "overriden" since it is considered as the "same" method
+ // (same USR) as the one from the interface.
+ if (const ObjCCategoryDecl *
+ Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Check whether we have a matching method at this category but only if we
+ // are at the super class level.
+ if (MovedToSuper)
+ if (ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this category; there is no need to look
+ // into its protocols.
+ Methods.push_back(Overridden);
+ return;
+ }
+
+ for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ return;
+ }
+
+ // Check whether we have a matching method at this level.
+ if (const ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this level; there is no need to look
+ // into other protocols or categories.
+ Methods.push_back(Overridden);
+ return;
+ }
+
+ if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){
+ for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
+ PEnd = Protocol->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ }
+
+ if (const ObjCInterfaceDecl *
+ Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
+ PEnd = Interface->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+
+ for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ CollectOverriddenMethodsRecurse(Category, Method, Methods,
+ MovedToSuper);
+
+ if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
+ return CollectOverriddenMethodsRecurse(Super, Method, Methods,
+ /*MovedToSuper=*/true);
+ }
+}
+
+static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ CollectOverriddenMethodsRecurse(Container, Method, Methods,
+ /*MovedToSuper=*/false);
+}
+
+static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &overridden) {
+ assert(Method->isOverriding());
+
+ if (const ObjCProtocolDecl *
+ ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
+ CollectOverriddenMethods(ProtD, Method, overridden);
+
+ } else if (const ObjCImplDecl *
+ IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
+ const ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(ID, Method, overridden);
+
+ } else if (const ObjCCategoryDecl *
+ CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
+ const ObjCInterfaceDecl *ID = CatD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(ID, Method, overridden);
+
+ } else {
+ CollectOverriddenMethods(
+ dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
+ Method, overridden);
+ }
+}
+
+static void collectOnCategoriesAfterLocation(SourceLocation Loc,
+ const ObjCInterfaceDecl *Class,
+ SourceManager &SM,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ if (!Class)
+ return;
+
+ for (const ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory())
+ if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
+ CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
+
+ collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
+ Method, Methods);
+}
+
+/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
+/// returns false.
+/// You'd think that in that case there are no overrides but categories can
+/// "introduce" new overridden methods that are missed by Sema because the
+/// overrides lookup that it does for methods, inside implementations, will
+/// stop at the interface level (if there is a method there) and not look
+/// further in super classes.
+/// Methods in an implementation can overide methods in super class's category
+/// but not in current class's category. But, such methods
+static void collectOverriddenMethodsFast(SourceManager &SM,
+ const ObjCMethodDecl *Method,
+ SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
+ assert(!Method->isOverriding());
+
+ const ObjCContainerDecl *
+ ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
+ if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
+ return;
+ const ObjCInterfaceDecl *Class = Method->getClassInterface();
+ if (!Class)
+ return;
+
+ collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
+ SM, Method, Methods);
+}
+
+void ObjCMethodDecl::getOverriddenMethods(
+ SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const {
+ const ObjCMethodDecl *Method = this;
+
+ if (Method->isRedeclaration()) {
+ Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
+ getMethod(Method->getSelector(), Method->isInstanceMethod());
+ }
+
+ if (!Method->isOverriding()) {
+ collectOverriddenMethodsFast(getASTContext().getSourceManager(),
+ Method, Overridden);
+ } else {
+ collectOverriddenMethodsSlow(Method, Overridden);
+ assert(!Overridden.empty() &&
+ "ObjCMethodDecl's overriding bit is not as expected");
+ }
+}
+
+const ObjCPropertyDecl *
+ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
+ Selector Sel = getSelector();
+ unsigned NumArgs = Sel.getNumArgs();
+ if (NumArgs > 1)
+ return 0;
+
+ if (!isInstanceMethod() || getMethodFamily() != OMF_None)
+ return 0;
+
+ if (isPropertyAccessor()) {
+ const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
+ bool IsGetter = (NumArgs == 0);
+
+ for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
+ E = Container->prop_end();
+ I != E; ++I) {
+ Selector NextSel = IsGetter ? (*I)->getGetterName()
+ : (*I)->getSetterName();
+ if (NextSel == Sel)
+ return *I;
+ }
+
+ llvm_unreachable("Marked as a property accessor but no property found!");
+ }
+
+ if (!CheckOverrides)
+ return 0;
+
+ typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy;
+ OverridesTy Overrides;
+ getOverriddenMethods(Overrides);
+ for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end();
+ I != E; ++I) {
+ if (const ObjCPropertyDecl *Prop = (*I)->findPropertyDecl(false))
+ return Prop;
+ }
+
+ return 0;
+
+}
+
//===----------------------------------------------------------------------===//
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
@@ -1081,6 +1328,20 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
+void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+ for (ObjCProtocolDecl::prop_iterator P = prop_begin(),
+ E = prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ // Insert into PM if not there already.
+ PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+ }
+ // Scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(),
+ E = protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM);
+}
+
+
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 7f47604dece3..386ad66c9917 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -105,6 +105,8 @@ static QualType GetBaseType(QualType T) {
break;
else if (const PointerType* PTy = BaseType->getAs<PointerType>())
BaseType = PTy->getPointeeType();
+ else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
+ BaseType = BPy->getPointeeType();
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
BaseType = ATy->getElementType();
else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
@@ -189,6 +191,9 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
+ if (Policy.SuppressAttributes)
+ return;
+
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
@@ -220,6 +225,9 @@ void DeclPrinter::Print(AccessSpecifier AS) {
//----------------------------------------------------------------------------
void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
+ if (Policy.TerseOutput)
+ return;
+
if (Indent)
Indentation += Policy.Indentation;
@@ -459,7 +467,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (I)
Proto += ", ";
- Proto += FT->getExceptionType(I).getAsString(SubPolicy);;
+ Proto += FT->getExceptionType(I).getAsString(SubPolicy);
}
Proto += ")";
} else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
@@ -550,7 +558,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten())
Out << " = delete";
- else if (D->doesThisDeclarationHaveABody()) {
+ else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
// parameters.
@@ -621,13 +629,13 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
Construct->getNumArgs() == 0 && !Construct->isListInitialization();
if (!ImplicitInit) {
- if (D->getInitStyle() == VarDecl::CallInit)
+ if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << "(";
else if (D->getInitStyle() == VarDecl::CInit) {
Out << " = ";
}
Init->printPretty(Out, 0, Policy, Indentation);
- if (D->getInitStyle() == VarDecl::CallInit)
+ if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << ")";
}
}
@@ -869,7 +877,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isVariadic())
Out << ", ...";
- if (OMD->getBody()) {
+ if (OMD->getBody() && !Policy.TerseOutput) {
Out << ' ';
OMD->getBody()->printPretty(Out, 0, Policy);
Out << '\n';
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a7e89994afe8..a70983f4c962 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
- NumParams(NumParams) {
- for (unsigned Idx = 0; Idx < NumParams; ++Idx)
- begin()[Idx] = Params[Idx];
+ NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
+ assert(this->NumParams == NumParams && "Too many template parameters");
+ for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
+ NamedDecl *P = Params[Idx];
+ begin()[Idx] = P;
+
+ if (!P->isTemplateParameterPack()) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
+ if (NTTP->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
+ if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ // FIXME: If a default argument contains an unexpanded parameter pack, the
+ // template parameter list does too.
+ }
+ }
}
TemplateParameterList *
@@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
void TemplateTemplateParmDecl::anchor() { }
+TemplateTemplateParmDecl::TemplateTemplateParmDecl(
+ DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, TemplateParameterList *Params,
+ unsigned NumExpansions, TemplateParameterList * const *Expansions)
+ : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
+ TemplateParmPosition(D, P), DefaultArgument(),
+ DefaultArgumentWasInherited(false), ParameterPack(true),
+ ExpandedParameterPack(true), NumExpandedParams(NumExpansions) {
+ if (Expansions)
+ std::memcpy(reinterpret_cast<void*>(this + 1), Expansions,
+ sizeof(TemplateParameterList*) * NumExpandedParams);
+}
+
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
@@ -587,12 +616,35 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
}
TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id,
+ TemplateParameterList *Params,
+ llvm::ArrayRef<TemplateParameterList*> Expansions) {
+ void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
+ sizeof(TemplateParameterList*) * Expansions.size());
+ return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
+ Expansions.size(),
+ Expansions.data());
+}
+
+TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false,
0, 0);
}
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumExpansions) {
+ unsigned Size = sizeof(TemplateTemplateParmDecl) +
+ sizeof(TemplateParameterList*) * NumExpansions;
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0,
+ NumExpansions, 0);
+}
+
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
@@ -712,13 +764,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
SourceRange
ClassTemplateSpecializationDecl::getSourceRange() const {
if (ExplicitInfo) {
- SourceLocation Begin = getExternLoc();
- if (Begin.isInvalid())
- Begin = getTemplateKeywordLoc();
- SourceLocation End = getRBraceLoc();
- if (End.isInvalid())
- End = getTypeAsWritten()->getTypeLoc().getEndLoc();
- return SourceRange(Begin, End);
+ SourceLocation Begin = getTemplateKeywordLoc();
+ if (Begin.isValid()) {
+ // Here we have an explicit (partial) specialization or instantiation.
+ assert(getSpecializationKind() == TSK_ExplicitSpecialization ||
+ getSpecializationKind() == TSK_ExplicitInstantiationDeclaration ||
+ getSpecializationKind() == TSK_ExplicitInstantiationDefinition);
+ if (getExternLoc().isValid())
+ Begin = getExternLoc();
+ SourceLocation End = getRBraceLoc();
+ if (End.isInvalid())
+ End = getTypeAsWritten()->getTypeLoc().getEndLoc();
+ return SourceRange(Begin, End);
+ }
+ // An implicit instantiation of a class template partial specialization
+ // uses ExplicitInfo to record the TypeAsWritten, but the source
+ // locations should be retrieved from the instantiation pattern.
+ typedef ClassTemplatePartialSpecializationDecl CTPSDecl;
+ CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this));
+ CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember();
+ assert(inst_from != 0);
+ return inst_from->getSourceRange();
}
else {
// No explicit info available.
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 84f3fc491cb0..5f43fbc251a0 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -1,4 +1,4 @@
-//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===//
+//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -64,6 +64,8 @@ template <class Impl> struct XMLDeclVisitor {
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: \
@@ -316,12 +318,12 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::NullPtr:
// FIXME: Implement!
break;
case TemplateArgument::Declaration: {
- if (Decl *D = A.getAsDecl())
- visitDeclRef(D);
+ visitDeclRef(A.getAsDecl());
break;
}
case TemplateArgument::Integral: {
@@ -841,7 +843,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("instance", D->isInstanceMethod());
setFlag("variadic", D->isVariadic());
- setFlag("synthesized", D->isSynthesized());
+ setFlag("property_accessor", D->isPropertyAccessor());
setFlag("defined", D->isDefined());
setFlag("related_result_type", D->hasRelatedResultType());
}
@@ -920,6 +922,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
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");
}
}
@@ -974,6 +977,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
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");
@@ -1023,7 +1036,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
void Decl::dumpXML() const {
- dump(llvm::errs());
+ dumpXML(llvm::errs());
}
void Decl::dumpXML(raw_ostream &out) const {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 24361efafa6c..f3a2e0563872 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -48,6 +48,75 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
return cast<CXXRecordDecl>(D);
}
+const Expr *
+Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+ const Expr *E = this;
+ while (true) {
+ E = E->IgnoreParens();
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if ((CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase) &&
+ E->getType()->isRecordType()) {
+ E = CE->getSubExpr();
+ CXXRecordDecl *Derived
+ = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ Adjustments.push_back(SubobjectAdjustment(CE, Derived));
+ continue;
+ }
+
+ if (CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ assert(ME->getBase()->getType()->isRecordType());
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field));
+ continue;
+ }
+ }
+ } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->isPtrMemOp()) {
+ assert(BO->getRHS()->isRValue());
+ E = BO->getLHS();
+ const MemberPointerType *MPT =
+ BO->getRHS()->getType()->getAs<MemberPointerType>();
+ Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ }
+ }
+
+ // Nothing changed.
+ break;
+ }
+ return E;
+}
+
+const Expr *
+Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const {
+ const Expr *E = this;
+ // Look through single-element init lists that claim to be lvalues. They're
+ // just syntactic wrappers in this case.
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue())
+ E = ILE->getInit(0);
+ }
+
+ // Look through expressions for materialized temporaries (for now).
+ if (const MaterializeTemporaryExpr *M
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ MTE = M;
+ E = M->GetTemporaryExpr();
+ }
+
+ if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
+ E = DAE->getExpr();
+ return E;
+}
+
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
@@ -784,19 +853,19 @@ void StringLiteral::setString(ASTContext &C, StringRef Str,
switch(CharByteWidth) {
case 1: {
char *AStrData = new (C) char[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asChar = AStrData;
break;
}
case 2: {
uint16_t *AStrData = new (C) uint16_t[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asUInt16 = AStrData;
break;
}
case 4: {
uint32_t *AStrData = new (C) uint32_t[Length];
- std::memcpy(AStrData,Str.data(),Str.size());
+ std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData));
StrData.asUInt32 = AStrData;
break;
}
@@ -869,7 +938,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++".
-const char *UnaryOperator::getOpcodeStr(Opcode Op) {
+StringRef UnaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
case UO_PostInc: return "++";
case UO_PostDec: return "--";
@@ -923,18 +992,18 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
//===----------------------------------------------------------------------===//
CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
+ ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
- NumArgs(numargs) {
+ NumArgs(args.size()) {
- SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs];
+ SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -951,18 +1020,18 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
+CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: Expr(CallExprClass, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
- NumArgs(numargs) {
+ NumArgs(args.size()) {
- SubExprs = new (C) Stmt*[numargs+PREARGS_START];
+ SubExprs = new (C) Stmt*[args.size()+PREARGS_START];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -1123,15 +1192,15 @@ SourceLocation CallExpr::getLocEnd() const {
OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
+ ArrayRef<OffsetOfNode> comps,
+ ArrayRef<Expr*> exprs,
SourceLocation RParenLoc) {
void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
- sizeof(OffsetOfNode) * numComps +
- sizeof(Expr*) * numExprs);
+ sizeof(OffsetOfNode) * comps.size() +
+ sizeof(Expr*) * exprs.size());
- return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps,
- exprsPtr, numExprs, RParenLoc);
+ return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs,
+ RParenLoc);
}
OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
@@ -1144,8 +1213,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
- Expr** exprsPtr, unsigned numExprs,
+ ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc)
: Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary,
/*TypeDependent=*/false,
@@ -1153,19 +1221,19 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
tsi->getType()->isInstantiationDependentType(),
tsi->getType()->containsUnexpandedParameterPack()),
OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
- NumComps(numComps), NumExprs(numExprs)
+ NumComps(comps.size()), NumExprs(exprs.size())
{
- for(unsigned i = 0; i < numComps; ++i) {
- setComponent(i, compsPtr[i]);
+ for (unsigned i = 0; i != comps.size(); ++i) {
+ setComponent(i, comps[i]);
}
- for(unsigned i = 0; i < numExprs; ++i) {
- if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent())
+ for (unsigned i = 0; i != exprs.size(); ++i) {
+ if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent())
ExprBits.ValueDependent = true;
- if (exprsPtr[i]->containsUnexpandedParameterPack())
+ if (exprs[i]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
- setIndexExpr(i, exprsPtr[i]);
+ setIndexExpr(i, exprs[i]);
}
}
@@ -1259,9 +1327,12 @@ SourceLocation MemberExpr::getLocStart() const {
return MemberLoc;
}
SourceLocation MemberExpr::getLocEnd() const {
+ SourceLocation EndLoc = getMemberNameInfo().getEndLoc();
if (hasExplicitTemplateArgs())
- return getRAngleLoc();
- return getMemberNameInfo().getEndLoc();
+ EndLoc = getRAngleLoc();
+ else if (EndLoc.isInvalid())
+ EndLoc = getBase()->getLocEnd();
+ return EndLoc;
}
void CastExpr::CheckCastConsistency() const {
@@ -1311,12 +1382,16 @@ void CastExpr::CheckCastConsistency() const {
assert(getType()->isBlockPointerType());
assert(getSubExpr()->getType()->isBlockPointerType());
goto CheckNoBasePath;
-
+
+ case CK_FunctionToPointerDecay:
+ assert(getType()->isPointerType());
+ assert(getSubExpr()->getType()->isFunctionType());
+ goto CheckNoBasePath;
+
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
case CK_ArrayToPointerDecay:
- case CK_FunctionToPointerDecay:
case CK_NullToMemberPointer:
case CK_NullToPointer:
case CK_ConstructorConversion:
@@ -1357,6 +1432,7 @@ void CastExpr::CheckCastConsistency() const {
case CK_IntegralComplexToBoolean:
case CK_LValueBitCast: // -> bool&
case CK_UserDefinedConversion: // operator bool()
+ case CK_BuiltinFnToFnPtr:
CheckNoBasePath:
assert(path_empty() && "Cast kind should not have a base path!");
break;
@@ -1469,6 +1545,8 @@ const char *CastExpr::getCastKindName() const {
return "NonAtomicToAtomic";
case CK_CopyAndAutoreleaseBlockObject:
return "CopyAndAutoreleaseBlockObject";
+ case CK_BuiltinFnToFnPtr:
+ return "BuiltinFnToFnPtr";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1564,7 +1642,7 @@ CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
-const char *BinaryOperator::getOpcodeStr(Opcode Op) {
+StringRef BinaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
case BO_PtrMemD: return ".*";
case BO_PtrMemI: return "->*";
@@ -1666,16 +1744,15 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
}
InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
- Expr **initExprs, unsigned numInits,
- SourceLocation rbraceloc)
+ ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
- InitExprs(C, numInits),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0)
+ InitExprs(C, initExprs.size()),
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
setInitializesStdInitializerList(false);
- for (unsigned I = 0; I != numInits; ++I) {
+ for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
if (initExprs[I]->isValueDependent())
@@ -1686,7 +1763,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
ExprBits.ContainsUnexpandedParameterPack = true;
}
- InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits);
+ InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
}
void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
@@ -1723,15 +1800,15 @@ void InitListExpr::setArrayFiller(Expr *filler) {
bool InitListExpr::isStringLiteralInit() const {
if (getNumInits() != 1)
return false;
- const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(getType());
- if (!CAT || !CAT->getElementType()->isIntegerType())
+ const ArrayType *AT = getType()->getAsArrayTypeUnsafe();
+ if (!AT || !AT->getElementType()->isIntegerType())
return false;
- const Expr *Init = getInit(0)->IgnoreParenImpCasts();
+ const Expr *Init = getInit(0)->IgnoreParens();
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
SourceRange InitListExpr::getSourceRange() const {
- if (SyntacticForm)
+ if (InitListExpr *SyntacticForm = getSyntacticForm())
return SyntacticForm->getSourceRange();
SourceLocation Beg = LBraceLoc, End = RBraceLoc;
if (Beg.isInvalid()) {
@@ -1945,6 +2022,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
+ // If we don't know precisely what we're looking at, let's not warn.
+ case UnresolvedLookupExprClass:
+ case CXXUnresolvedConstructExprClass:
+ return false;
+
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass:
return false;
@@ -2014,6 +2096,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
R1 = getSourceRange();
return true;
}
+ case CXXFunctionalCastExprClass:
case CStyleCastExprClass: {
// Ignore an explicit cast to void unless the operand is a non-trivial
// volatile lvalue.
@@ -2032,6 +2115,10 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
+ // Ignore casts within macro expansions.
+ if (getExprLoc().isMacroID())
+ return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+
// If this is a cast to a constructor conversion, check the operand.
// Otherwise, the result of the cast is unused.
if (CE->getCastKind() == CK_ConstructorConversion)
@@ -2641,6 +2728,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case UnresolvedMemberExprClass:
case PackExpansionExprClass:
case SubstNonTypeTemplateParmPackExprClass:
+ case FunctionParmPackExprClass:
llvm_unreachable("shouldn't see dependent / unresolved nodes here");
case DeclRefExprClass:
@@ -2995,6 +3083,24 @@ const ObjCPropertyRefExpr *Expr::getObjCProperty() const {
return cast<ObjCPropertyRefExpr>(E);
}
+bool Expr::isObjCSelfExpr() const {
+ const Expr *E = IgnoreParenImpCasts();
+
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return false;
+
+ const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl());
+ if (!Param)
+ return false;
+
+ const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext());
+ if (!M)
+ return false;
+
+ return M->getSelfDecl() == Param;
+}
+
FieldDecl *Expr::getBitField() {
Expr *E = this->IgnoreParens();
@@ -3339,33 +3445,29 @@ Selector ObjCMessageExpr::getSelector() const {
return Selector(SelectorOrMethod);
}
-ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+QualType ObjCMessageExpr::getReceiverType() const {
switch (getReceiverKind()) {
case Instance:
- if (const ObjCObjectPointerType *Ptr
- = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- break;
-
+ return getInstanceReceiver()->getType();
case Class:
- if (const ObjCObjectType *Ty
- = getClassReceiver()->getAs<ObjCObjectType>())
- return Ty->getInterface();
- break;
-
+ return getClassReceiver();
case SuperInstance:
- if (const ObjCObjectPointerType *Ptr
- = getSuperType()->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- break;
-
case SuperClass:
- if (const ObjCObjectType *Iface
- = getSuperType()->getAs<ObjCObjectType>())
- return Iface->getInterface();
- break;
+ return getSuperType();
}
+ llvm_unreachable("unexpected receiver kind");
+}
+
+ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+ QualType T = getReceiverType();
+
+ if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+
+ if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>())
+ return Ty->getInterface();
+
return 0;
}
@@ -3386,17 +3488,17 @@ bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
return getCond()->EvaluateKnownConstInt(C) != 0;
}
-ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
+ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
QualType Type, SourceLocation BLoc,
SourceLocation RP)
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
Type->isDependentType(), Type->isDependentType(),
Type->isInstantiationDependentType(),
Type->containsUnexpandedParameterPack()),
- BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr)
+ BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size())
{
- SubExprs = new (C) Stmt*[nexpr];
- for (unsigned i = 0; i < nexpr; i++) {
+ SubExprs = new (C) Stmt*[args.size()];
+ for (unsigned i = 0; i != args.size(); i++) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
@@ -3421,8 +3523,9 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex)
@@ -3434,19 +3537,21 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
AssocExprs[ResultIndex]->isValueDependent(),
AssocExprs[ResultIndex]->isInstantiationDependent(),
ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
- SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
- ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
- RParenLoc(RParenLoc) {
+ AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
+ SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
+ NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex),
+ GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
- std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
- std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+ assert(AssocTypes.size() == AssocExprs.size());
+ std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
+ std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
- TypeSourceInfo **AssocTypes, Expr **AssocExprs,
- unsigned NumAssocs, SourceLocation DefaultLoc,
+ ArrayRef<TypeSourceInfo*> AssocTypes,
+ ArrayRef<Expr*> AssocExprs,
+ SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack)
: Expr(GenericSelectionExprClass,
@@ -3457,13 +3562,14 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
/*isValueDependent=*/true,
/*isInstantiationDependent=*/true,
ContainsUnexpandedParameterPack),
- AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
- SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
- ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
- RParenLoc(RParenLoc) {
+ AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]),
+ SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]),
+ NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc),
+ DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
- std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
- std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+ assert(AssocTypes.size() == AssocExprs.size());
+ std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes);
+ std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
//===----------------------------------------------------------------------===//
@@ -3483,8 +3589,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
- Expr **IndexExprs,
- unsigned NumIndexExprs,
+ ArrayRef<Expr*> IndexExprs,
Expr *Init)
: Expr(DesignatedInitExprClass, Ty,
Init->getValueKind(), Init->getObjectKind(),
@@ -3492,7 +3597,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
Init->isInstantiationDependent(),
Init->containsUnexpandedParameterPack()),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
- NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
+ NumDesignators(NumDesignators), NumSubExprs(IndexExprs.size() + 1) {
this->Designators = new (C) Designator[NumDesignators];
// Record the initializer itself.
@@ -3542,20 +3647,20 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
}
}
- assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions");
+ assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions");
}
DesignatedInitExpr *
DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
unsigned NumDesignators,
- Expr **IndexExprs, unsigned NumIndexExprs,
+ ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
- sizeof(Stmt *) * (NumIndexExprs + 1), 8);
+ sizeof(Stmt *) * (IndexExprs.size() + 1), 8);
return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
- IndexExprs, NumIndexExprs, Init);
+ IndexExprs, Init);
}
DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
@@ -3651,13 +3756,13 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
}
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
- Expr **exprs, unsigned nexprs,
+ ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
false, false, false, false),
- NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
- Exprs = new (C) Stmt*[nexprs];
- for (unsigned i = 0; i != nexprs; ++i) {
+ NumExprs(exprs.size()), LParenLoc(lparenloc), RParenLoc(rparenloc) {
+ Exprs = new (C) Stmt*[exprs.size()];
+ for (unsigned i = 0; i != exprs.size(); ++i) {
if (exprs[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (exprs[i]->isValueDependent())
@@ -3902,14 +4007,14 @@ ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
getMethod, setMethod, RB);
}
-AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
+AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
QualType t, AtomicOp op, SourceLocation RP)
: Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
false, false, false, false),
- NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
+ NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
{
- assert(nexpr == getNumSubExprs(op) && "wrong number of subexpressions");
- for (unsigned i = 0; i < nexpr; i++) {
+ assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions");
+ for (unsigned i = 0; i != args.size(); i++) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3fa49e0e18b9..55722a2a99af 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -51,6 +51,26 @@ QualType CXXUuidofExpr::getTypeOperand() const {
.getUnqualifiedType();
}
+// static
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+ // 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();
+
+ // Loop all record redeclaration looking for an uuid attribute.
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+ E = RD->redecls_end(); I != E; ++I) {
+ if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
+ return Uuid;
+ }
+
+ return 0;
+}
+
// CXXScalarValueInitExpr
SourceRange CXXScalarValueInitExpr::getSourceRange() const {
SourceLocation Start = RParenLoc;
@@ -63,24 +83,24 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const {
CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize,
- Expr **placementArgs, unsigned numPlaceArgs,
+ ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle,
Expr *initializer, QualType ty,
TypeSourceInfo *allocatedTypeInfo,
- SourceLocation startLoc, SourceRange directInitRange)
+ SourceRange Range, SourceRange directInitRange)
: Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
ty->isDependentType(), ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->containsUnexpandedParameterPack()),
SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
- StartLoc(startLoc), DirectInitRange(directInitRange),
+ Range(Range), DirectInitRange(directInitRange),
GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
assert((initializer != 0 || initializationStyle == NoInit) &&
"Only NoInit can have no initializer.");
StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
- AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0);
+ AllocateArgsArray(C, arraySize != 0, placementArgs.size(), initializer != 0);
unsigned i = 0;
if (Array) {
if (arraySize->isInstantiationDependent())
@@ -102,7 +122,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = initializer;
}
- for (unsigned j = 0; j < NumPlacementArgs; ++j) {
+ for (unsigned j = 0; j != placementArgs.size(); ++j) {
if (placementArgs[j]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (placementArgs[j]->containsUnexpandedParameterPack())
@@ -110,6 +130,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = placementArgs[j];
}
+
+ switch (getInitializationStyle()) {
+ case CallInit:
+ this->Range.setEnd(DirectInitRange.getEnd()); break;
+ case ListInit:
+ this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break;
+ default: break;
+ }
}
void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
@@ -127,18 +155,6 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
-SourceLocation CXXNewExpr::getEndLoc() const {
- switch (getInitializationStyle()) {
- case NoInit:
- return AllocatedTypeInfo->getTypeLoc().getEndLoc();
- case CallInit:
- return DirectInitRange.getEnd();
- case ListInit:
- return getInitializer()->getSourceRange().getEnd();
- }
- llvm_unreachable("bogus initialization style");
-}
-
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
const Expr *Arg = getArgument();
@@ -227,7 +243,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo,
ADL, /*Overload*/ true, Args,
- Begin, End, /*StdIsAssociated=*/false);
+ Begin, End);
}
UnresolvedLookupExpr *
@@ -697,15 +713,14 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
- Cons, false, Args, NumArgs,
+ Cons, false, Args,
HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
@@ -719,14 +734,14 @@ SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<Expr*> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs,
+ Elidable, Args,
HadMultipleCandidates, ListInitialization,
ZeroInitialization, ConstructKind,
ParenRange);
@@ -735,7 +750,7 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
- Expr **args, unsigned numargs,
+ ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
@@ -745,16 +760,16 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs),
+ Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
ConstructKind(ConstructKind), Args(0)
{
if (NumArgs) {
- Args = new (C) Stmt*[NumArgs];
+ Args = new (C) Stmt*[args.size()];
- for (unsigned i = 0; i != NumArgs; ++i) {
+ for (unsigned i = 0; i != args.size(); ++i) {
assert(args[i] && "NULL argument in CXXConstructExpr");
if (args[i]->isValueDependent())
@@ -877,9 +892,12 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
QualType T = Context.getTypeDeclType(Class);
unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1);
- if (!ArrayIndexVars.empty())
- Size += sizeof(VarDecl *) * ArrayIndexVars.size()
- + sizeof(unsigned) * (Captures.size() + 1);
+ if (!ArrayIndexVars.empty()) {
+ Size += sizeof(unsigned) * (Captures.size() + 1);
+ // Realign for following VarDecl array.
+ Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<VarDecl*>());
+ Size += sizeof(VarDecl *) * ArrayIndexVars.size();
+ }
void *Mem = Context.Allocate(Size);
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
Captures, ExplicitParams, ExplicitResultType,
@@ -997,8 +1015,7 @@ ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc)
: Expr(CXXUnresolvedConstructExprClass,
Type->getType().getNonReferenceType(),
@@ -1011,9 +1028,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
Type(Type),
LParenLoc(LParenLoc),
RParenLoc(RParenLoc),
- NumArgs(NumArgs) {
+ NumArgs(Args.size()) {
Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1);
- for (unsigned I = 0; I != NumArgs; ++I) {
+ for (unsigned I = 0; I != Args.size(); ++I) {
if (Args[I]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
@@ -1025,13 +1042,11 @@ CXXUnresolvedConstructExpr *
CXXUnresolvedConstructExpr::Create(ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<Expr*> Args,
SourceLocation RParenLoc) {
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
- sizeof(Expr *) * NumArgs);
- return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc,
- Args, NumArgs, RParenLoc);
+ sizeof(Expr *) * Args.size());
+ return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, RParenLoc);
}
CXXUnresolvedConstructExpr *
@@ -1300,6 +1315,34 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
return TemplateArgument(Arguments, NumArguments);
}
+FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
+ SourceLocation NameLoc,
+ unsigned NumParams,
+ Decl * const *Params)
+ : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary,
+ true, true, true, true),
+ ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
+ if (Params)
+ std::uninitialized_copy(Params, Params + NumParams,
+ reinterpret_cast<Decl**>(this+1));
+}
+
+FunctionParmPackExpr *
+FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+ ParmVarDecl *ParamPack, SourceLocation NameLoc,
+ llvm::ArrayRef<Decl*> Params) {
+ return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
+ sizeof(ParmVarDecl*) * Params.size()))
+ FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
+}
+
+FunctionParmPackExpr *
+FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) {
+ return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
+ sizeof(ParmVarDecl*) * NumParams))
+ FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
+}
+
TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc,
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index f16d70b5da1b..24ec6bb02074 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
+ case Expr::FunctionParmPackExprClass:
return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 06c41a2e7ea2..6e0b5fca60c0 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -953,7 +953,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
else
- Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ Info.Note(Base.get<const Expr*>()->getExprLoc(),
diag::note_constexpr_temporary_here);
}
@@ -987,6 +987,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
+ // Check if this is a thread-local variable.
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
+ if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
+ if (Var->isThreadSpecified())
+ return false;
+ }
+ }
+
// Allow address constant expressions to be past-the-end pointers. This is
// an extension: the standard requires them to point to an object.
if (!IsReferenceType)
@@ -2586,7 +2594,7 @@ public:
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
- assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
SubobjectDesignator Designator(BaseTy);
@@ -2665,7 +2673,7 @@ public:
if (E->isArrow()) {
if (!EvaluatePointer(E->getBase(), Result, this->Info))
return false;
- BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+ BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType();
} else if (E->getBase()->isRValue()) {
assert(E->getBase()->getType()->isRecordType());
if (!EvaluateTemporary(E->getBase(), Result, this->Info))
@@ -2878,19 +2886,13 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
}
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
- if (E->isTypeOperand())
+ if (!E->isPotentiallyEvaluated())
return Success(E);
- CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl();
- // FIXME: The standard says "a typeid expression whose operand is of a
- // polymorphic class type" is not a constant expression, but it probably
- // means "a typeid expression whose operand is potentially evaluated".
- if (RD && RD->isPolymorphic()) {
- Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
- return false;
- }
- return Success(E);
+
+ Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
+ return false;
}
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
@@ -3036,7 +3038,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
- QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
+ QualType Pointee = PExp->getType()->castAs<PointerType>()->getPointeeType();
return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
AdditionalOffset);
}
@@ -4288,6 +4290,16 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Error(E);
}
+ case Builtin::BI__builtin_bswap16:
+ case Builtin::BI__builtin_bswap32:
+ case Builtin::BI__builtin_bswap64: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.byteSwap(), E);
+ }
+
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
@@ -4902,7 +4914,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero())
return false;
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
- const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
+ const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>();
if (!LHSExpr || !RHSExpr)
return false;
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
@@ -5176,7 +5188,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
QualType Ty = E->getTypeOfArgument();
if (Ty->isVectorType()) {
- unsigned n = Ty->getAs<VectorType>()->getNumElements();
+ unsigned n = Ty->castAs<VectorType>()->getNumElements();
// The vec_step built-in functions that take a 3-component
// vector return 4. (OpenCL 1.1 spec 6.11.12)
@@ -5349,6 +5361,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralRealToComplex:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -5753,7 +5766,7 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
}
bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType ElemTy = E->getType()->castAs<ComplexType>()->getElementType();
if (ElemTy->isRealFloatingType()) {
Result.makeComplexFloat();
APFloat Zero = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(ElemTy));
@@ -5835,6 +5848,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -5911,9 +5925,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
return HandleIntToFloatCast(Info, E, From, Result.IntReal,
To, Result.FloatReal) &&
@@ -6177,11 +6191,9 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isVoidType()) {
- if (Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus0x)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
- else
- Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
if (!EvaluateVoid(E, Info))
return false;
} else if (Info.getLangOpts().CPlusPlus0x) {
@@ -6470,6 +6482,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::FunctionParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::MaterializeTemporaryExprClass:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 7c7a5e5de387..851944a42b6e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -343,17 +343,10 @@ private:
void mangleCXXDtorType(CXXDtorType T);
void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs);
- void mangleTemplateArgs(TemplateName Template,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgument *TemplateArgs,
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgumentList &AL);
- void mangleTemplateArg(const NamedDecl *P, TemplateArgument A);
- void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
- unsigned numArgs);
+ void mangleTemplateArgs(const TemplateArgumentList &AL);
+ void mangleTemplateArg(TemplateArgument A);
void mangleTemplateParameter(unsigned Index);
@@ -570,8 +563,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
return;
}
@@ -593,8 +585,7 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD,
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
} else {
mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
}
@@ -693,9 +684,10 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
if (Value.isSigned() && Value.isNegative()) {
Out << 'n';
- Value.abs().print(Out, true);
- } else
- Value.print(Out, Value.isSigned());
+ Value.abs().print(Out, /*signed*/ false);
+ } else {
+ Value.print(Out, /*signed*/ false);
+ }
}
void CXXNameMangler::mangleNumber(int64_t Number) {
@@ -737,8 +729,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
- TST->getNumArgs());
+ mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
} else if (const DependentTemplateSpecializationType *DTST
@@ -751,7 +742,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
} else {
// We use the QualType mangle type variant here because it handles
// substitutions.
@@ -942,7 +933,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
}
}
- mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
break;
}
@@ -959,7 +950,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
const DependentTemplateSpecializationType *tst
= cast<DependentTemplateSpecializationType>(type);
mangleSourceName(tst->getIdentifier());
- mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
break;
}
}
@@ -1228,8 +1219,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
}
else {
manglePrefix(DC, NoFunction);
@@ -1246,8 +1236,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'N';
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
Out << 'E';
}
@@ -1341,11 +1330,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
Out << "Ul";
- DeclarationName Name
- = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- const FunctionProtoType *Proto
- = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()->
- getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
+ getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
Out << "E";
@@ -1423,8 +1409,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ mangleTemplateArgs(*TemplateArgs);
}
else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
return;
@@ -2110,6 +2095,7 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
// ::= Dv [<dimension expression>] _ <element type>
// <extended element type> ::= <element type>
// ::= p # AltiVec vector pixel
+// ::= b # Altivec vector bool
void CXXNameMangler::mangleType(const VectorType *T) {
if ((T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
@@ -2174,7 +2160,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
addSubstitution(QualType(T, 0));
}
}
@@ -2200,7 +2186,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getArgs(), T->getNumArgs());
Out << 'E';
}
@@ -2414,7 +2400,6 @@ recurse:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
- case Expr::CXXNoexceptExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
case Expr::PseudoObjectExprClass:
@@ -2606,6 +2591,11 @@ recurse:
Out <<"_E";
break;
+ case Expr::CXXNoexceptExprClass:
+ Out << "nx";
+ mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand());
+ break;
+
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
@@ -2808,7 +2798,15 @@ recurse:
// };
Out << "_SUBSTPACK_";
break;
-
+
+ case Expr::FunctionParmPackExprClass: {
+ // FIXME: not clear how to mangle this!
+ const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
+ Out << "v110_SUBSTPACK";
+ mangleFunctionParam(FPPE->getParameterPack());
+ break;
+ }
+
case Expr::DependentScopeDeclRefExprClass: {
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
@@ -3043,50 +3041,28 @@ void CXXNameMangler::mangleTemplateArgs(
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
- mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument());
- Out << 'E';
-}
-
-void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
- NumTemplateArgs);
-
- mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs);
-}
-
-void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args,
- unsigned numArgs) {
- // <template-args> ::= I <template-arg>+ E
- Out << 'I';
- for (unsigned i = 0; i != numArgs; ++i)
- mangleTemplateArg(0, args[i]);
+ mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument());
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgumentList &AL) {
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0, e = AL.size(); i != e; ++i)
- mangleTemplateArg(PL.getParam(i), AL[i]);
+ mangleTemplateArg(AL[i]);
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
- const TemplateArgument *TemplateArgs,
+void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
+ mangleTemplateArg(TemplateArgs[i]);
Out << 'E';
}
-void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
- TemplateArgument A) {
+void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
@@ -3135,25 +3111,12 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
- assert(P && "Missing template parameter for declaration argument");
// <expr-primary> ::= L <mangled-name> E # external name
- // <expr-primary> ::= L <type> 0 E
// Clang produces AST's where pointer-to-member-function expressions
// and pointer-to-function expressions are represented as a declaration not
// an expression. We compensate for it here to produce the correct mangling.
- const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
-
- // Handle NULL pointer arguments.
- if (!A.getAsDecl()) {
- Out << "L";
- mangleType(Parameter->getType());
- Out << "0E";
- break;
- }
-
-
- NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
- bool compensateMangling = !Parameter->getType()->isReferenceType();
+ ValueDecl *D = A.getAsDecl();
+ bool compensateMangling = !A.isDeclForReferenceParam();
if (compensateMangling) {
Out << 'X';
mangleOperatorName(OO_Amp, 1);
@@ -3176,14 +3139,20 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
break;
}
-
+ case TemplateArgument::NullPtr: {
+ // <expr-primary> ::= L <type> 0 E
+ Out << 'L';
+ mangleType(A.getNullPtrType());
+ Out << "0E";
+ break;
+ }
case TemplateArgument::Pack: {
// Note: proposal by Mike Herrick on 12/20/10
Out << 'J';
for (TemplateArgument::pack_iterator PA = A.pack_begin(),
PAEnd = A.pack_end();
PA != PAEnd; ++PA)
- mangleTemplateArg(P, *PA);
+ mangleTemplateArg(*PA);
Out << 'E';
}
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index e2cee7f52cfb..5d5b83d9a30b 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include <map>
@@ -56,7 +57,7 @@ public:
void mangleVariableEncoding(const VarDecl *VD);
void mangleNumber(int64_t Number);
void mangleNumber(const llvm::APSInt &Value);
- void mangleType(QualType T, SourceRange Range);
+ void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true);
private:
void disableBackReferences() { UseNameBackReferences = false; }
@@ -68,6 +69,7 @@ private:
void manglePostfix(const DeclContext *DC, bool NoFunction=false);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
+ void manglePointerQualifiers(Qualifiers Quals);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleTemplateInstantiationName(const TemplateDecl *TD,
@@ -75,7 +77,7 @@ private:
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleLocalName(const FunctionDecl *FD);
- void mangleTypeRepeated(QualType T, SourceRange Range);
+ void mangleArgumentType(QualType T, SourceRange Range);
// Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -95,6 +97,7 @@ private:
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number);
+ void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
void mangleTemplateArgs(
@@ -266,18 +269,18 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
Out << '4';
// Now mangle the type.
// <variable-type> ::= <type> <cvr-qualifiers>
- // ::= <type> A # pointers, references, arrays
+ // ::= <type> <pointee-cvr-qualifiers> # pointers, references
// Pointers and references are odd. The type of 'int * const foo;' gets
// mangled as 'QAHA' instead of 'PAHB', for example.
TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
QualType Ty = TL.getType();
if (Ty->isPointerType() || Ty->isReferenceType()) {
mangleType(Ty, TL.getSourceRange());
- Out << 'A';
+ mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
} else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
// Global arrays are funny, too.
mangleType(AT, true);
- Out << 'A';
+ mangleQualifiers(Ty.getQualifiers(), false);
} else {
mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange());
mangleQualifiers(Ty.getLocalQualifiers(), false);
@@ -304,39 +307,23 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
}
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
- // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
- // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
- if (Number < 0) {
- Out << '?';
- Number = -Number;
- }
- // There's a special shorter mangling for 0, but Microsoft
- // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
- if (Number >= 1 && Number <= 10)
- Out << Number-1;
- else {
- // We have to build up the encoding in reverse order, so it will come
- // out right when we write it out.
- char Encoding[16];
- char *EndPtr = Encoding+sizeof(Encoding);
- char *CurPtr = EndPtr;
- do {
- *--CurPtr = 'A' + (Number % 16);
- Number /= 16;
- } while (Number);
- Out.write(CurPtr, EndPtr-CurPtr);
- Out << '@';
- }
+ 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()) {
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);
@@ -348,10 +335,10 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
char *CurPtr = EndPtr;
llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
NibbleMask = 0xf;
- for (int i = 0, e = Value.getActiveBits() / 4; i != e; ++i) {
+ do {
*--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
Temp = Temp.lshr(4);
- }
+ } while (Temp != 0);
Out.write(CurPtr, EndPtr-CurPtr);
Out << '@';
}
@@ -386,7 +373,7 @@ isTemplate(const NamedDecl *ND,
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
TypeSourceInfo *TSI = Spec->getTypeAsWritten();
if (TSI) {
- TemplateSpecializationTypeLoc &TSTL =
+ TemplateSpecializationTypeLoc TSTL =
cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
@@ -784,6 +771,23 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T,
}
void
+MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
+ // See if this is a constant expression.
+ llvm::APSInt Value;
+ if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
+ mangleIntegerLiteral(E->getType(), Value);
+ return;
+ }
+
+ // As bad as this diagnostic is, it's better than crashing.
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+}
+
+void
MicrosoftCXXNameMangler::mangleTemplateArgs(
const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
// <template-args> ::= {<type> | <integer-literal>}+ @
@@ -800,21 +804,19 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(
case TemplateArgument::Integral:
mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
break;
- case TemplateArgument::Expression: {
- // See if this is a constant expression.
- Expr *TAE = TA.getAsExpr();
- llvm::APSInt Value;
- if (TAE->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(TAE->getType(), Value);
- break;
- }
- /* fallthrough */
- } default: {
+ case TemplateArgument::Expression:
+ mangleExpression(TA.getAsExpr());
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Pack: {
// Issue a diagnostic.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this %select{ERROR|ERROR|pointer/reference|ERROR|"
- "template|template pack expansion|expression|parameter pack}0 "
+ "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
+ "integral|template|template pack expansion|ERROR|parameter pack}0 "
"template argument yet");
Diags.Report(TAL.getLocation(), DiagID)
<< TA.getKind()
@@ -879,43 +881,60 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
// ::= 3 # ?
// ::= 4 # ?
// ::= 5 # not really based
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
if (!IsMember) {
- if (!Quals.hasVolatile()) {
- if (!Quals.hasConst())
- Out << 'A';
- else
- Out << 'B';
+ if (HasConst && HasVolatile) {
+ Out << 'D';
+ } else if (HasVolatile) {
+ Out << 'C';
+ } else if (HasConst) {
+ Out << 'B';
} else {
- if (!Quals.hasConst())
- Out << 'C';
- else
- Out << 'D';
+ Out << 'A';
}
} else {
- if (!Quals.hasVolatile()) {
- if (!Quals.hasConst())
- Out << 'Q';
- else
- Out << 'R';
+ if (HasConst && HasVolatile) {
+ Out << 'T';
+ } else if (HasVolatile) {
+ Out << 'S';
+ } else if (HasConst) {
+ Out << 'R';
} else {
- if (!Quals.hasConst())
- Out << 'S';
- else
- Out << 'T';
+ Out << 'Q';
}
}
// FIXME: For now, just drop all extension qualifiers on the floor.
}
-void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) {
+void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
+ // <pointer-cvr-qualifiers> ::= P # no qualifiers
+ // ::= Q # const
+ // ::= R # volatile
+ // ::= S # const volatile
+ bool HasConst = Quals.hasConst(),
+ HasVolatile = Quals.hasVolatile();
+ if (HasConst && HasVolatile) {
+ Out << 'S';
+ } else if (HasVolatile) {
+ Out << 'R';
+ } else if (HasConst) {
+ Out << 'Q';
+ } else {
+ Out << 'P';
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
+ SourceRange Range) {
void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
size_t OutSizeBefore = Out.GetNumBytesInBuffer();
- mangleType(T,Range);
+ mangleType(T, Range, false);
// See if it's worth creating a back reference.
// Only types longer than 1 character are considered
@@ -930,38 +949,30 @@ void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range)
}
}
-void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) {
+void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
+ bool MangleQualifiers) {
// Only operate on the canonical type!
T = getASTContext().getCanonicalType(T);
-
+
Qualifiers Quals = T.getLocalQualifiers();
- if (Quals) {
- // We have to mangle these now, while we still have enough information.
- // <pointer-cvr-qualifiers> ::= P # pointer
- // ::= Q # const pointer
- // ::= R # volatile pointer
- // ::= S # const volatile pointer
- if (T->isAnyPointerType() || T->isMemberPointerType() ||
- T->isBlockPointerType()) {
- if (!Quals.hasVolatile())
- Out << 'Q';
- else {
- if (!Quals.hasConst())
- Out << 'R';
- else
- Out << 'S';
- }
- } else
- // Just emit qualifiers like normal.
- // NB: When we mangle a pointer/reference type, and the pointee
- // type has no qualifiers, the lack of qualifier gets mangled
- // in there.
- mangleQualifiers(Quals, false);
- } else if (T->isAnyPointerType() || T->isMemberPointerType() ||
- T->isBlockPointerType()) {
- Out << 'P';
+ // We have to mangle these now, while we still have enough information.
+ if (T->isAnyPointerType() || T->isMemberPointerType() ||
+ T->isBlockPointerType()) {
+ manglePointerQualifiers(Quals);
+ } else if (Quals && MangleQualifiers) {
+ mangleQualifiers(Quals, false);
}
- switch (T->getTypeClass()) {
+
+ SplitQualType split = T.split();
+ const Type *ty = split.Ty;
+
+ // If we're mangling a qualified array type, push the qualifiers to
+ // the element type.
+ if (split.Quals && isa<ArrayType>(T)) {
+ ty = Context.getASTContext().getAsArrayType(T);
+ }
+
+ switch (ty->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT) \
case Type::CLASS: \
@@ -969,7 +980,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) {
return;
#define TYPE(CLASS, PARENT) \
case Type::CLASS: \
- mangleType(static_cast<const CLASS##Type*>(T.getTypePtr()), Range); \
+ mangleType(cast<CLASS##Type>(ty), Range); \
break;
#include "clang/AST/TypeNodes.def"
#undef ABSTRACT_TYPE
@@ -1059,6 +1070,8 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
SourceRange) {
// Structors only appear in decls, so at this point we know it's not a
// structor type.
+ // FIXME: This may not be lambda-friendly.
+ Out << "$$A6";
mangleType(T, NULL, false, false);
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
@@ -1117,14 +1130,14 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
- mangleTypeRepeated(Type, (*Parm)->getSourceRange());
+ 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)
- mangleTypeRepeated(*Arg, SourceRange());
+ mangleArgumentType(*Arg, SourceRange());
}
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
@@ -1214,7 +1227,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
if (CC == CC_Default) {
if (IsInstMethod) {
const FunctionProtoType *FPT =
- T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+ T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
bool isVariadic = FPT->isVariadic();
CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
} else {
@@ -1260,10 +1273,10 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
// <class-type> ::= V <name>
// <enum-type> ::= W <size> <name>
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
- mangleType(static_cast<const TagType*>(T));
+ mangleType(cast<TagType>(T));
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
- mangleType(static_cast<const TagType*>(T));
+ mangleType(cast<TagType>(T));
}
void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
switch (T->getDecl()->getTagKind()) {
@@ -1271,6 +1284,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
Out << 'T';
break;
case TTK_Struct:
+ case TTK_Interface:
Out << 'U';
break;
case TTK_Class:
@@ -1286,37 +1300,39 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
}
// <type> ::= <array-type>
-// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as global
+// <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 param
// 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::mangleType(const ArrayType *T, bool IsGlobal) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
- if (IsGlobal)
- Out << 'P';
- else
+ if (IsGlobal) {
+ manglePointerQualifiers(T->getElementType().getQualifiers());
+ } else {
Out << 'Q';
+ }
mangleExtraDimensions(T->getElementType());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
SourceRange) {
- mangleType(static_cast<const ArrayType *>(T), false);
+ mangleType(cast<ArrayType>(T), false);
}
void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
SmallVector<llvm::APInt, 3> Dimensions;
@@ -1409,10 +1425,8 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
Out << '6';
mangleType(FT, NULL, false, false);
} else {
- if (!PointeeTy.hasQualifiers())
- // Lack of qualifiers is mangled as 'A'.
- Out << 'A';
- mangleType(PointeeTy, Range);
+ mangleQualifiers(PointeeTy.getQualifiers(), false);
+ mangleType(PointeeTy, Range, false);
}
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
@@ -1497,7 +1511,9 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T,
void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
SourceRange Range) {
Out << "_E";
- mangleType(T->getPointeeType(), Range);
+
+ QualType pointee = T->getPointeeType();
+ mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
}
void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 39077d1766e8..0837509194bc 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::ARCUnbridgedCast:
case BuiltinType::Half:
case BuiltinType::PseudoObject:
+ case BuiltinType::BuiltinFn:
break;
}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index fa87afd0fa22..113592860b77 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -20,22 +20,63 @@ using namespace clang;
typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;
-static void BuildParentMap(MapTy& M, Stmt* S) {
- for (Stmt::child_range I = S->children(); I; ++I)
- if (*I) {
- // Prefer the first time we see this statement in the traversal.
- // This is important for PseudoObjectExprs.
- Stmt *&Parent = M[*I];
- if (!Parent) {
- Parent = S;
- BuildParentMap(M, *I);
+enum OpaqueValueMode {
+ OV_Transparent,
+ OV_Opaque
+};
+
+static void BuildParentMap(MapTy& M, Stmt* S,
+ OpaqueValueMode OVMode = OV_Transparent) {
+
+ switch (S->getStmtClass()) {
+ case Stmt::PseudoObjectExprClass: {
+ assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
+ PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+
+ M[POE->getSyntacticForm()] = S;
+ BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
+
+ for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),
+ E = POE->semantics_end();
+ I != E; ++I) {
+ M[*I] = S;
+ BuildParentMap(M, *I, OV_Opaque);
+ }
+ break;
+ }
+ case Stmt::BinaryConditionalOperatorClass: {
+ assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
+ BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S);
+
+ M[BCO->getCommon()] = S;
+ BuildParentMap(M, BCO->getCommon(), OV_Transparent);
+
+ M[BCO->getCond()] = S;
+ BuildParentMap(M, BCO->getCond(), OV_Opaque);
+
+ M[BCO->getTrueExpr()] = S;
+ BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque);
+
+ M[BCO->getFalseExpr()] = S;
+ BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent);
+
+ break;
+ }
+ case Stmt::OpaqueValueExprClass:
+ if (OVMode == OV_Transparent) {
+ OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ M[OVE->getSourceExpr()] = S;
+ BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
+ }
+ break;
+ default:
+ for (Stmt::child_range I = S->children(); I; ++I) {
+ if (*I) {
+ M[*I] = S;
+ BuildParentMap(M, *I, OVMode);
}
}
-
- // Also include the source expr tree of an OpaqueValueExpr in the map.
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {
- M[OVE->getSourceExpr()] = S;
- BuildParentMap(M, OVE->getSourceExpr());
+ break;
}
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index a5a32870577a..80b627293e42 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -143,11 +143,10 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const {
// a separate allocator for all temporary stuff.
llvm::BumpPtrAllocator Allocator;
- comments::CommandTraits Traits;
- comments::Lexer L(Allocator, Traits,
- Range.getBegin(), comments::CommentOptions(),
+ comments::Lexer L(Allocator, Context.getCommentCommandTraits(),
+ Range.getBegin(),
RawText.begin(), RawText.end());
- comments::BriefParser P(L, Traits);
+ comments::BriefParser P(L, Context.getCommentCommandTraits());
const std::string Result = P.Parse();
const unsigned BriefTextLength = Result.size();
@@ -160,19 +159,22 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const {
}
comments::FullComment *RawComment::parse(const ASTContext &Context,
+ const Preprocessor *PP,
const Decl *D) const {
// Make sure that RawText is valid.
getRawText(Context.getSourceManager());
- comments::CommandTraits Traits;
- comments::Lexer L(Context.getAllocator(), Traits,
- getSourceRange().getBegin(), comments::CommentOptions(),
+ comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(),
+ getSourceRange().getBegin(),
RawText.begin(), RawText.end());
comments::Sema S(Context.getAllocator(), Context.getSourceManager(),
- Context.getDiagnostics(), Traits);
+ Context.getDiagnostics(),
+ Context.getCommentCommandTraits(),
+ PP);
S.setDecl(D);
comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(),
- Context.getDiagnostics(), Traits);
+ Context.getDiagnostics(),
+ Context.getCommentCommandTraits());
return P.parseFullComment();
}
@@ -182,26 +184,22 @@ bool containsOnlyWhitespace(StringRef Str) {
return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos;
}
-bool onlyWhitespaceBetweenComments(SourceManager &SM,
- const RawComment &C1, const RawComment &C2) {
- std::pair<FileID, unsigned> C1EndLocInfo = SM.getDecomposedLoc(
- C1.getSourceRange().getEnd());
- std::pair<FileID, unsigned> C2BeginLocInfo = SM.getDecomposedLoc(
- C2.getSourceRange().getBegin());
+bool onlyWhitespaceBetween(SourceManager &SM,
+ SourceLocation Loc1, SourceLocation Loc2) {
+ std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1);
+ std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2);
- // Question does not make sense if comments are located in different files.
- if (C1EndLocInfo.first != C2BeginLocInfo.first)
+ // Question does not make sense if locations are in different files.
+ if (Loc1Info.first != Loc2Info.first)
return false;
bool Invalid = false;
- const char *Buffer = SM.getBufferData(C1EndLocInfo.first, &Invalid).data();
+ const char *Buffer = SM.getBufferData(Loc1Info.first, &Invalid).data();
if (Invalid)
return false;
- StringRef TextBetweenComments(Buffer + C1EndLocInfo.second,
- C2BeginLocInfo.second - C1EndLocInfo.second);
-
- return containsOnlyWhitespace(TextBetweenComments);
+ StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second);
+ return containsOnlyWhitespace(Text);
}
} // unnamed namespace
@@ -221,11 +219,13 @@ void RawCommentList::addComment(const RawComment &RC,
}
if (OnlyWhitespaceSeen) {
- if (!onlyWhitespaceBetweenComments(SourceMgr, LastComment, RC))
+ if (!onlyWhitespaceBetween(SourceMgr,
+ PrevCommentEndLoc,
+ RC.getSourceRange().getBegin()))
OnlyWhitespaceSeen = false;
}
- LastComment = RC;
+ PrevCommentEndLoc = RC.getSourceRange().getEnd();
// Ordinary comments are not interesting for us.
if (RC.isOrdinary())
@@ -244,15 +244,20 @@ 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 trailing comments if they are on same or consecutive lines.
+ // Merge comments if they are on same or consecutive lines.
+ bool Merged = false;
if (OnlyWhitespaceSeen &&
- (C1.isTrailingComment() == C2.isTrailingComment()) &&
- (!C1.isTrailingComment() ||
- C1.getEndLine(SourceMgr) + 1 >= C2.getBeginLine(SourceMgr))) {
- SourceRange MergedRange(C1.getSourceRange().getBegin(),
- C2.getSourceRange().getEnd());
- *Comments.back() = RawComment(SourceMgr, MergedRange, true);
- } else
+ (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);
+ Merged = true;
+ }
+ }
+ if (!Merged)
Comments.push_back(new (Allocator) RawComment(RC));
OnlyWhitespaceSeen = true;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index d5df63f7d151..4dfffc45e49c 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -789,8 +789,8 @@ protected:
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
- RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
- void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
+ RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+ void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
@@ -1557,6 +1557,13 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
(void)Allowed;
assert(Allowed && "Base subobject externally placed at overlapping offset");
+
+ if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){
+ // The externally-supplied base offset is before the base offset we
+ // computed. Assume that the structure is packed.
+ Alignment = CharUnits::One();
+ InferAlignment = false;
+ }
}
if (!Base->Class->isEmpty()) {
@@ -1574,12 +1581,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
- if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
IsUnion = RD->isUnion();
+ IsMsStruct = RD->isMsStruct(Context);
+ }
- Packed = D->hasAttr<PackedAttr>();
-
- IsMsStruct = D->hasAttr<MsStructAttr>();
+ Packed = D->hasAttr<PackedAttr>();
// Honor the default struct packing maximum alignment flag.
if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
@@ -1616,7 +1623,6 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
if (ExternalLayout) {
if (ExternalAlign > 0) {
Alignment = Context.toCharUnitsFromBits(ExternalAlign);
- UnpackedAlignment = Alignment;
} else {
// The external source didn't have alignment information; infer it.
InferAlignment = true;
@@ -2085,7 +2091,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
ZeroLengthBitfield = 0;
}
- if (Context.getLangOpts().MSBitfields || IsMsStruct) {
+ 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.
@@ -2166,11 +2172,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
}
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
- if (ExternalLayout) {
- setSize(ExternalSize);
- return;
- }
-
// In C++, records cannot be of size 0.
if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
@@ -2184,20 +2185,37 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
setSize(CharUnits::One());
}
+ // Finally, round the size of the record up to the alignment of the
+ // record itself.
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpackedSizeInBits =
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.toBits(UnpackedAlignment));
+ CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
+ uint64_t RoundedSize
+ = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment));
+
+ if (ExternalLayout) {
+ // If we're inferring alignment, and the external size is smaller than
+ // our size after we've rounded up to alignment, conservatively set the
+ // alignment to 1.
+ if (InferAlignment && ExternalSize < RoundedSize) {
+ Alignment = CharUnits::One();
+ InferAlignment = false;
+ }
+ setSize(ExternalSize);
+ 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;
}
- // Finally, round the size of the record up to the alignment of the
- // record itself.
- uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
- uint64_t UnpackedSizeInBits =
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.toBits(UnpackedAlignment));
- CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
- setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
+ // Set the size to the final size.
+ setSize(RoundedSize);
unsigned CharBitNum = Context.getTargetInfo().getCharWidth();
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
@@ -2255,7 +2273,7 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
// The externally-supplied field offset is before the field offset we
// computed. Assume that the structure is packed.
- Alignment = CharUnits::fromQuantity(1);
+ Alignment = CharUnits::One();
InferAlignment = false;
}
@@ -2263,6 +2281,20 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
return ExternalFieldOffset;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// field padding diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for field padding diagnostic!");
+ }
+}
+
void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
uint64_t UnpaddedOffset,
uint64_t UnpackedOffset,
@@ -2291,14 +2323,14 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
}
if (D->getIdentifier())
Diag(D->getLocation(), diag::warn_padded_struct_field)
- << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not
<< D->getIdentifier();
else
Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
- << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
@@ -2508,8 +2540,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
- ObjCContainerDecl *Key =
- Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
+ const ObjCContainerDecl *Key =
+ Impl ? (const ObjCContainerDecl*) Impl : (const ObjCContainerDecl*) D;
if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
return *Entry;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 77452c9d9d1c..eafcf92eee82 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -320,15 +321,52 @@ bool Stmt::hasImplicitControlFlow() const {
}
}
-Expr *AsmStmt::getOutputExpr(unsigned i) {
- return cast<Expr>(Exprs[i]);
+std::string AsmStmt::generateAsmString(ASTContext &C) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->generateAsmString(C);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->generateAsmString(C);
+ llvm_unreachable("unknown asm statement kind!");
}
-/// getOutputConstraint - Return the constraint string for the specified
-/// output operand. All output constraints are known to be non-empty (either
-/// '=' or '+').
StringRef AsmStmt::getOutputConstraint(unsigned i) const {
- return getOutputConstraintLiteral(i)->getString();
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getOutputConstraint(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getOutputConstraint(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+const Expr *AsmStmt::getOutputExpr(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getOutputExpr(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getOutputExpr(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+StringRef AsmStmt::getInputConstraint(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getInputConstraint(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getInputConstraint(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+const Expr *AsmStmt::getInputExpr(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getInputExpr(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getInputExpr(i);
+ llvm_unreachable("unknown asm statement kind!");
+}
+
+StringRef AsmStmt::getClobber(unsigned i) const {
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
+ return gccAsmStmt->getClobber(i);
+ if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
+ return msAsmStmt->getClobber(i);
+ llvm_unreachable("unknown asm statement kind!");
}
/// getNumPlusOperands - Return the number of output operands that have a "+"
@@ -341,22 +379,35 @@ unsigned AsmStmt::getNumPlusOperands() const {
return Res;
}
-Expr *AsmStmt::getInputExpr(unsigned i) {
+StringRef GCCAsmStmt::getClobber(unsigned i) const {
+ return getClobberStringLiteral(i)->getString();
+}
+
+Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i]);
+}
+
+/// getOutputConstraint - Return the constraint string for the specified
+/// output operand. All output constraints are known to be non-empty (either
+/// '=' or '+').
+StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const {
+ return getOutputConstraintLiteral(i)->getString();
+}
+
+Expr *GCCAsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
-void AsmStmt::setInputExpr(unsigned i, Expr *E) {
+void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
Exprs[i + NumOutputs] = E;
}
-
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
-StringRef AsmStmt::getInputConstraint(unsigned i) const {
+StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
return getInputConstraintLiteral(i)->getString();
}
-
-void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
+void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
IdentifierInfo **Names,
StringLiteral **Constraints,
Stmt **Exprs,
@@ -390,7 +441,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
-int AsmStmt::getNamedOperand(StringRef SymbolicName) const {
+int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
@@ -410,7 +461,7 @@ int AsmStmt::getNamedOperand(StringRef SymbolicName) const {
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
-unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
+unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
ASTContext &C, unsigned &DiagOffs) const {
StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
@@ -548,6 +599,44 @@ unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
}
}
+/// Assemble final IR asm string (GCC-style).
+std::string GCCAsmStmt::generateAsmString(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;
+ unsigned DiagOffs;
+ AnalyzeAsmString(Pieces, C, DiagOffs);
+
+ std::string AsmString;
+ for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
+ if (Pieces[i].isString())
+ AsmString += Pieces[i].getString();
+ else if (Pieces[i].getModifier() == '\0')
+ AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo());
+ else
+ AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' +
+ Pieces[i].getModifier() + '}';
+ }
+ return AsmString;
+}
+
+/// Assemble final IR asm string (MS-style).
+std::string MSAsmStmt::generateAsmString(ASTContext &C) const {
+ // FIXME: This needs to be translated into the IR string representation.
+ return AsmStr;
+}
+
+Expr *MSAsmStmt::getOutputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i]);
+}
+
+Expr *MSAsmStmt::getInputExpr(unsigned i) {
+ return cast<Expr>(Exprs[i + NumOutputs]);
+}
+void MSAsmStmt::setInputExpr(unsigned i, Expr *E) {
+ Exprs[i + NumOutputs] = E;
+}
+
QualType CXXCatchStmt::getCaughtType() const {
if (ExceptionDecl)
return ExceptionDecl->getType();
@@ -558,15 +647,14 @@ QualType CXXCatchStmt::getCaughtType() const {
// Constructors
//===----------------------------------------------------------------------===//
-AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
- bool isvolatile, bool msasm,
- unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints,
- Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
- StringLiteral **clobbers, SourceLocation rparenloc)
- : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
- , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
- , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
+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)
+ : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
+ numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
unsigned NumExprs = NumOutputs + NumInputs;
@@ -585,26 +673,37 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
SourceLocation lbraceloc, bool issimple, bool isvolatile,
- ArrayRef<Token> asmtoks, ArrayRef<IdentifierInfo*> inputs,
- ArrayRef<IdentifierInfo*> outputs, StringRef asmstr,
- ArrayRef<StringRef> clobbers, SourceLocation endloc)
- : Stmt(MSAsmStmtClass), AsmLoc(asmloc), LBraceLoc(lbraceloc), EndLoc(endloc),
- AsmStr(asmstr.str()), IsSimple(issimple), IsVolatile(isvolatile),
- NumAsmToks(asmtoks.size()), NumInputs(inputs.size()),
- NumOutputs(outputs.size()), NumClobbers(clobbers.size()) {
+ ArrayRef<Token> asmtoks, unsigned numoutputs,
+ unsigned numinputs, ArrayRef<IdentifierInfo*> names,
+ ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
+ StringRef asmstr, ArrayRef<StringRef> clobbers,
+ SourceLocation endloc)
+ : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
+ numinputs, clobbers.size()), LBraceLoc(lbraceloc),
+ EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) {
unsigned NumExprs = NumOutputs + NumInputs;
Names = new (C) IdentifierInfo*[NumExprs];
- for (unsigned i = 0, e = NumOutputs; i != e; ++i)
- Names[i] = outputs[i];
- for (unsigned i = NumOutputs, e = NumExprs; i != e; ++i)
- Names[i] = inputs[i];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i)
+ Names[i] = names[i];
+
+ Exprs = new (C) Stmt*[NumExprs];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i)
+ Exprs[i] = exprs[i];
AsmToks = new (C) Token[NumAsmToks];
for (unsigned i = 0, e = NumAsmToks; i != e; ++i)
AsmToks[i] = asmtoks[i];
+ Constraints = new (C) StringRef[NumExprs];
+ for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+ size_t size = constraints[i].size();
+ char *dest = new (C) char[size];
+ std::strncpy(dest, constraints[i].data(), size);
+ Constraints[i] = StringRef(dest, size);
+ }
+
Clobbers = new (C) StringRef[NumClobbers];
for (unsigned i = 0, e = NumClobbers; i != e; ++i) {
// FIXME: Avoid the allocation/copy if at all possible.
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 962e35269c18..fbc990f6b3c2 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Stmt::dump/Stmt::print methods, which dump out the
+// This file implements the Stmt::dump method, which dumps out the
// AST in a form that exposes type details and other fields.
//
//===----------------------------------------------------------------------===//
@@ -30,6 +30,7 @@ namespace {
SourceManager *SM;
raw_ostream &OS;
unsigned IndentLevel;
+ bool IsFirstLine;
/// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
/// the first few levels of an AST. This keeps track of how many ast levels
@@ -41,46 +42,64 @@ namespace {
const char *LastLocFilename;
unsigned LastLocLine;
+ class IndentScope {
+ StmtDumper &Dumper;
+ public:
+ IndentScope(StmtDumper &Dumper) : Dumper(Dumper) {
+ Dumper.indent();
+ }
+ ~IndentScope() {
+ Dumper.unindent();
+ }
+ };
+
public:
StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
+ : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) {
LastLocFilename = "";
LastLocLine = ~0U;
}
+ ~StmtDumper() {
+ OS << "\n";
+ }
+
void DumpSubTree(Stmt *S) {
// Prune the recursion if not using dump all.
if (MaxDepth == 0) return;
- ++IndentLevel;
- if (S) {
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
- VisitDeclStmt(DS);
- else {
- Visit(S);
-
- // Print out children.
- Stmt::child_range CI = S->children();
- if (CI) {
- while (CI) {
- OS << '\n';
- DumpSubTree(*CI++);
- }
- }
- }
- OS << ')';
- } else {
- Indent();
+ IndentScope Indent(*this);
+
+ if (!S) {
OS << "<<<NULL>>>";
+ return;
+ }
+
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
}
- --IndentLevel;
+
+ Visit(S);
+ for (Stmt::child_range CI = S->children(); CI; CI++)
+ DumpSubTree(*CI);
}
void DumpDeclarator(Decl *D);
- void Indent() const {
- for (int i = 0, e = IndentLevel; i < e; ++i)
- OS << " ";
+ void indent() {
+ if (IsFirstLine)
+ IsFirstLine = false;
+ else
+ OS << "\n";
+ OS.indent(IndentLevel * 2);
+ OS << "(";
+ IndentLevel++;
+ }
+
+ void unindent() {
+ OS << ")";
+ IndentLevel--;
}
void DumpType(QualType T) {
@@ -96,9 +115,8 @@ namespace {
}
void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
- Indent();
- OS << "(" << Node->getStmtClassName()
- << " " << (void*)Node;
+ OS << Node->getStmtClassName()
+ << " " << (const void*)Node;
DumpSourceRange(Node);
}
void DumpValueKind(ExprValueKind K) {
@@ -262,7 +280,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// If this is a vardecl with an initializer, emit it.
if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
if (V->getInit()) {
- OS << " =\n";
+ OS << " =";
DumpSubTree(V->getInit());
}
}
@@ -294,9 +312,9 @@ void StmtDumper::DumpDeclarator(Decl *D) {
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << *LD;
} else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(\n";
+ OS << "\"static_assert(";
DumpSubTree(SAD->getAssertExpr());
- OS << ",\n";
+ OS << ",";
DumpSubTree(SAD->getMessage());
OS << ");\"";
} else {
@@ -306,17 +324,12 @@ void StmtDumper::DumpDeclarator(Decl *D) {
void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
DumpStmt(Node);
- OS << "\n";
for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
DI != DE; ++DI) {
+ IndentScope Indent(*this);
Decl* D = *DI;
- ++IndentLevel;
- Indent();
OS << (void*) D << " ";
DumpDeclarator(D);
- if (DI+1 != DE)
- OS << "\n";
- --IndentLevel;
}
}
@@ -503,35 +516,29 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *block = Node->getBlockDecl();
OS << " decl=" << block;
- IndentLevel++;
if (block->capturesCXXThis()) {
- OS << '\n'; Indent(); OS << "(capture this)";
+ IndentScope Indent(*this);
+ OS << "capture this";
}
for (BlockDecl::capture_iterator
i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- OS << '\n';
- Indent();
- OS << "(capture ";
+ IndentScope Indent(*this);
+ OS << "capture ";
if (i->isByRef()) OS << "byref ";
if (i->isNested()) OS << "nested ";
if (i->getVariable())
DumpDeclRef(i->getVariable());
if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
- OS << ")";
}
- IndentLevel--;
- OS << '\n';
DumpSubTree(block->getBody());
}
void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
DumpExpr(Node);
- if (Expr *Source = Node->getSourceExpr()) {
- OS << '\n';
+ if (Expr *Source = Node->getSourceExpr())
DumpSubTree(Source);
- }
}
// GNU extensions.
@@ -589,15 +596,11 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
- ++IndentLevel;
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- OS << "\n";
- Indent();
- OS << "(cleanup ";
+ IndentScope Indent(*this);
+ OS << "cleanup ";
DumpDeclRef(Node->getObject(i));
- OS << ")";
}
- --IndentLevel;
}
void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
@@ -734,7 +737,6 @@ void Stmt::dump(SourceManager &SM) const {
void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
StmtDumper P(&SM, OS, 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- OS << "\n";
}
/// dump - This does a local dump of the specified AST fragment. It dumps the
@@ -743,19 +745,16 @@ void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
void Stmt::dump() const {
StmtDumper P(0, llvm::errs(), 4);
P.DumpSubTree(const_cast<Stmt*>(this));
- llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll(SourceManager &SM) const {
StmtDumper P(&SM, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
- llvm::errs() << "\n";
}
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
void Stmt::dumpAll() const {
StmtDumper P(0, llvm::errs(), ~0U);
P.DumpSubTree(const_cast<Stmt*>(this));
- llvm::errs() << "\n";
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index c0960ce6a244..57eb1a95181c 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -61,7 +61,7 @@ namespace {
void PrintRawCompoundStmt(CompoundStmt *S);
void PrintRawDecl(Decl *D);
- void PrintRawDeclStmt(DeclStmt *S);
+ void PrintRawDeclStmt(const DeclStmt *S);
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
void PrintCallArgs(CallExpr *E);
@@ -121,8 +121,8 @@ void StmtPrinter::PrintRawDecl(Decl *D) {
D->print(OS, Policy, IndentLevel);
}
-void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
- DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
+void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) {
+ DeclStmt::const_decl_iterator Begin = S->decl_begin(), End = S->decl_end();
SmallVector<Decl*, 2> Decls;
for ( ; Begin != End; ++Begin)
Decls.push_back(*Begin);
@@ -187,7 +187,10 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
OS << "if (";
- PrintExpr(If->getCond());
+ if (const DeclStmt *DS = If->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(If->getCond());
OS << ')';
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) {
@@ -224,7 +227,10 @@ void StmtPrinter::VisitIfStmt(IfStmt *If) {
void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
Indent() << "switch (";
- PrintExpr(Node->getCond());
+ if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(Node->getCond());
OS << ")";
// Pretty print compoundstmt bodies (very common).
@@ -240,7 +246,10 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
Indent() << "while (";
- PrintExpr(Node->getCond());
+ if (const DeclStmt *DS = Node->getConditionVariableDeclStmt())
+ PrintRawDeclStmt(DS);
+ else
+ PrintExpr(Node->getCond());
OS << ")\n";
PrintStmt(Node->getBody());
}
@@ -366,7 +375,7 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
}
-void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
+void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
Indent() << "asm ";
if (Node->isVolatile())
@@ -422,7 +431,7 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
if (i != 0)
OS << ", ";
- VisitStringLiteral(Node->getClobber(i));
+ VisitStringLiteral(Node->getClobberStringLiteral(i));
}
OS << ");\n";
@@ -734,10 +743,30 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
case BuiltinType::UInt128: OS << "Ui128"; break;
}
}
-void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+
+static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
+ bool PrintSuffix) {
SmallString<16> Str;
Node->getValue().toString(Str);
OS << Str;
+ if (Str.find_first_not_of("-0123456789") == StringRef::npos)
+ OS << '.'; // Trailing dot in order to separate from ints.
+
+ if (!PrintSuffix)
+ return;
+
+ // Emit suffixes. Float literals are always a builtin float type.
+ switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ default: llvm_unreachable("Unexpected type for float literal!");
+ case BuiltinType::Half: break; // FIXME: suffix?
+ case BuiltinType::Double: break; // no suffix.
+ case BuiltinType::Float: OS << 'F'; break;
+ case BuiltinType::LongDouble: OS << 'L'; break;
+ }
+}
+
+void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+ PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true);
}
void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) {
@@ -907,7 +936,7 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
- OS << "(" << Node->getType().getAsString(Policy) << ")";
+ OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")";
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
@@ -1110,6 +1139,8 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
PrintExpr(Node->getArg(0));
OS << ' ' << OpStrings[Kind];
}
+ } else if (Kind == OO_Arrow) {
+ PrintExpr(Node->getArg(0));
} else if (Kind == OO_Call) {
PrintExpr(Node->getArg(0));
OS << '(';
@@ -1217,7 +1248,12 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
OS << Int->getValue().toString(10, /*isSigned*/false);
break;
}
- case UserDefinedLiteral::LOK_Floating:
+ case UserDefinedLiteral::LOK_Floating: {
+ // Print floating literal without suffix.
+ FloatingLiteral *Float = cast<FloatingLiteral>(Node->getCookedLiteral());
+ PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false);
+ break;
+ }
case UserDefinedLiteral::LOK_String:
case UserDefinedLiteral::LOK_Character:
PrintExpr(Node->getCookedLiteral());
@@ -1379,10 +1415,12 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
OS << "::";
OS << "new ";
unsigned NumPlace = E->getNumPlacementArgs();
- if (NumPlace > 0) {
+ if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) {
OS << "(";
PrintExpr(E->getPlacementArg(0));
for (unsigned i = 1; i < NumPlace; ++i) {
+ if (isa<CXXDefaultArgExpr>(E->getPlacementArg(i)))
+ break;
OS << ", ";
PrintExpr(E->getPlacementArg(i));
}
@@ -1429,6 +1467,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
OS << '.';
if (E->getQualifier())
E->getQualifier()->print(OS, Policy);
+ OS << "~";
std::string TypeS;
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
@@ -1531,6 +1570,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsFunction: return "__is_function";
case UTT_IsFundamental: return "__is_fundamental";
case UTT_IsIntegral: return "__is_integral";
+ case UTT_IsInterfaceClass: return "__is_interface_class";
case UTT_IsLiteral: return "__is_literal";
case UTT_IsLvalueReference: return "__is_lvalue_reference";
case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
@@ -1647,6 +1687,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
Visit(Node->getReplacement());
}
+void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ OS << *E->getParameterPack();
+}
+
void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){
PrintExpr(Node->GetTemporaryExpr());
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 2168b64d5b23..bfd3132506ec 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -158,7 +158,7 @@ void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) {
VisitStmt(S);
}
-void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
+void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
VisitStmt(S);
ID.AddBoolean(S->isVolatile());
ID.AddBoolean(S->isSimple());
@@ -175,7 +175,7 @@ void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
}
ID.AddInteger(S->getNumClobbers());
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
- VisitStringLiteral(S->getClobber(I));
+ VisitStringLiteral(S->getClobberStringLiteral(I));
}
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
@@ -973,6 +973,14 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmExpr(
Visit(E->getReplacement());
}
+void StmtProfiler::VisitFunctionParmPackExpr(const FunctionParmPackExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getParameterPack());
+ ID.AddInteger(S->getNumExpansions());
+ for (FunctionParmPackExpr::iterator I = S->begin(), E = S->end(); I != E; ++I)
+ VisitDecl(*I);
+}
+
void StmtProfiler::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *S) {
VisitExpr(S);
@@ -1165,6 +1173,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitDecl(Arg.getAsDecl());
break;
+ case TemplateArgument::NullPtr:
+ VisitType(Arg.getNullPtrType());
+ break;
+
case TemplateArgument::Integral:
Arg.getAsIntegral().Profile(ID);
VisitType(Arg.getIntegralType());
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 95ff4edf1d6b..e9ee385457f8 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -77,7 +77,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
const TemplateArgument *Args,
unsigned NumArgs) {
if (NumArgs == 0)
- return TemplateArgument(0, 0);
+ return getEmptyPack();
TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs];
std::copy(Args, Args + NumArgs, Storage);
@@ -99,12 +99,11 @@ bool TemplateArgument::isDependent() const {
return true;
case Declaration:
- if (Decl *D = getAsDecl()) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
- return DC->isDependentContext();
- return D->getDeclContext()->isDependentContext();
- }
-
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case NullPtr:
return false;
case Integral:
@@ -141,11 +140,11 @@ bool TemplateArgument::isInstantiationDependent() const {
return true;
case Declaration:
- if (Decl *D = getAsDecl()) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D))
- return DC->isDependentContext();
- return D->getDeclContext()->isDependentContext();
- }
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case NullPtr:
return false;
case Integral:
@@ -174,6 +173,7 @@ bool TemplateArgument::isPackExpansion() const {
case Integral:
case Pack:
case Template:
+ case NullPtr:
return false;
case TemplateExpansion:
@@ -195,6 +195,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
case Declaration:
case Integral:
case TemplateExpansion:
+ case NullPtr:
break;
case Type:
@@ -286,12 +287,16 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
switch (getKind()) {
case Null:
case Type:
- case Declaration:
case Expression:
case Template:
case TemplateExpansion:
+ case NullPtr:
return TypeOrValue == Other.TypeOrValue;
+ case Declaration:
+ return getAsDecl() == Other.getAsDecl() &&
+ isDeclForReferenceParam() && Other.isDeclForReferenceParam();
+
case Integral:
return getIntegralType() == Other.getIntegralType() &&
getAsIntegral() == Other.getAsIntegral();
@@ -319,12 +324,13 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
case TemplateExpansion:
return TemplateArgument(getAsTemplateOrTemplatePattern());
-
+
case Declaration:
case Integral:
case Pack:
case Null:
case Template:
+ case NullPtr:
return TemplateArgument();
}
@@ -348,18 +354,20 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
}
case Declaration: {
- if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) {
- if (ND->getDeclName()) {
- Out << *ND;
- } else {
- Out << "<anonymous>";
- }
+ NamedDecl *ND = cast<NamedDecl>(getAsDecl());
+ if (ND->getDeclName()) {
+ // FIXME: distinguish between pointer and reference args?
+ Out << *ND;
} else {
- Out << "nullptr";
+ Out << "<anonymous>";
}
break;
}
-
+
+ case NullPtr:
+ Out << "nullptr";
+ break;
+
case Template:
getAsTemplate().print(Out, Policy);
break;
@@ -411,6 +419,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Declaration:
return getSourceDeclExpression()->getSourceRange();
+ case TemplateArgument::NullPtr:
+ return getSourceNullPtrExpression()->getSourceRange();
+
case TemplateArgument::Type:
if (TypeSourceInfo *TSI = getTypeSourceInfo())
return TSI->getTypeLoc().getSourceRange();
@@ -430,6 +441,8 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
case TemplateArgument::Integral:
+ return getSourceIntegralExpression()->getSourceRange();
+
case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
@@ -490,6 +503,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
getTemplateNameLoc());
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Template:
case TemplateArgument::Integral:
case TemplateArgument::Pack:
@@ -512,8 +526,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << Arg.getAsType();
case TemplateArgument::Declaration:
- if (Decl *D = Arg.getAsDecl())
- return DB << D;
+ return DB << Arg.getAsDecl();
+
+ case TemplateArgument::NullPtr:
return DB << "nullptr";
case TemplateArgument::Integral:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index abefae44b2ba..580ec50ca1f8 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -288,18 +288,17 @@ QualType QualType::IgnoreParens(QualType T) {
return T;
}
-/// \brief This will check for a TypedefType by removing any existing sugar
-/// until it reaches a TypedefType or a non-sugared type.
-template <> const TypedefType *Type::getAs() const {
- const Type *Cur = this;
-
+/// \brief This will check for a T (which should be a Type which can act as
+/// sugar, such as a TypedefType) by removing any existing sugar until it
+/// reaches a T or a non-sugared type.
+template<typename T> static const T *getAsSugar(const Type *Cur) {
while (true) {
- if (const TypedefType *TDT = dyn_cast<TypedefType>(Cur))
- return TDT;
+ if (const T *Sugar = dyn_cast<T>(Cur))
+ return Sugar;
switch (Cur->getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
- case Class: { \
+ case Type::Class: { \
const Class##Type *Ty = cast<Class##Type>(Cur); \
if (!Ty->isSugared()) return 0; \
Cur = Ty->desugar().getTypePtr(); \
@@ -310,6 +309,14 @@ template <> const TypedefType *Type::getAs() const {
}
}
+template <> const TypedefType *Type::getAs() const {
+ return getAsSugar<TypedefType>(this);
+}
+
+template <> const TemplateSpecializationType *Type::getAs() const {
+ return getAsSugar<TemplateSpecializationType>(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,9 +364,15 @@ bool Type::isStructureType() const {
return RT->getDecl()->isStruct();
return false;
}
+bool Type::isInterfaceType() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return RT->getDecl()->isInterface();
+ return false;
+}
bool Type::isStructureOrClassType() const {
if (const RecordType *RT = getAs<RecordType>())
- return RT->getDecl()->isStruct() || RT->getDecl()->isClass();
+ return RT->getDecl()->isStruct() || RT->getDecl()->isClass() ||
+ RT->getDecl()->isInterface();
return false;
}
bool Type::isVoidPointerType() const {
@@ -499,10 +512,18 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
return 0;
}
-const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
+const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
+ QualType PointeeType;
if (const PointerType *PT = getAs<PointerType>())
- if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(RT->getDecl());
+ PointeeType = PT->getPointeeType();
+ else if (const ReferenceType *RT = getAs<ReferenceType>())
+ PointeeType = RT->getPointeeType();
+ else
+ return 0;
+
+ if (const RecordType *RT = PointeeType->getAs<RecordType>())
+ return dyn_cast<CXXRecordDecl>(RT->getDecl());
+
return 0;
}
@@ -1205,8 +1226,6 @@ bool QualType::isCXX11PODType(ASTContext &Context) const {
return false;
case Qualifiers::OCL_None:
- if (ty->isObjCLifetimeType())
- return false;
break;
}
}
@@ -1317,6 +1336,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
case TST_typename: return ETK_Typename;
case TST_class: return ETK_Class;
case TST_struct: return ETK_Struct;
+ case TST_interface: return ETK_Interface;
case TST_union: return ETK_Union;
case TST_enum: return ETK_Enum;
}
@@ -1327,6 +1347,7 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
switch(TypeSpec) {
case TST_class: return TTK_Class;
case TST_struct: return TTK_Struct;
+ case TST_interface: return TTK_Interface;
case TST_union: return TTK_Union;
case TST_enum: return TTK_Enum;
}
@@ -1339,6 +1360,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
switch (Kind) {
case TTK_Class: return ETK_Class;
case TTK_Struct: return ETK_Struct;
+ case TTK_Interface: return ETK_Interface;
case TTK_Union: return ETK_Union;
case TTK_Enum: return ETK_Enum;
}
@@ -1350,6 +1372,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ETK_Class: return TTK_Class;
case ETK_Struct: return TTK_Struct;
+ case ETK_Interface: return TTK_Interface;
case ETK_Union: return TTK_Union;
case ETK_Enum: return TTK_Enum;
case ETK_None: // Fall through.
@@ -1367,6 +1390,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
return false;
case ETK_Class:
case ETK_Struct:
+ case ETK_Interface:
case ETK_Union:
case ETK_Enum:
return true;
@@ -1381,6 +1405,7 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
case ETK_Typename: return "typename";
case ETK_Class: return "class";
case ETK_Struct: return "struct";
+ case ETK_Interface: return "__interface";
case ETK_Union: return "union";
case ETK_Enum: return "enum";
}
@@ -1480,6 +1505,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>";
case ARCUnbridgedCast: return "<ARC unbridged cast type>";
+ case BuiltinFn: return "<builtin fn type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
@@ -1516,6 +1542,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86Pascal: return "pascal";
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
+ case CC_PnaclCall: return "pnaclcall";
}
llvm_unreachable("Invalid calling convention.");
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index c7bb7da4d17b..58c4cbd00c8a 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -98,23 +98,38 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
+ TypeLoc LeftMost = Cur;
while (true) {
switch (Cur.getTypeLocClass()) {
- // FIXME: Currently QualifiedTypeLoc does not have a source range
- // case Qualified:
case Elaborated:
- case DependentName:
- case DependentTemplateSpecialization:
+ LeftMost = Cur;
break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ LeftMost = Cur;
+ break;
+ }
+ /* Fall through */
+ case FunctionNoProto:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ // FIXME: Currently QualifiedTypeLoc does not have a source range
+ case Qualified:
+ Cur = Cur.getNextTypeLoc();
+ continue;
default:
- TypeLoc Next = Cur.getNextTypeLoc();
- if (Next.isNull()) break;
- Cur = Next;
+ if (!Cur.getLocalSourceRange().getBegin().isInvalid())
+ LeftMost = Cur;
+ Cur = Cur.getNextTypeLoc();
+ if (Cur.isNull())
+ break;
continue;
- }
+ } // switch
break;
- }
- return Cur.getLocalSourceRange().getBegin();
+ } // while
+ return LeftMost.getLocalSourceRange().getBegin();
}
SourceLocation TypeLoc::getEndLoc() const {
@@ -131,10 +146,15 @@ SourceLocation TypeLoc::getEndLoc() const {
case DependentSizedArray:
case IncompleteArray:
case VariableArray:
- case FunctionProto:
case FunctionNoProto:
Last = Cur;
break;
+ case FunctionProto:
+ if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ Last = TypeLoc();
+ else
+ Last = Cur;
+ break;
case Pointer:
case BlockPointer:
case MemberPointer:
@@ -241,6 +261,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
+ case BuiltinType::BuiltinFn:
return TST_unspecified;
}
@@ -300,7 +321,9 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
- case TemplateArgument::Pack:
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Impossible TemplateArgument");
+
case TemplateArgument::Expression:
ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
break;
@@ -310,7 +333,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
Context.getTrivialTypeSourceInfo(Args[i].getAsType(),
Loc));
break;
-
+
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
@@ -327,7 +350,11 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
? SourceLocation()
: Loc);
break;
- }
+ }
+
+ case TemplateArgument::Pack:
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
}
}
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index c42117c82bf5..90b2ca9cce15 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -141,9 +141,6 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
OS << "NULL TYPE";
return;
}
-
- if (Policy.SuppressSpecifiers && T->isSpecifierType())
- return;
SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
@@ -556,7 +553,8 @@ void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) {
void
FunctionProtoType::printExceptionSpecification(raw_ostream &OS,
- PrintingPolicy Policy) const {
+ const PrintingPolicy &Policy)
+ const {
if (hasDynamicExceptionSpec()) {
OS << " throw(";
@@ -646,6 +644,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_AAPCS_VFP:
OS << " __attribute__((pcs(\"aapcs-vfp\")))";
break;
+ case CC_PnaclCall:
+ OS << " __attribute__((pnaclcall))";
+ break;
}
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
@@ -798,6 +799,7 @@ void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
if (DC->isTranslationUnit()) return;
+ if (DC->isFunctionOrMethod()) return;
AppendScope(DC->getParent(), OS);
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
@@ -1165,6 +1167,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
}
+ case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
}
OS << "))";
}
@@ -1343,7 +1346,8 @@ PrintTemplateArgumentList(raw_ostream &OS,
void
FunctionProtoType::printExceptionSpecification(std::string &S,
- PrintingPolicy Policy) const {
+ const PrintingPolicy &Policy)
+ const {
if (hasDynamicExceptionSpec()) {
S += " throw(";
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 104530fc1305..33dad40c0c50 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -1891,6 +1891,9 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
if (MD->isPure())
Out << " [pure]";
+ if (MD->isDeleted())
+ Out << " [deleted]";
+
ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this function pointer has a return adjustment, dump it.
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 085049debdbe..8ecb26e8c19d 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -27,10 +27,75 @@ namespace ast_matchers {
namespace internal {
namespace {
+typedef MatchFinder::MatchCallback MatchCallback;
+
+/// \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 Maps from a node to its parent.
+ typedef llvm::DenseMap<const void*, ast_type_traits::DynTypedNode> ParentMap;
+
+ /// \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; }
+
+ template <typename T>
+ bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {
+ if (Node == NULL)
+ return true;
+ if (ParentStack.size() > 0)
+ (*Parents)[Node] = 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>;
+};
+
// We use memoization to avoid running the same matcher on the same
// AST node twice. This pair 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.
+//
+// We currently only memoize on nodes whose pointers identify the
+// nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc).
+// For \c QualType and \c TypeLoc it is possible to implement
+// 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;
// Used to store the result of a match and possibly bound nodes.
@@ -50,16 +115,16 @@ public:
// descendants of a traversed node. max_depth is the maximum depth
// to traverse: use 1 for matching the children and INT_MAX for
// matching the descendants.
- MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
+ MatchChildASTVisitor(const DynTypedMatcher *Matcher,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
int MaxDepth,
ASTMatchFinder::TraversalKind Traversal,
ASTMatchFinder::BindKind Bind)
- : BaseMatcher(BaseMatcher),
+ : Matcher(Matcher),
Finder(Finder),
Builder(Builder),
- CurrentDepth(-1),
+ CurrentDepth(0),
MaxDepth(MaxDepth),
Traversal(Traversal),
Bind(Bind),
@@ -76,10 +141,23 @@ public:
// Traverse*(c) for each child c of 'node'.
// - Traverse*(c) in turn calls Traverse(c), completing the
// recursion.
- template <typename T>
- bool findMatch(const T &Node) {
+ bool findMatch(const ast_type_traits::DynTypedNode &DynNode) {
reset();
- traverse(Node);
+ if (const Decl *D = DynNode.get<Decl>())
+ traverse(*D);
+ else if (const Stmt *S = DynNode.get<Stmt>())
+ traverse(*S);
+ else if (const NestedNameSpecifier *NNS =
+ DynNode.get<NestedNameSpecifier>())
+ traverse(*NNS);
+ else if (const NestedNameSpecifierLoc *NNSLoc =
+ DynNode.get<NestedNameSpecifierLoc>())
+ traverse(*NNSLoc);
+ else if (const QualType *Q = DynNode.get<QualType>())
+ traverse(*Q);
+ else if (const TypeLoc *T = DynNode.get<TypeLoc>())
+ traverse(*T);
+ // FIXME: Add other base types after adding tests.
return Matches;
}
@@ -87,9 +165,11 @@ public:
// They are public only to allow CRTP to work. They are *not *part
// of the public API of this class.
bool TraverseDecl(Decl *DeclNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
return (DeclNode == NULL) || traverse(*DeclNode);
}
bool TraverseStmt(Stmt *StmtNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
const Stmt *StmtToTraverse = StmtNode;
if (Traversal ==
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
@@ -100,9 +180,39 @@ public:
}
return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
}
+ // We assume that the QualType and the contained type are on the same
+ // hierarchy level. Thus, we try to match either of them.
bool TraverseType(QualType TypeNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ // Match the Type.
+ if (!match(*TypeNode))
+ return false;
+ // The QualType is matched inside traverse.
return traverse(TypeNode);
}
+ // We assume that the TypeLoc, contained QualType and contained Type all are
+ // on the same hierarchy level. Thus, we try to match all of them.
+ bool TraverseTypeLoc(TypeLoc TypeLocNode) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ // Match the Type.
+ if (!match(*TypeLocNode.getType()))
+ return false;
+ // Match the QualType.
+ if (!match(TypeLocNode.getType()))
+ return false;
+ // The TypeLoc is matched inside traverse.
+ return traverse(TypeLocNode);
+ }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ return (NNS == NULL) || traverse(*NNS);
+ }
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ if (!match(*NNS.getNestedNameSpecifier()))
+ return false;
+ return !NNS || traverse(NNS);
+ }
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
@@ -120,7 +230,7 @@ private:
// Resets the state of this object.
void reset() {
Matches = false;
- CurrentDepth = -1;
+ CurrentDepth = 0;
}
// Forwards the call to the corresponding Traverse*() method in the
@@ -134,49 +244,57 @@ private:
bool baseTraverse(QualType TypeNode) {
return VisitorBase::TraverseType(TypeNode);
}
+ bool baseTraverse(TypeLoc TypeLocNode) {
+ return VisitorBase::TraverseTypeLoc(TypeLocNode);
+ }
+ bool baseTraverse(const NestedNameSpecifier &NNS) {
+ return VisitorBase::TraverseNestedNameSpecifier(
+ const_cast<NestedNameSpecifier*>(&NNS));
+ }
+ bool baseTraverse(NestedNameSpecifierLoc NNS) {
+ return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
+ }
- // Traverses the subtree rooted at 'node'; returns true if the
- // traversal should continue after this function returns; also sets
- // matched_ to true if a match is found during the traversal.
+ // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
+ // 0 < CurrentDepth <= MaxDepth.
+ //
+ // Returns 'true' if traversal should continue after this function
+ // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
template <typename T>
- bool traverse(const T &Node) {
- TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
- traverse_can_only_be_instantiated_with_base_type);
- ScopedIncrement ScopedDepth(&CurrentDepth);
- if (CurrentDepth == 0) {
- // We don't want to match the root node, so just recurse.
- return baseTraverse(Node);
+ bool match(const T &Node) {
+ if (CurrentDepth == 0 || CurrentDepth > MaxDepth) {
+ return true;
}
if (Bind != ASTMatchFinder::BK_All) {
- if (BaseMatcher->matches(Node, Finder, Builder)) {
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
+ Finder, Builder)) {
Matches = true;
return false; // Abort as soon as a match is found.
}
- if (CurrentDepth < MaxDepth) {
- // The current node doesn't match, and we haven't reached the
- // maximum depth yet, so recurse.
- return baseTraverse(Node);
- }
- // The current node doesn't match, and we have reached the
- // maximum depth, so don't recurse (but continue the traversal
- // such that other nodes at the current level can be visited).
- return true;
} else {
BoundNodesTreeBuilder RecursiveBuilder;
- if (BaseMatcher->matches(Node, Finder, &RecursiveBuilder)) {
+ if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node),
+ Finder, &RecursiveBuilder)) {
// After the first match the matcher succeeds.
Matches = true;
Builder->addMatch(RecursiveBuilder.build());
}
- if (CurrentDepth < MaxDepth) {
- baseTraverse(Node);
- }
- // In kBindAll mode we always search for more matches.
- return true;
}
+ return true;
}
- const UntypedBaseMatcher *const BaseMatcher;
+ // Traverses the subtree rooted at 'Node'; returns true if the
+ // traversal should continue after this function returns.
+ template <typename T>
+ bool traverse(const T &Node) {
+ TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
+ traverse_can_only_be_instantiated_with_base_type);
+ if (!match(Node))
+ return false;
+ return baseTraverse(Node);
+ }
+
+ const DynTypedMatcher *const Matcher;
ASTMatchFinder *const Finder;
BoundNodesTreeBuilder *const Builder;
int CurrentDepth;
@@ -191,12 +309,21 @@ private:
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
- MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers)
- : Triggers(Triggers),
+ MatchASTVisitor(std::vector<std::pair<const 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();
+ I != E; ++I) {
+ I->second->onStartOfTranslationUnit();
+ }
+ }
+
void set_active_ast_context(ASTContext *NewActiveASTContext) {
ActiveASTContext = NewActiveASTContext;
}
@@ -207,7 +334,7 @@ public:
bool VisitTypedefDecl(TypedefDecl *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
+ // isDerivedFrom(x) properly, where x can be the name of the base
// class or any of its aliases.
//
// In general, the is-alias-of (as defined by typedefs) relation
@@ -228,7 +355,7 @@ public:
// `- E
//
// It is wrong to assume that the relation is a chain. A correct
- // implementation of IsDerivedFrom() needs to recognize that B and
+ // implementation of isDerivedFrom() needs to recognize that B and
// E are aliases, even though neither is a typedef of the other.
// Therefore, we cannot simply walk through one typedef chain to
// find out whether the type name matches.
@@ -243,23 +370,27 @@ public:
bool TraverseStmt(Stmt *StmtNode);
bool TraverseType(QualType TypeNode);
bool TraverseTypeLoc(TypeLoc TypeNode);
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool memoizedMatchesRecursively(const T &Node,
- const UntypedBaseMatcher &BaseMatcher,
+ bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
- TOOLING_COMPILE_ASSERT((llvm::is_same<T, Decl>::value) ||
- (llvm::is_same<T, Stmt>::value),
- type_does_not_support_memoization);
- const UntypedMatchInput input(BaseMatcher.getID(), &Node);
+ const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
+
+ // For AST-nodes that don't have an identity, we can't memoize.
+ if (!input.second)
+ 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, BaseMatcher, &DescendantBoundNodesBuilder,
+ matchesRecursively(Node, Matcher, &DescendantBoundNodesBuilder,
MaxDepth, Traversal, Bind);
InsertResult.first->second.Nodes =
DescendantBoundNodesBuilder.build();
@@ -269,12 +400,12 @@ public:
}
// Matches children or descendants of 'Node' with 'BaseMatcher'.
- template <typename T>
- bool matchesRecursively(const T &Node, const UntypedBaseMatcher &BaseMatcher,
+ bool matchesRecursively(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
TraversalKind Traversal, BindKind Bind) {
MatchChildASTVisitor Visitor(
- &BaseMatcher, this, Builder, MaxDepth, Traversal, Bind);
+ &Matcher, this, Builder, MaxDepth, Traversal, Bind);
return Visitor.findMatch(Node);
}
@@ -282,38 +413,54 @@ public:
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder);
- // Implements ASTMatchFinder::MatchesChildOf.
- virtual bool matchesChildOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
+ // Implements ASTMatchFinder::matchesChildOf.
+ virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
TraversalKind Traversal,
BindKind Bind) {
- return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal,
+ return matchesRecursively(Node, Matcher, Builder, 1, Traversal,
Bind);
}
- virtual bool matchesChildOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- TraversalKind Traversal,
- BindKind Bind) {
- return matchesRecursively(StmtNode, BaseMatcher, Builder, 1, Traversal,
- Bind);
- }
-
- // Implements ASTMatchFinder::MatchesDescendantOf.
- virtual bool matchesDescendantOf(const Decl &DeclNode,
- const UntypedBaseMatcher &BaseMatcher,
+ // Implements ASTMatchFinder::matchesDescendantOf.
+ virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
BindKind Bind) {
- return memoizedMatchesRecursively(DeclNode, BaseMatcher, Builder, INT_MAX,
+ return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
TK_AsIs, Bind);
}
- virtual bool matchesDescendantOf(const Stmt &StmtNode,
- const UntypedBaseMatcher &BaseMatcher,
- BoundNodesTreeBuilder *Builder,
- BindKind Bind) {
- return memoizedMatchesRecursively(StmtNode, BaseMatcher, Builder, INT_MAX,
- TK_AsIs, Bind);
+ // Implements ASTMatchFinder::matchesAncestorOf.
+ virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) {
+ if (!Parents) {
+ // We always need to run over the whole translation unit, as
+ // \c hasAncestor can escape any subtree.
+ Parents.reset(ParentMapASTVisitor::buildMap(
+ *ActiveASTContext->getTranslationUnitDecl()));
+ }
+ ast_type_traits::DynTypedNode Ancestor = Node;
+ while (Ancestor.get<TranslationUnitDecl>() !=
+ ActiveASTContext->getTranslationUnitDecl()) {
+ assert(Ancestor.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ ParentMapASTVisitor::ParentMap::const_iterator I =
+ Parents->find(Ancestor.getMemoizationData());
+ if (I == Parents->end()) {
+ assert(false &&
+ "Found node that is not in the parent map.");
+ return false;
+ }
+ Ancestor = I->second;
+ if (Matcher.matches(Ancestor, this, Builder))
+ return true;
+ if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
+ return false;
+ }
+ return false;
}
bool shouldVisitTemplateInstantiations() const { return true; }
@@ -358,21 +505,22 @@ private:
// result callback for every node that matches.
template <typename T>
void match(const T &node) {
- for (std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers->begin(), End = Triggers->end();
- It != End; ++It) {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
BoundNodesTreeBuilder Builder;
- if (It->first->matches(node, this, &Builder)) {
+ if (I->first->matches(ast_type_traits::DynTypedNode::create(node),
+ this, &Builder)) {
BoundNodesTree BoundNodes = Builder.build();
- MatchVisitor Visitor(ActiveASTContext, It->second);
+ MatchVisitor Visitor(ActiveASTContext, I->second);
BoundNodes.visitMatches(&Visitor);
}
}
}
- std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *const Triggers;
+ std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> > *const MatcherCallbackPairs;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
@@ -381,16 +529,16 @@ private:
// Maps (matcher, node) -> the match result for memoization.
typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
MemoizationMap ResultCache;
+
+ llvm::OwningPtr<ParentMapASTVisitor::ParentMap> Parents;
};
// Returns true if the given class is directly or indirectly derived
-// from a base type with the given name. A class is considered to be
-// also derived from itself.
+// from a base type with the given name. A class is not considered to be
+// derived from itself.
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder) {
- if (Base.matches(*Declaration, this, Builder))
- return true;
if (!Declaration->hasDefinition())
return false;
typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
@@ -403,6 +551,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
// 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.
@@ -439,6 +588,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
}
assert(ClassDecl != NULL);
assert(ClassDecl != Declaration);
+ if (Base.matches(*ClassDecl, this, Builder))
+ return true;
if (classIsDerivedFrom(ClassDecl, Base, Builder))
return true;
}
@@ -466,19 +617,40 @@ bool MatchASTVisitor::TraverseType(QualType TypeNode) {
return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
}
-bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) {
- match(TypeLoc.getType());
- return RecursiveASTVisitor<MatchASTVisitor>::
- TraverseTypeLoc(TypeLoc);
+bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) {
+ // The RecursiveASTVisitor only visits types if they're not within TypeLocs.
+ // We still want to find those types via matchers, so we match them here. Note
+ // that the TypeLocs are structurally a shadow-hierarchy to the expressed
+ // type, so we visit all involved parts of a compound type when matching on
+ // each TypeLoc.
+ match(TypeLocNode);
+ match(TypeLocNode.getType());
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode);
+}
+
+bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ match(*NNS);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
+}
+
+bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
+ NestedNameSpecifierLoc NNS) {
+ match(NNS);
+ // We only match the nested name specifier here (as opposed to traversing it)
+ // because the traversal is already done in the parallel "Loc"-hierarchy.
+ match(*NNS.getNestedNameSpecifier());
+ return
+ RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
}
class MatchASTConsumer : public ASTConsumer {
public:
- MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> > *Triggers,
- MatchFinder::ParsingDoneTestCallback *ParsingDone)
- : Visitor(Triggers),
- ParsingDone(ParsingDone) {}
+ MatchASTConsumer(
+ std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> > *MatcherCallbackPairs,
+ MatchFinder::ParsingDoneTestCallback *ParsingDone)
+ : Visitor(MatcherCallbackPairs),
+ ParsingDone(ParsingDone) {}
private:
virtual void HandleTranslationUnit(ASTContext &Context) {
@@ -486,6 +658,7 @@ private:
ParsingDone->run();
}
Visitor.set_active_ast_context(&Context);
+ Visitor.onStartOfTranslationUnit();
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
Visitor.set_active_ast_context(NULL);
}
@@ -508,9 +681,9 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
MatchFinder::MatchFinder() : ParsingDone(NULL) {}
MatchFinder::~MatchFinder() {
- for (std::vector< std::pair<const internal::UntypedBaseMatcher*,
- MatchFinder::MatchCallback*> >::const_iterator
- It = Triggers.begin(), End = Triggers.end();
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end();
It != End; ++It) {
delete It->first;
}
@@ -518,24 +691,54 @@ MatchFinder::~MatchFinder() {
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<Decl>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<Decl>(NodeMatch), Action));
}
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<QualType>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<QualType>(NodeMatch), Action));
}
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- Triggers.push_back(std::make_pair(
- new internal::TypedBaseMatcher<Stmt>(NodeMatch), Action));
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new internal::Matcher<Stmt>(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new NestedNameSpecifierMatcher(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new NestedNameSpecifierLocMatcher(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ MatcherCallbackPairs.push_back(std::make_pair(
+ new TypeLocMatcher(NodeMatch), Action));
}
ASTConsumer *MatchFinder::newASTConsumer() {
- return new internal::MatchASTConsumer(&Triggers, ParsingDone);
+ return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
+}
+
+void MatchFinder::findAll(const Decl &Node, ASTContext &Context) {
+ internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ Visitor.set_active_ast_context(&Context);
+ Visitor.TraverseDecl(const_cast<Decl*>(&Node));
+}
+
+void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
+ internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
+ Visitor.set_active_ast_context(&Context);
+ Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
}
void MatchFinder::registerTestCallbackAfterParsing(
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 69c51905fe8f..408195d36902 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -18,18 +18,29 @@ 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 BoundNodesMap::copyTo(BoundNodesMap *Other) const {
+ copy(NodeMap.begin(), NodeMap.end(),
+ inserter(Other->NodeMap, Other->NodeMap.begin()));
+}
+
BoundNodesTree::BoundNodesTree() {}
BoundNodesTree::BoundNodesTree(
- const std::map<std::string, const Decl*>& DeclBindings,
- const std::map<std::string, const Stmt*>& StmtBindings,
+ const BoundNodesMap& Bindings,
const std::vector<BoundNodesTree> RecursiveBindings)
- : DeclBindings(DeclBindings), StmtBindings(StmtBindings),
+ : Bindings(Bindings),
RecursiveBindings(RecursiveBindings) {}
void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
- copyBindingsTo(DeclBindings, Builder);
- copyBindingsTo(StmtBindings, Builder);
+ Bindings.copyTo(Builder);
for (std::vector<BoundNodesTree>::const_iterator
I = RecursiveBindings.begin(),
E = RecursiveBindings.end();
@@ -38,63 +49,34 @@ void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
}
}
-template <typename T>
-void BoundNodesTree::copyBindingsTo(
- const T& Bindings, BoundNodesTreeBuilder* Builder) const {
- for (typename T::const_iterator I = Bindings.begin(),
- E = Bindings.end();
- I != E; ++I) {
- Builder->setBinding(I->first, I->second);
- }
-}
-
void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
- std::map<std::string, const Decl*> AggregatedDeclBindings;
- std::map<std::string, const Stmt*> AggregatedStmtBindings;
- visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings,
- AggregatedStmtBindings);
+ BoundNodesMap AggregatedBindings;
+ visitMatchesRecursively(ResultVisitor, AggregatedBindings);
}
void BoundNodesTree::
visitMatchesRecursively(Visitor* ResultVisitor,
- std::map<std::string, const Decl*>
- AggregatedDeclBindings,
- std::map<std::string, const Stmt*>
- AggregatedStmtBindings) {
- copy(DeclBindings.begin(), DeclBindings.end(),
- inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin()));
- copy(StmtBindings.begin(), StmtBindings.end(),
- inserter(AggregatedStmtBindings, AggregatedStmtBindings.begin()));
+ const BoundNodesMap& AggregatedBindings) {
+ BoundNodesMap CombinedBindings(AggregatedBindings);
+ Bindings.copyTo(&CombinedBindings);
if (RecursiveBindings.empty()) {
- ResultVisitor->visitMatch(BoundNodes(AggregatedDeclBindings,
- AggregatedStmtBindings));
+ ResultVisitor->visitMatch(BoundNodes(CombinedBindings));
} else {
for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
- AggregatedDeclBindings,
- AggregatedStmtBindings);
+ CombinedBindings);
}
}
}
BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
-void BoundNodesTreeBuilder::setBinding(const std::string &Id,
- const Decl *Node) {
- DeclBindings[Id] = Node;
-}
-
-void BoundNodesTreeBuilder::setBinding(const std::string &Id,
- const Stmt *Node) {
- StmtBindings[Id] = Node;
-}
-
void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
RecursiveBindings.push_back(Bindings);
}
BoundNodesTree BoundNodesTreeBuilder::build() const {
- return BoundNodesTree(DeclBindings, StmtBindings, RecursiveBindings);
+ return BoundNodesTree(Bindings, RecursiveBindings);
}
} // end namespace internal
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 7de7f395e8a7..e7df0a813b37 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -29,13 +29,15 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
+#include "BodyFarm.h"
+
using namespace clang;
typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap;
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d,
- const CFG::BuildOptions &buildOptions)
+ const Decl *d,
+ const CFG::BuildOptions &buildOptions)
: Manager(Mgr),
D(d),
cfgBuildOptions(buildOptions),
@@ -49,7 +51,7 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d)
+ const Decl *d)
: Manager(Mgr),
D(d),
forcedBlkExprs(0),
@@ -62,11 +64,16 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool addInitializers) {
+ bool addImplicitDtors,
+ bool addInitializers,
+ bool addTemporaryDtors,
+ bool synthesizeBodies)
+ : SynthesizeBodies(synthesizeBodies)
+{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
+ cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
}
void AnalysisDeclContextManager::clear() {
@@ -75,9 +82,18 @@ void AnalysisDeclContextManager::clear() {
Contexts.clear();
}
+static BodyFarm &getBodyFarm(ASTContext &C) {
+ static BodyFarm *BF = new BodyFarm(C);
+ return *BF;
+}
+
Stmt *AnalysisDeclContext::getBody() const {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->getBody();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Stmt *Body = FD->getBody();
+ if (!Body && Manager && Manager->synthesizeBodies())
+ return getBodyFarm(getASTContext()).getBody(FD);
+ return Body;
+ }
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
@@ -201,6 +217,13 @@ PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() {
}
AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
+ // that has the body.
+ FD->hasBody(FD);
+ D = FD;
+ }
+
AnalysisDeclContext *&AC = Contexts[D];
if (!AC)
AC = new AnalysisDeclContext(this, D, cfgBuildOptions);
@@ -332,6 +355,10 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const {
return NULL;
}
+bool LocationContext::inTopFrame() const {
+ return getCurrentStackFrame()->inTopFrame();
+}
+
bool LocationContext::isParentOf(const LocationContext *LC) const {
do {
const LocationContext *Parent = LC->getParent();
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
new file mode 100644
index 000000000000..794ff9cc2bb1
--- /dev/null
+++ b/lib/Analysis/BodyFarm.cpp
@@ -0,0 +1,374 @@
+//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprObjC.h"
+#include "BodyFarm.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Helper creation functions for constructing faux ASTs.
+//===----------------------------------------------------------------------===//
+
+static bool isDispatchBlock(QualType Ty) {
+ // Is it a block pointer?
+ const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
+ if (!BPT)
+ return false;
+
+ // Check if the block pointer type takes no arguments and
+ // returns void.
+ const FunctionProtoType *FT =
+ BPT->getPointeeType()->getAs<FunctionProtoType>();
+ if (!FT || !FT->getResultType()->isVoidType() ||
+ FT->getNumArgs() != 0)
+ return false;
+
+ return true;
+}
+
+namespace {
+class ASTMaker {
+public:
+ ASTMaker(ASTContext &C) : C(C) {}
+
+ /// Create a new BinaryOperator representing a simple assignment.
+ BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
+
+ /// Create a new BinaryOperator representing a comparison.
+ BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op);
+
+ /// Create a new compound stmt using the provided statements.
+ CompoundStmt *makeCompound(ArrayRef<Stmt*>);
+
+ /// Create a new DeclRefExpr for the referenced variable.
+ DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
+
+ /// Create a new UnaryOperator representing a dereference.
+ UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast for an integer conversion.
+ Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast to a builtin boolean type.
+ ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
+
+ // Create an implicit cast for lvalue-to-rvaluate conversions.
+ ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
+
+ /// Create an Objective-C bool literal.
+ ObjCBoolLiteralExpr *makeObjCBool(bool Val);
+
+ /// Create a Return statement.
+ ReturnStmt *makeReturn(const Expr *RetVal);
+
+private:
+ ASTContext &C;
+};
+}
+
+BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
+ QualType Ty) {
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
+ BO_Assign, Ty, VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op) {
+ assert(BinaryOperator::isLogicalOp(Op) ||
+ BinaryOperator::isComparisonOp(Op));
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS),
+ const_cast<Expr*>(RHS),
+ Op,
+ C.getLogicalOperationType(),
+ VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
+ return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
+ Stmts.size(),
+ SourceLocation(), SourceLocation());
+}
+
+DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
+ DeclRefExpr *DR =
+ DeclRefExpr::Create(/* Ctx = */ C,
+ /* QualifierLoc = */ NestedNameSpecifierLoc(),
+ /* TemplateKWLoc = */ SourceLocation(),
+ /* D = */ const_cast<VarDecl*>(D),
+ /* isEnclosingLocal = */ false,
+ /* NameLoc = */ SourceLocation(),
+ /* T = */ D->getType(),
+ /* VK = */ VK_LValue);
+ return DR;
+}
+
+UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
+ return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
+ VK_LValue, OK_Ordinary, SourceLocation());
+}
+
+ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
+ return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
+ if (Arg->getType() == Ty)
+ return const_cast<Expr*>(Arg);
+
+ return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
+ return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
+ QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
+ return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
+}
+
+ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
+ return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Creation functions for faux ASTs.
+//===----------------------------------------------------------------------===//
+
+typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
+
+/// Create a fake body for dispatch_once.
+static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the first parameter is a pointer to integer type.
+ const ParmVarDecl *Predicate = D->getParamDecl(0);
+ QualType PredicateQPtrTy = Predicate->getType();
+ const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
+ if (!PredicatePtrTy)
+ return 0;
+ QualType PredicateTy = PredicatePtrTy->getPointeeType();
+ if (!PredicateTy->isIntegerType())
+ return 0;
+
+ // Check if the second parameter is the proper block type.
+ const ParmVarDecl *Block = D->getParamDecl(1);
+ QualType Ty = Block->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fakse body that checks the predicate,
+ // sets it, and calls the block. Basically, an AST dump of:
+ //
+ // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
+ // if (!*predicate) {
+ // *predicate = 1;
+ // block();
+ // }
+ // }
+
+ ASTMaker M(C);
+
+ // (1) Create the call.
+ DeclRefExpr *DR = M.makeDeclRefExpr(Block);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+
+ // (2) Create the assignment to the predicate.
+ IntegerLiteral *IL =
+ IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
+ C.IntTy, SourceLocation());
+ BinaryOperator *B =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
+ PredicateTy),
+ M.makeIntegralCast(IL, PredicateTy),
+ PredicateTy);
+
+ // (3) Create the compound statement.
+ Stmt *Stmts[2];
+ Stmts[0] = B;
+ Stmts[1] = CE;
+ CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // (4) Create the 'if' condition.
+ ImplicitCastExpr *LValToRval =
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate),
+ PredicateQPtrTy),
+ PredicateTy),
+ PredicateTy);
+
+ UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+
+ // (5) Create the 'if' statement.
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ return If;
+}
+
+/// Create a fake body for dispatch_sync.
+static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the second parameter is a block.
+ const ParmVarDecl *PV = D->getParamDecl(1);
+ QualType Ty = PV->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fake body that just calls the block.
+ // This is basically just an AST dump of:
+ //
+ // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
+ // block();
+ // }
+ //
+ ASTMaker M(C);
+ DeclRefExpr *DR = M.makeDeclRefExpr(PV);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+ return CE;
+}
+
+static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
+{
+ // There are exactly 3 arguments.
+ if (D->param_size() != 3)
+ return 0;
+
+ // Body for:
+ // if (oldValue == *theValue) {
+ // *theValue = newValue;
+ // return YES;
+ // }
+ // else return NO;
+
+ QualType ResultTy = D->getResultType();
+ bool isBoolean = ResultTy->isBooleanType();
+ if (!isBoolean && !ResultTy->isIntegralType(C))
+ return 0;
+
+ const ParmVarDecl *OldValue = D->getParamDecl(0);
+ QualType OldValueTy = OldValue->getType();
+
+ const ParmVarDecl *NewValue = D->getParamDecl(1);
+ QualType NewValueTy = NewValue->getType();
+
+ assert(OldValueTy == NewValueTy);
+
+ const ParmVarDecl *TheValue = D->getParamDecl(2);
+ QualType TheValueTy = TheValue->getType();
+ const PointerType *PT = TheValueTy->getAs<PointerType>();
+ if (!PT)
+ return 0;
+ QualType PointeeTy = PT->getPointeeType();
+
+ ASTMaker M(C);
+ // Construct the comparison.
+ Expr *Comparison =
+ M.makeComparison(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ PointeeTy),
+ BO_EQ);
+
+ // Construct the body of the IfStmt.
+ Stmt *Stmts[2];
+ Stmts[0] =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
+ NewValueTy);
+
+ Expr *BoolVal = M.makeObjCBool(true);
+ Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmts[1] = M.makeReturn(RetVal);
+ CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // Construct the else clause.
+ BoolVal = M.makeObjCBool(false);
+ RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmt *Else = M.makeReturn(RetVal);
+
+ /// Construct the If.
+ Stmt *If =
+ new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+ SourceLocation(), Else);
+
+ return If;
+}
+
+Stmt *BodyFarm::getBody(const FunctionDecl *D) {
+ D = D->getCanonicalDecl();
+
+ llvm::Optional<Stmt *> &Val = Bodies[D];
+ if (Val.hasValue())
+ return Val.getValue();
+
+ Val = 0;
+
+ if (D->getIdentifier() == 0)
+ return 0;
+
+ StringRef Name = D->getName();
+ if (Name.empty())
+ return 0;
+
+ FunctionFarmer FF;
+
+ if (Name.startswith("OSAtomicCompareAndSwap") ||
+ Name.startswith("objc_atomicCompareAndSwap")) {
+ FF = create_OSAtomicCompareAndSwap;
+ }
+ else {
+ FF = llvm::StringSwitch<FunctionFarmer>(Name)
+ .Case("dispatch_sync", create_dispatch_sync)
+ .Case("dispatch_once", create_dispatch_once)
+ .Default(NULL);
+ }
+
+ if (FF) { Val = FF(C, D); }
+ return Val.getValue();
+}
+
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
new file mode 100644
index 000000000000..d503cc1bcd07
--- /dev/null
+++ b/lib/Analysis/BodyFarm.h
@@ -0,0 +1,43 @@
+//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
+#define LLVM_CLANG_ANALYSIS_BODYFARM_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class FunctionDecl;
+class Stmt;
+
+class BodyFarm {
+public:
+ BodyFarm(ASTContext &C) : C(C) {}
+
+ /// Factory method for creating bodies for ordinary functions.
+ Stmt *getBody(const FunctionDecl *D);
+
+private:
+ typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap;
+
+ ASTContext &C;
+ BodyMap Bodies;
+};
+}
+
+#endif
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 05c53850f568..315e54380b2f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -467,6 +467,30 @@ private:
CachedBoolEvals[S] = Result; // update or insert
return Result;
}
+ else {
+ switch (Bop->getOpcode()) {
+ default: break;
+ // For 'x & 0' and 'x * 0', we can determine that
+ // the value is always false.
+ case BO_Mul:
+ case BO_And: {
+ // If either operand is zero, we know the value
+ // must be false.
+ llvm::APSInt IntVal;
+ if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ }
+ break;
+ }
+ }
}
return evaluateAsBooleanConditionNoCache(S);
@@ -682,7 +706,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
IsReference = FD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1022,6 +1046,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ExprWithCleanupsClass:
return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc);
+ case Stmt::CXXDefaultArgExprClass:
+ // FIXME: The expression inside a CXXDefaultArgExpr is owned by the
+ // called function's declaration, not by the caller. If we simply add
+ // this expression to the CFG, we could end up with the same Expr
+ // appearing multiple times.
+ // PR13385 / <rdar://problem/12156507>
+ return VisitStmt(S, asc);
+
case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
@@ -1585,7 +1617,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
IsReference = VD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1616,8 +1648,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If the type of VD is a VLA, then we must process its size expressions.
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
+ VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) {
+ if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
+ LastBlock = newBlock;
+ }
// Remove variable from local scope.
if (ScopePos && VD == *ScopePos)
@@ -1735,7 +1769,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
- Block = addStmt(I->getCond());
+ CFGBlock *LastBlock = addStmt(I->getCond());
// Finally, if the IfStmt contains a condition variable, add both the IfStmt
// and the condition variable initialization to the CFG.
@@ -1743,11 +1777,11 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, I->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
@@ -2254,7 +2288,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
}
// The default case when not handling logical operators.
- EntryConditionBlock = ExitConditionBlock = createBlock(false);
+ ExitConditionBlock = createBlock(false);
ExitConditionBlock->setTerminator(W);
// Now add the actual condition to the condition block.
@@ -2579,7 +2613,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
Block = SwitchTerminatedBlock;
- Block = addStmt(Terminator->getCond());
+ CFGBlock *LastBlock = addStmt(Terminator->getCond());
// Finally, if the SwitchStmt contains a condition variable, add both the
// SwitchStmt and the condition variable initialization to the CFG.
@@ -2587,11 +2621,11 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, Terminator->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
static bool shouldAddCase(bool &switchExclusivelyCovered,
@@ -2775,8 +2809,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
Block = NULL;
- Block = addStmt(Terminator->getTryBlock());
- return Block;
+ return addStmt(Terminator->getTryBlock());
}
CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
@@ -2917,15 +2950,15 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
addLocalScopeAndDtors(S->getLoopVarStmt());
// Populate a new block to contain the loop body and loop variable.
- Block = addStmt(S->getBody());
+ addStmt(S->getBody());
if (badCFG)
return 0;
- Block = addStmt(S->getLoopVarStmt());
+ CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
if (badCFG)
return 0;
// This new body block is a successor to our condition block.
- addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
+ addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock);
}
// Link up the condition block with the code that follows the loop (the
@@ -2940,7 +2973,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) {
- if (BuildOpts.AddImplicitDtors) {
+ if (BuildOpts.AddTemporaryDtors) {
// If adding implicit destructors visit the full expression for adding
// destructors of temporaries.
VisitForTemporaryDtors(E->getSubExpr());
@@ -3020,6 +3053,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
}
CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
+ assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
+
tryAgain:
if (!E) {
badCFG = true;
@@ -3449,12 +3484,12 @@ class StmtPrinterHelper : public PrinterHelper {
StmtMapTy StmtMap;
DeclMapTy DeclMap;
signed currentBlock;
- unsigned currentStmt;
+ unsigned currStmt;
const LangOptions &LangOpts;
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : currentBlock(0), currentStmt(0), LangOpts(LO)
+ : currentBlock(0), currStmt(0), LangOpts(LO)
{
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
@@ -3515,7 +3550,7 @@ public:
const LangOptions &getLangOpts() const { return LangOpts; }
void setBlockID(signed i) { currentBlock = i; }
- void setStmtID(unsigned i) { currentStmt = i; }
+ void setStmtID(unsigned i) { currStmt = i; }
virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
StmtMapTy::iterator I = StmtMap.find(S);
@@ -3524,7 +3559,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3539,7 +3574,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3831,8 +3866,8 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
if (Helper) Helper->setBlockID(-1);
- CFGBlockTerminatorPrint TPrinter(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
+ PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions());
+ CFGBlockTerminatorPrint TPrinter(OS, Helper, PP);
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
OS << '\n';
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index d57e4813ca02..ca166669fc89 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,13 +1,15 @@
add_clang_library(clangAnalysis
AnalysisDeclContext.cpp
- CallGraph.cpp
+ BodyFarm.cpp
CFG.cpp
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
+ CallGraph.cpp
CocoaConventions.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
+ ObjCNoReturn.cpp
PostOrderCFGView.cpp
PrintfFormatString.cpp
ProgramPoint.cpp
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index e7ea48688dae..73063b5132c8 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -14,6 +14,7 @@
#include "FormatStringParsing.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -489,9 +490,12 @@ analyze_format_string::LengthModifier::toString() const {
const char *ConversionSpecifier::toString() const {
switch (kind) {
case dArg: return "d";
+ case DArg: return "D";
case iArg: return "i";
case oArg: return "o";
+ case OArg: return "O";
case uArg: return "u";
+ case UArg: return "U";
case xArg: return "x";
case XArg: return "X";
case fArg: return "f";
@@ -523,6 +527,29 @@ const char *ConversionSpecifier::toString() const {
return NULL;
}
+llvm::Optional<ConversionSpecifier>
+ConversionSpecifier::getStandardSpecifier() const {
+ ConversionSpecifier::Kind NewKind;
+
+ switch (getKind()) {
+ default:
+ return llvm::Optional<ConversionSpecifier>();
+ case DArg:
+ NewKind = dArg;
+ break;
+ case UArg:
+ NewKind = uArg;
+ break;
+ case OArg:
+ NewKind = oArg;
+ break;
+ }
+
+ ConversionSpecifier FixedCS(*this);
+ FixedCS.setKind(NewKind);
+ return FixedCS;
+}
+
//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -548,7 +575,7 @@ void OptionalAmount::toString(raw_ostream &os) const {
}
}
-bool FormatSpecifier::hasValidLengthModifier() const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
@@ -563,9 +590,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsPtrDiff:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::nArg:
@@ -578,9 +608,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsLong:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -611,14 +644,15 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
return true;
- // GNU extension.
+ // GNU libc extension.
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::uArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
- return true;
+ return !Target.getTriple().isOSDarwin() &&
+ !Target.getTriple().isOSWindows();
default:
return false;
}
@@ -697,6 +731,9 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt)
return LangOpt.ObjC1 || LangOpt.ObjC2;
case ConversionSpecifier::InvalidSpecifier:
case ConversionSpecifier::PrintErrno:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::OArg:
+ case ConversionSpecifier::UArg:
return false;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
@@ -719,6 +756,20 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
+llvm::Optional<LengthModifier>
+FormatSpecifier::getCorrectedLengthModifier() const {
+ if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
+ if (LM.getKind() == LengthModifier::AsLongDouble ||
+ LM.getKind() == LengthModifier::AsQuad) {
+ LengthModifier FixedLM(LM);
+ FixedLM.setKind(LengthModifier::AsLongLong);
+ return FixedLM;
+ }
+ }
+
+ return llvm::Optional<LengthModifier>();
+}
+
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
assert(isa<TypedefType>(QT) && "Expected a TypedefType");
diff --git a/lib/Analysis/ObjCNoReturn.cpp b/lib/Analysis/ObjCNoReturn.cpp
new file mode 100644
index 000000000000..52d844bf9dd8
--- /dev/null
+++ b/lib/Analysis/ObjCNoReturn.cpp
@@ -0,0 +1,67 @@
+//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- 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 special handling of recognizing ObjC API hooks that
+// do not return but aren't marked as such in API headers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+
+using namespace clang;
+
+static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
+ if (!Class)
+ return false;
+ if (Class->getIdentifier() == II)
+ return true;
+ return isSubclass(Class->getSuperClass(), II);
+}
+
+ObjCNoReturn::ObjCNoReturn(ASTContext &C)
+ : RaiseSel(GetNullarySelector("raise", C)),
+ NSExceptionII(&C.Idents.get("NSException"))
+{
+ // Generate selectors.
+ SmallVector<IdentifierInfo*, 3> II;
+
+ // raise:format:
+ II.push_back(&C.Idents.get("raise"));
+ II.push_back(&C.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[0] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+
+ // raise:format:arguments:
+ II.push_back(&C.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[1] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+}
+
+
+bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
+ Selector S = ME->getSelector();
+
+ if (ME->isInstanceMessage()) {
+ // Check for the "raise" message.
+ return S == RaiseSel;
+ }
+
+ if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
+ if (isSubclass(ID, NSExceptionII)) {
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
+ if (S == NSExceptionInstanceRaiseSelectors[i])
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 9e4c0fec4c04..2fa5a88f2c71 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -52,7 +53,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -196,6 +198,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
@@ -212,18 +227,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
@@ -482,9 +498,11 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
- if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
+ if (ATR.isValid() && ATR.matchesType(Ctx, QT))
+ return true;
+ }
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
@@ -549,6 +567,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
// The plus prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -572,6 +591,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
// Alternate form flag only valid with the oxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -596,9 +616,12 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
// Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -623,6 +646,7 @@ bool PrintfSpecifier::hasValidSpacePrefix() const {
// The space prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -659,8 +683,10 @@ bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
case ConversionSpecifier::gArg:
@@ -678,9 +704,12 @@ bool PrintfSpecifier::hasValidPrecision() const {
// Precision is only valid with the diouxXaAeEfFgGs conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index bb63e2c18490..11f2ebe9ad2d 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -112,8 +112,8 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
static int SrcCmp(const void *p1, const void *p2) {
return
- ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
- ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
}
unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 2942400621d1..574e56a5e068 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -67,7 +68,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_scanf;
const char *I = Beg;
@@ -172,6 +174,20 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
case 'o': k = ConversionSpecifier::oArg; break;
case 's': k = ConversionSpecifier::sArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
+ // Apple extensions
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
ScanfConversionSpecifier CS(conversionPosition, k);
if (k == ScanfConversionSpecifier::ScanListArg) {
@@ -202,6 +218,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
switch(CS.getKind()) {
// Signed int.
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
switch (LM.getKind()) {
case LengthModifier::None:
@@ -233,7 +250,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// Unsigned int.
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
switch (LM.getKind()) {
@@ -430,9 +449,11 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_scanf::ArgType &AT = getArgType(Ctx);
- if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_scanf::ArgType &AT = getArgType(Ctx);
+ if (AT.isValid() && AT.matchesType(Ctx, QT))
+ return true;
+ }
// Figure out the conversion specifier.
if (PT->isRealFloatingType())
@@ -463,18 +484,19 @@ void ScanfSpecifier::toString(raw_ostream &os) const {
bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 5954682579d8..c7f1f62cb57d 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -70,27 +70,28 @@ namespace {
class SExpr {
private:
enum ExprOp {
- EOP_Nop, //< No-op
- EOP_Wildcard, //< Matches anything.
- EOP_This, //< This keyword.
- EOP_NVar, //< Named variable.
- EOP_LVar, //< Local variable.
- EOP_Dot, //< Field access
- EOP_Call, //< Function call
- EOP_MCall, //< Method call
- EOP_Index, //< Array index
- EOP_Unary, //< Unary operation
- EOP_Binary, //< Binary operation
- EOP_Unknown //< Catchall for everything else
+ EOP_Nop, ///< No-op
+ EOP_Wildcard, ///< Matches anything.
+ EOP_Universal, ///< Universal lock.
+ EOP_This, ///< This keyword.
+ EOP_NVar, ///< Named variable.
+ EOP_LVar, ///< Local variable.
+ EOP_Dot, ///< Field access
+ EOP_Call, ///< Function call
+ EOP_MCall, ///< Method call
+ EOP_Index, ///< Array index
+ EOP_Unary, ///< Unary operation
+ EOP_Binary, ///< Binary operation
+ EOP_Unknown ///< Catchall for everything else
};
class SExprNode {
private:
- unsigned char Op; //< Opcode of the root node
- unsigned char Flags; //< Additional opcode-specific data
- unsigned short Sz; //< Number of child nodes
- const void* Data; //< Additional opcode-specific data
+ unsigned char Op; ///< Opcode of the root node
+ unsigned char Flags; ///< Additional opcode-specific data
+ unsigned short Sz; ///< Number of child nodes
+ const void* Data; ///< Additional opcode-specific data
public:
SExprNode(ExprOp O, unsigned F, const void* D)
@@ -118,18 +119,19 @@ private:
unsigned arity() const {
switch (Op) {
- case EOP_Nop: return 0;
- case EOP_Wildcard: return 0;
- case EOP_NVar: return 0;
- case EOP_LVar: return 0;
- case EOP_This: return 0;
- case EOP_Dot: return 1;
- case EOP_Call: return Flags+1; // First arg is function.
- case EOP_MCall: return Flags+1; // First arg is implicit obj.
- case EOP_Index: return 2;
- case EOP_Unary: return 1;
- case EOP_Binary: return 2;
- case EOP_Unknown: return Flags;
+ case EOP_Nop: return 0;
+ case EOP_Wildcard: return 0;
+ case EOP_Universal: return 0;
+ case EOP_NVar: return 0;
+ case EOP_LVar: return 0;
+ case EOP_This: return 0;
+ case EOP_Dot: return 1;
+ case EOP_Call: return Flags+1; // First arg is function.
+ case EOP_MCall: return Flags+1; // First arg is implicit obj.
+ case EOP_Index: return 2;
+ case EOP_Unary: return 1;
+ case EOP_Binary: return 2;
+ case EOP_Unknown: return Flags;
}
return 0;
}
@@ -194,6 +196,11 @@ private:
return NodeVec.size()-1;
}
+ unsigned makeUniversal() {
+ NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));
+ return NodeVec.size()-1;
+ }
+
unsigned makeNamedVar(const NamedDecl *D) {
NodeVec.push_back(SExprNode(EOP_NVar, 0, D));
return NodeVec.size()-1;
@@ -219,8 +226,21 @@ private:
return NodeVec.size()-1;
}
- unsigned makeMCall(unsigned NumArgs, const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, D));
+ // Grab the very first declaration of virtual method D
+ const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+ while (true) {
+ D = D->getCanonicalDecl();
+ CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
+ E = D->end_overridden_methods();
+ if (I == E)
+ return D; // Method does not override anything
+ D = *I; // FIXME: this does not work with multiple inheritance.
+ }
+ return 0;
+ }
+
+ unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
+ NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, getFirstVirtualDecl(D)));
return NodeVec.size()-1;
}
@@ -300,8 +320,9 @@ private:
} else if (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.
- if (LockReturnedAttr* At =
- CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) {
+ CXXMethodDecl* MD =
+ cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
+ if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
LRCallCtx.SelfArrow =
@@ -320,8 +341,7 @@ private:
return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref);
}
unsigned NumCallArgs = CMCE->getNumArgs();
- unsigned Root =
- makeMCall(NumCallArgs, CMCE->getMethodDecl()->getCanonicalDecl());
+ unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
Expr** CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
@@ -330,8 +350,9 @@ private:
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
} else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- if (LockReturnedAttr* At =
- CE->getDirectCallee()->getAttr<LockReturnedAttr>()) {
+ FunctionDecl* FD =
+ cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
+ if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
LRCallCtx.NumArgs = CE->getNumArgs();
LRCallCtx.FunArgs = CE->getArgs();
@@ -442,9 +463,23 @@ private:
/// \param DeclExp An expression involving the Decl on which the attribute
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
- void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
+ void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D,
+ VarDecl *SelfDecl = 0) {
CallingContext CallCtx(D);
+ if (MutexExp) {
+ if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
+ if (SLit->getString() == StringRef("*"))
+ // The "*" expr is a universal lock, which essentially turns off
+ // checks until it is removed from the lockset.
+ makeUniversal();
+ else
+ // Ignore other string literals for now.
+ makeNop();
+ return;
+ }
+ }
+
// If we are processing a raw attribute expression, with no substitutions.
if (DeclExp == 0) {
buildSExpr(MutexExp, 0);
@@ -465,7 +500,7 @@ private:
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = 0; // FIXME -- get the parent from DeclStmt
+ CallCtx.SelfArg = 0; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
@@ -473,14 +508,26 @@ private:
CallCtx.SelfArg = DeclExp;
}
- // If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0) {
- buildSExpr(CallCtx.SelfArg, 0);
+ // Hack to handle constructors, where self cannot be recovered from
+ // the expression.
+ if (SelfDecl && !CallCtx.SelfArg) {
+ DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
+ SelfDecl->getLocation());
+ CallCtx.SelfArg = &SelfDRE;
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
return;
}
- // For most attributes.
- buildSExpr(MutexExp, &CallCtx);
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
}
/// \brief Get index of next sibling of node i.
@@ -496,8 +543,9 @@ public:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) {
- buildSExprFromExpr(MutexExp, DeclExp, D);
+ SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D,
+ VarDecl *SelfDecl=0) {
+ buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
/// Return true if this is a valid decl sequence.
@@ -506,6 +554,17 @@ public:
return !NodeVec.empty();
}
+ bool shouldIgnore() const {
+ // Nop is a mutex that we have decided to deliberately ignore.
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Nop;
+ }
+
+ bool isUniversal() const {
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Universal;
+ }
+
/// Issue a warning about an invalid lock expression
static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
Expr *DeclExp, const NamedDecl* D) {
@@ -528,7 +587,9 @@ public:
bool matches(const SExpr &Other, unsigned i = 0, unsigned j = 0) const {
if (NodeVec[i].matches(Other.NodeVec[j])) {
- unsigned n = NodeVec[i].arity();
+ unsigned ni = NodeVec[i].arity();
+ unsigned nj = Other.NodeVec[j].arity();
+ unsigned n = (ni < nj) ? ni : nj;
bool Result = true;
unsigned ci = i+1; // first child of i
unsigned cj = j+1; // first child of j
@@ -541,6 +602,15 @@ public:
return false;
}
+ // A partial match between a.mu and b.mu returns true a and b have the same
+ // type (and thus mu refers to the same mutex declaration), regardless of
+ // whether a and b are different objects or not.
+ bool partiallyMatches(const SExpr &Other) const {
+ if (NodeVec[0].kind() == EOP_Dot)
+ return NodeVec[0].matches(Other.NodeVec[0]);
+ return false;
+ }
+
/// \brief Pretty print a lock expression for use in error messages.
std::string toString(unsigned i = 0) const {
assert(isValid());
@@ -553,6 +623,8 @@ public:
return "_";
case EOP_Wildcard:
return "(?)";
+ case EOP_Universal:
+ return "*";
case EOP_This:
return "this";
case EOP_NVar:
@@ -695,6 +767,10 @@ struct LockData {
ID.AddInteger(AcquireLoc.getRawEncoding());
ID.AddInteger(LKind);
}
+
+ bool isAtLeast(LockKind LK) {
+ return (LK == LK_Shared) || (LKind == LK_Exclusive);
+ }
};
@@ -780,9 +856,28 @@ public:
return false;
}
- LockData* findLock(FactManager& FM, const SExpr& M) const {
+ LockData* findLock(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M))
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ LockData* findLockUniv(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M) || Exp.isUniversal())
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const {
for (const_iterator I=begin(), E=end(); I != E; ++I) {
- if (FM[*I].MutID.matches(M)) return &FM[*I].LDat;
+ const SExpr& Exp = FM[*I].MutID;
+ if (Exp.partiallyMatches(M)) return &FM[*I];
}
return 0;
}
@@ -811,6 +906,7 @@ struct CFGBlockInfo {
SourceLocation EntryLoc; // Location of first statement in block
SourceLocation ExitLoc; // Location of last statement in block.
unsigned EntryIndex; // Used to replay contexts later
+ bool Reachable; // Is this block reachable?
const FactSet &getSet(CFGBlockSide Side) const {
return Side == CBS_Entry ? EntrySet : ExitSet;
@@ -821,7 +917,7 @@ struct CFGBlockInfo {
private:
CFGBlockInfo(LocalVarContext EmptyCtx)
- : EntryContext(EmptyCtx), ExitContext(EmptyCtx)
+ : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(false)
{ }
public:
@@ -939,7 +1035,7 @@ public:
return;
}
Dec->printName(llvm::errs());
- llvm::errs() << "." << i << " " << ((void*) Dec);
+ llvm::errs() << "." << i << " " << ((const void*) Dec);
}
/// Dumps an ASCII representation of the variable map to llvm::errs()
@@ -1339,7 +1435,7 @@ public:
template <typename AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
- const NamedDecl *D);
+ const NamedDecl *D, VarDecl *SelfDecl=0);
template <class AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
@@ -1376,6 +1472,9 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
const LockData &LDat) {
// FIXME: deal with acquired before/after annotations.
// FIXME: Don't always warn when we have support for reentrant locks.
+ if (Mutex.shouldIgnore())
+ return;
+
if (FSet.findLock(FactMan, Mutex)) {
Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
} else {
@@ -1385,12 +1484,15 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
/// \brief Remove a lock from the lockset, warning if the lock is not there.
-/// \param LockExp The lock expression corresponding to the lock to be removed
+/// \param Mutex The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const SExpr &Mutex,
SourceLocation UnlockLoc,
bool FullyRemove) {
+ if (Mutex.shouldIgnore())
+ return;
+
const LockData *LDat = FSet.findLock(FactMan, Mutex);
if (!LDat) {
Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc);
@@ -1423,12 +1525,13 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
/// and push them onto Mtxs, discarding any duplicates.
template <typename AttrType>
void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
- Expr *Exp, const NamedDecl *D) {
+ Expr *Exp, const NamedDecl *D,
+ VarDecl *SelfDecl) {
typedef typename AttrType::args_iterator iterator_type;
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(0, Exp, D);
+ SExpr Mu(0, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, 0, Exp, D);
else
@@ -1437,7 +1540,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
}
for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- SExpr Mu(*I, Exp, D);
+ SExpr Mu(*I, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, *I, Exp, D);
else
@@ -1512,6 +1615,9 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) {
return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
}
+ else if (const ExprWithCleanups* EWC = dyn_cast<ExprWithCleanups>(Cond)) {
+ return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
+ }
else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
return getTrylockCallExpr(E, C, Negate);
@@ -1591,7 +1697,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
case attr::SharedTrylockFunction: {
SharedTrylockFunctionAttr *A =
cast<SharedTrylockFunctionAttr>(Attr);
- getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
+ getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
PredBlock, CurrBlock, A->getSuccessValue(), Negate);
break;
}
@@ -1631,39 +1737,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
+ void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
- /// \brief Returns true if the lockset contains a lock, regardless of whether
- /// the lock is held exclusively or shared.
- bool locksetContains(const SExpr &Mu) const {
- return FSet.findLock(Analyzer->FactMan, Mu);
- }
-
- /// \brief Returns true if the lockset contains a lock with the passed in
- /// locktype.
- bool locksetContains(const SExpr &Mu, LockKind KindRequested) const {
- const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu);
- return (LockHeld && KindRequested == LockHeld->LKind);
- }
-
- /// \brief Returns true if the lockset contains a lock with at least the
- /// passed in locktype. So for example, if we pass in LK_Shared, this function
- /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
- /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(const SExpr &Lock,
- LockKind KindRequested) const {
- switch (KindRequested) {
- case LK_Shared:
- return locksetContains(Lock);
- case LK_Exclusive:
- return locksetContains(Lock, KindRequested);
- }
- llvm_unreachable("Unknown LockKind");
- }
-
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
: StmtVisitor<BuildLockset>(),
@@ -1701,13 +1780,57 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
LockKind LK = getLockKindFromAccessKind(AK);
SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid())
+ if (!Mutex.isValid()) {
SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
- else if (!locksetContainsAtLeast(Mutex, LK))
+ return;
+ } else if (Mutex.shouldIgnore()) {
+ return;
+ }
+
+ LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);
+ bool NoError = true;
+ if (!LDat) {
+ // No exact match found. Look for a partial match.
+ FactEntry* FEntry = FSet.findPartialMatch(Analyzer->FactMan, Mutex);
+ if (FEntry) {
+ // Warn that there's no precise match.
+ LDat = &FEntry->LDat;
+ std::string PartMatchStr = FEntry->MutID.toString();
+ StringRef PartMatchName(PartMatchStr);
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc(), &PartMatchName);
+ } else {
+ // Warn that there's no match at all.
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc());
+ }
+ NoError = false;
+ }
+ // Make sure the mutex we found is the right kind.
+ if (NoError && LDat && !LDat->isAtLeast(LK))
Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
Exp->getExprLoc());
}
+/// \brief Warn if the LSet contains the given lock.
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+ Expr *MutexExp) {
+ SExpr Mutex(MutexExp, Exp, D);
+ if (!Mutex.isValid()) {
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ return;
+ }
+
+ LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
+ if (LDat) {
+ std::string DeclName = D->getNameAsString();
+ StringRef DeclNameSR (DeclName);
+ Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(),
+ Exp->getExprLoc());
+ }
+}
+
+
/// \brief This method identifies variable dereferences and checks pt_guarded_by
/// and pt_guarded_var annotations. Note that we only check these annotations
/// at the time a pointer is dereferenced.
@@ -1776,7 +1899,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind exclusive.
case attr::ExclusiveLockFunction: {
ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(At);
- Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1784,7 +1907,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind shared.
case attr::SharedLockFunction: {
SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(At);
- Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1792,7 +1915,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// mutexes from the lockset, and flag a warning if they are not there.
case attr::UnlockFunction: {
UnlockFunctionAttr *A = cast<UnlockFunctionAttr>(At);
- Analyzer->getMutexIDs(LocksToRemove, A, Exp, D);
+ Analyzer->getMutexIDs(LocksToRemove, A, Exp, D, VD);
break;
}
@@ -1816,15 +1939,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
+
for (LocksExcludedAttr::args_iterator I = A->args_begin(),
E = A->args_end(); I != E; ++I) {
- SExpr Mutex(*I, Exp, D);
- if (!Mutex.isValid())
- SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D);
- else if (locksetContains(Mutex))
- Analyzer->Handler.handleFunExcludesLock(D->getName(),
- Mutex.toString(),
- Exp->getExprLoc());
+ warnIfMutexHeld(D, Exp, *I);
}
break;
}
@@ -1973,8 +2091,8 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) {
/// are the same. In the event of a difference, we use the intersection of these
/// two locksets at the start of D.
///
-/// \param LSet1 The first lockset.
-/// \param LSet2 The second lockset.
+/// \param FSet1 The first lockset.
+/// \param FSet2 The second lockset.
/// \param JoinLoc The location of the join point for error reporting
/// \param LEK1 The error message to report if a mutex is missing from LSet1
/// \param LEK2 The error message to report if a mutex is missing from Lset2
@@ -2012,7 +2130,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat2.Managed)
+ else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
LDat2.AcquireLoc,
JoinLoc, LEK1);
@@ -2035,7 +2153,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat1.Managed)
+ else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
LDat1.AcquireLoc,
JoinLoc, LEK2);
@@ -2081,6 +2199,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+ // Mark entry block as reachable
+ BlockInfo[CFGraph->getEntry().getBlockID()].Reachable = true;
+
// Compute SSA names for local variables
LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
@@ -2168,10 +2289,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
continue;
+ int PrevBlockID = (*PI)->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
// Ignore edges from blocks that can't return.
- if ((*PI)->hasNoReturnElement())
+ if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable)
continue;
+ // Okay, we can reach this block from the entry.
+ CurrBlockInfo->Reachable = true;
+
// If the previous block ended in a 'continue' or 'break' statement, then
// a difference in locksets is probably due to a bug in that block, rather
// than in some other predecessor. In that case, keep the other
@@ -2183,8 +2310,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
- int PrevBlockID = (*PI)->getBlockID();
- CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
FactSet PrevLockset;
getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
@@ -2198,6 +2324,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
+ // Skip rest of block if it's not reachable.
+ if (!CurrBlockInfo->Reachable)
+ continue;
+
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
@@ -2287,6 +2417,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFGBlockInfo *Initial = &BlockInfo[CFGraph->getEntry().getBlockID()];
CFGBlockInfo *Final = &BlockInfo[CFGraph->getExit().getBlockID()];
+ // Skip the final check if the exit block is unreachable.
+ if (!Final->Reachable)
+ return;
+
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(Initial->EntrySet, Final->ExitSet,
Final->ExitLoc,
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 858be4561caf..b2e27cad1f39 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -13,6 +13,7 @@
#include <utility>
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/PackedVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -22,6 +23,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -97,22 +99,21 @@ static bool isAlwaysUninit(const Value v) {
namespace {
-typedef llvm::PackedVector<Value, 2> ValueVector;
+typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
class CFGBlockValues {
const CFG &cfg;
- std::vector<ValueVector*> vals;
+ SmallVector<ValueVector, 8> vals;
ValueVector scratch;
DeclToIndex declToIndex;
public:
CFGBlockValues(const CFG &cfg);
- ~CFGBlockValues();
unsigned getNumEntries() const { return declToIndex.size(); }
void computeSetOfDeclarations(const DeclContext &dc);
ValueVector &getValueVector(const CFGBlock *block) {
- return *vals[block->getBlockID()];
+ return vals[block->getBlockID()];
}
void setAllScratchValues(Value V);
@@ -138,12 +139,6 @@ public:
CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
-CFGBlockValues::~CFGBlockValues() {
- for (std::vector<ValueVector*>::iterator I = vals.begin(), E = vals.end();
- I != E; ++I)
- delete *I;
-}
-
void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
declToIndex.computeMap(dc);
unsigned decls = declToIndex.size();
@@ -153,7 +148,7 @@ void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
return;
vals.resize(n);
for (unsigned i = 0; i < n; ++i)
- vals[i] = new ValueVector(decls);
+ vals[i].resize(decls);
}
#if DEBUG_LOGGING
@@ -412,6 +407,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
const CFGBlock *block;
AnalysisDeclContext &ac;
const ClassifyRefs &classification;
+ ObjCNoReturn objCNoRet;
UninitVariablesHandler *handler;
public:
@@ -420,16 +416,18 @@ public:
const ClassifyRefs &classification,
UninitVariablesHandler *handler)
: vals(vals), cfg(cfg), block(block), ac(ac),
- classification(classification), handler(handler) {}
+ classification(classification), objCNoRet(ac.getASTContext()),
+ handler(handler) {}
void reportUse(const Expr *ex, const VarDecl *vd);
- void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitBinaryOperator(BinaryOperator *bo);
void VisitBlockExpr(BlockExpr *be);
void VisitCallExpr(CallExpr *ce);
- void VisitDeclStmt(DeclStmt *ds);
void VisitDeclRefExpr(DeclRefExpr *dr);
- void VisitBinaryOperator(BinaryOperator *bo);
+ void VisitDeclStmt(DeclStmt *ds);
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME);
bool isTrackedVar(const VarDecl *vd) {
return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
@@ -605,14 +603,26 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
}
void TransferFunctions::VisitCallExpr(CallExpr *ce) {
- // After a call to a function like setjmp or vfork, any variable which is
- // initialized anywhere within this function may now be initialized. For now,
- // just assume such a call initializes all variables.
- // FIXME: Only mark variables as initialized if they have an initializer which
- // is reachable from here.
- Decl *Callee = ce->getCalleeDecl();
- if (Callee && Callee->hasAttr<ReturnsTwiceAttr>())
- vals.setAllScratchValues(Initialized);
+ if (Decl *Callee = ce->getCalleeDecl()) {
+ if (Callee->hasAttr<ReturnsTwiceAttr>()) {
+ // After a call to a function like setjmp or vfork, any variable which is
+ // initialized anywhere within this function may now be initialized. For
+ // now, just assume such a call initializes all variables. FIXME: Only
+ // mark variables as initialized if they have an initializer which is
+ // reachable from here.
+ vals.setAllScratchValues(Initialized);
+ }
+ else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
+ // Functions labeled like "analyzer_noreturn" are often used to denote
+ // "panic" functions that in special debug situations can still return,
+ // but for the most part should not be treated as returning. This is a
+ // useful annotation borrowed from the static analyzer that is useful for
+ // suppressing branch-specific false positives when we call one of these
+ // functions but keep pretending the path continues (when in reality the
+ // user doesn't care).
+ vals.setAllScratchValues(Unknown);
+ }
+ }
}
void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
@@ -677,6 +687,14 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
}
}
+void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ // If the Objective-C message expression is an implicit no-return that
+ // is not modeled in the CFG, set the tracked dataflow values to Unknown.
+ if (objCNoRet.isImplicitNoReturn(ME)) {
+ vals.setAllScratchValues(Unknown);
+ }
+}
+
//------------------------------------------------------------------------====//
// High-level "driver" logic for uninitialized values analysis.
//====------------------------------------------------------------------------//
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
index 4793b251f603..d16965ddd872 100644
--- a/lib/Basic/ConvertUTF.c
+++ b/lib/Basic/ConvertUTF.c
@@ -111,7 +111,6 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
* into an inline function.
*/
-#ifdef CLANG_NEEDS_THESE_ONE_DAY
/* --------------------------------------------------------------------- */
@@ -285,7 +284,6 @@ ConversionResult ConvertUTF16toUTF8 (
*targetStart = target;
return result;
}
-#endif
/* --------------------------------------------------------------------- */
@@ -361,7 +359,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
@@ -395,15 +393,25 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
/* --------------------------------------------------------------------- */
/*
+ * Exported function to return the total number of bytes in a codepoint
+ * represented in UTF-8, given the value of the first byte.
+ */
+unsigned getNumBytesForUTF8(UTF8 first) {
+ return trailingBytesForUTF8[first] + 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
* Exported function to return whether a UTF-8 string is legal or not.
* This is not used here; it's just exported.
*/
-Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd) {
- while (source != sourceEnd) {
- int length = trailingBytesForUTF8[*source] + 1;
- if (length > sourceEnd - source || !isLegalUTF8(source, length))
+Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
+ while (*source != sourceEnd) {
+ int length = trailingBytesForUTF8[**source] + 1;
+ if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
return false;
- source += length;
+ *source += length;
}
return true;
}
diff --git a/lib/Basic/ConvertUTFWrapper.cpp b/lib/Basic/ConvertUTFWrapper.cpp
index a1b3f7fd9da3..6be3828d2868 100644
--- a/lib/Basic/ConvertUTFWrapper.cpp
+++ b/lib/Basic/ConvertUTFWrapper.cpp
@@ -13,16 +13,19 @@
namespace clang {
bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr) {
+ char *&ResultPtr, const UTF8 *&ErrorPtr) {
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
ConversionResult result = conversionOK;
// Copy the character span over.
if (WideCharWidth == 1) {
- if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(Source.begin()),
- reinterpret_cast<const UTF8*>(Source.end())))
+ const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin());
+ if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) {
result = sourceIllegal;
- memcpy(ResultPtr, Source.data(), Source.size());
- ResultPtr += Source.size();
+ ErrorPtr = Pos;
+ } else {
+ memcpy(ResultPtr, Source.data(), Source.size());
+ ResultPtr += Source.size();
+ }
} else if (WideCharWidth == 2) {
const UTF8 *sourceStart = (const UTF8*)Source.data();
// FIXME: Make the type of the result buffer correct instead of
@@ -34,6 +37,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
&targetStart, targetStart + 2*Source.size(), flags);
if (result == conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
+ else
+ ErrorPtr = sourceStart;
} else if (WideCharWidth == 4) {
const UTF8 *sourceStart = (const UTF8*)Source.data();
// FIXME: Make the type of the result buffer correct instead of
@@ -45,6 +50,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
&targetStart, targetStart + 4*Source.size(), flags);
if (result == conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
+ else
+ ErrorPtr = sourceStart;
}
assert((result != targetExhausted)
&& "ConvertUTF8toUTFXX exhausted target buffer");
@@ -67,4 +74,3 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
}
} // end namespace clang
-
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 8065b2d98f32..854c4c56bb7f 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -12,9 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cctype>
@@ -36,9 +38,10 @@ static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
DiagnosticsEngine::DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
+ DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client, bool ShouldOwnClient)
- : Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient),
- SourceMgr(0) {
+ : Diags(diags), DiagOpts(DiagOpts), Client(client),
+ OwnsDiagClient(ShouldOwnClient), SourceMgr(0) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
@@ -515,23 +518,7 @@ static void HandleOrdinalModifier(unsigned ValNo,
// We could use text forms for the first N ordinals, but the numeric
// forms are actually nicer in diagnostics because they stand out.
- Out << ValNo;
-
- // It is critically important that we do this perfectly for
- // user-written sequences with over 100 elements.
- switch (ValNo % 100) {
- case 11:
- case 12:
- case 13:
- Out << "th"; return;
- default:
- switch (ValNo % 10) {
- case 1: Out << "st"; return;
- case 2: Out << "nd"; return;
- case 3: Out << "rd"; return;
- default: Out << "th"; return;
- }
- }
+ Out << ValNo << llvm::getOrdinalSuffix(ValNo);
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index ca96fd2b9b24..ed976436e284 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -628,9 +628,9 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
if (DiagLevel >= DiagnosticIDs::Error) {
if (isUnrecoverable(DiagID))
Diag.UnrecoverableErrorOccurred = true;
-
+
+ Diag.ErrorOccurred = true;
if (Diag.Client->IncludeInDiagnosticCounts()) {
- Diag.ErrorOccurred = true;
++Diag.NumErrors;
}
@@ -686,4 +686,3 @@ bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
unsigned cat = getCategoryNumberForDiag(DiagID);
return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
}
-
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index c6b894c7e2fe..a816969b9144 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -36,6 +36,9 @@
#include <sys/uio.h>
#else
#include <io.h>
+#ifndef S_ISFIFO
+#define S_ISFIFO(x) (0)
+#endif
#endif
using namespace clang;
@@ -57,6 +60,10 @@ FileEntry::~FileEntry() {
if (FD != -1) ::close(FD);
}
+bool FileEntry::isNamedPipe() const {
+ return S_ISFIFO(FileMode);
+}
+
//===----------------------------------------------------------------------===//
// Windows.
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 4869ae1056be..1965bf99338b 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -17,7 +17,6 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cctype>
@@ -33,6 +32,7 @@ IdentifierInfo::IdentifierInfo() {
TokenID = tok::identifier;
ObjCOrBuiltinID = 0;
HasMacro = false;
+ HadMacro = false;
IsExtension = false;
IsCXX11CompatKeyword = false;
IsPoisoned = false;
@@ -105,6 +105,7 @@ namespace {
KEYC11 = 0x400,
KEYARC = 0x800,
KEYNOMS = 0x01000,
+ WCHARSUPPORT = 0x02000,
KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude.
};
}
@@ -129,6 +130,7 @@ static void AddKeyword(StringRef Keyword,
else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
+ else if (LangOpts.WChar && (Flags & WCHARSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 634884074e14..76c7f8b364eb 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -23,8 +23,8 @@ using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
- Umbrella(), IsAvailable(true), IsFromModuleFile(false),
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
+ Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), NameVisibility(Hidden)
@@ -219,6 +219,13 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(Headers[I]->getName());
OS << "\"\n";
}
+
+ for (unsigned I = 0, N = ExcludedHeaders.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "exclude header \"";
+ OS.write_escaped(ExcludedHeaders[I]->getName());
+ OS << "\"\n";
+ }
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index bb5a10a9c7e4..0d62f7bb4b8c 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -61,6 +61,13 @@ void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{
OS << '>';
}
+std::string SourceLocation::printToString(const SourceManager &SM) const {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ print(OS, SM);
+ return S;
+}
+
void SourceLocation::dump(const SourceManager &SM) const {
print(llvm::errs(), SM);
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 9ec247429945..cd0284a18e5d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -1029,6 +1029,17 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
return 1;
}
+ // See if we just calculated the line number for this FilePos and can use
+ // that to lookup the start of the line instead of searching for it.
+ if (LastLineNoFileIDQuery == FID &&
+ LastLineNoContentCache->SourceLineCache != 0) {
+ unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
+ unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
+ unsigned LineEnd = SourceLineCache[LastLineNoResult];
+ if (FilePos >= LineStart && FilePos < LineEnd)
+ return FilePos - LineStart + 1;
+ }
+
const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
@@ -1112,7 +1123,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
// Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'.
while (NextBuf+16 <= End) {
- __m128i Chunk = *(__m128i*)NextBuf;
+ const __m128i Chunk = *(const __m128i*)NextBuf;
__m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs),
_mm_cmpeq_epi8(Chunk, LFs));
unsigned Mask = _mm_movemask_epi8(Cmp);
@@ -1577,6 +1588,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
}
}
+ (void) SourceFile;
return FirstFID;
}
@@ -1693,46 +1705,91 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
if (!ExpInfo.isMacroArgExpansion())
continue;
- SourceLocation SpellLoc = ExpInfo.getSpellingLoc();
- while (!SpellLoc.isFileID()) {
- std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc);
- const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion();
- if (!Info.isMacroArgExpansion())
- break;
- SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second);
+ associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+ ExpInfo.getSpellingLoc(),
+ SourceLocation::getMacroLoc(Entry.getOffset()),
+ getFileIDSize(FileID::get(ID)));
+ }
+}
+
+void SourceManager::associateFileChunkWithMacroArgExp(
+ MacroArgsMap &MacroArgsCache,
+ FileID FID,
+ SourceLocation SpellLoc,
+ SourceLocation ExpansionLoc,
+ unsigned ExpansionLength) const {
+ if (!SpellLoc.isFileID()) {
+ unsigned SpellBeginOffs = SpellLoc.getOffset();
+ unsigned SpellEndOffs = SpellBeginOffs + ExpansionLength;
+
+ // The spelling range for this macro argument expansion can span multiple
+ // consecutive FileID entries. Go through each entry contained in the
+ // spelling range and if one is itself a macro argument expansion, recurse
+ // and associate the file chunk that it represents.
+
+ FileID SpellFID; // Current FileID in the spelling range.
+ unsigned SpellRelativeOffs;
+ llvm::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
+ while (1) {
+ const SLocEntry &Entry = getSLocEntry(SpellFID);
+ unsigned SpellFIDBeginOffs = Entry.getOffset();
+ unsigned SpellFIDSize = getFileIDSize(SpellFID);
+ unsigned SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize;
+ const ExpansionInfo &Info = Entry.getExpansion();
+ if (Info.isMacroArgExpansion()) {
+ unsigned CurrSpellLength;
+ if (SpellFIDEndOffs < SpellEndOffs)
+ CurrSpellLength = SpellFIDSize - SpellRelativeOffs;
+ else
+ CurrSpellLength = ExpansionLength;
+ associateFileChunkWithMacroArgExp(MacroArgsCache, FID,
+ Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs),
+ ExpansionLoc, CurrSpellLength);
+ }
+
+ if (SpellFIDEndOffs >= SpellEndOffs)
+ return; // we covered all FileID entries in the spelling range.
+
+ // Move to the next FileID entry in the spelling range.
+ unsigned advance = SpellFIDSize - SpellRelativeOffs + 1;
+ ExpansionLoc = ExpansionLoc.getLocWithOffset(advance);
+ ExpansionLength -= advance;
+ ++SpellFID.ID;
+ SpellRelativeOffs = 0;
}
- if (!SpellLoc.isFileID())
- continue;
-
- unsigned BeginOffs;
- if (!isInFileID(SpellLoc, FID, &BeginOffs))
- continue;
- unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
-
- // Add a new chunk for this macro argument. A previous macro argument chunk
- // may have been lexed again, so e.g. if the map is
- // 0 -> SourceLocation()
- // 100 -> Expanded loc #1
- // 110 -> SourceLocation()
- // and we found a new macro FileID that lexed from offet 105 with length 3,
- // the new map will be:
- // 0 -> SourceLocation()
- // 100 -> Expanded loc #1
- // 105 -> Expanded loc #2
- // 108 -> Expanded loc #1
- // 110 -> SourceLocation()
- //
- // Since re-lexed macro chunks will always be the same size or less of
- // previous chunks, we only need to find where the ending of the new macro
- // chunk is mapped to and update the map with new begin/end mappings.
-
- MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
- --I;
- SourceLocation EndOffsMappedLoc = I->second;
- MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
- MacroArgsCache[EndOffs] = EndOffsMappedLoc;
}
+
+ assert(SpellLoc.isFileID());
+
+ unsigned BeginOffs;
+ if (!isInFileID(SpellLoc, FID, &BeginOffs))
+ return;
+
+ unsigned EndOffs = BeginOffs + ExpansionLength;
+
+ // Add a new chunk for this macro argument. A previous macro argument chunk
+ // may have been lexed again, so e.g. if the map is
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ // and we found a new macro FileID that lexed from offet 105 with length 3,
+ // the new map will be:
+ // 0 -> SourceLocation()
+ // 100 -> Expanded loc #1
+ // 105 -> Expanded loc #2
+ // 108 -> Expanded loc #1
+ // 110 -> SourceLocation()
+ //
+ // Since re-lexed macro chunks will always be the same size or less of
+ // previous chunks, we only need to find where the ending of the new macro
+ // chunk is mapped to and update the map with new begin/end mappings.
+
+ MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs);
+ --I;
+ SourceLocation EndOffsMappedLoc = I->second;
+ MacroArgsCache[BeginOffs] = ExpansionLoc;
+ MacroArgsCache[EndOffs] = EndOffsMappedLoc;
}
/// \brief If \arg Loc points inside a function macro argument, the returned
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index db5941a5d921..83d4e2bf63c9 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -24,7 +24,8 @@ using namespace clang;
static const LangAS::Map DefaultAddrSpaceMap = { 0 };
// TargetInfo Constructor.
-TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
+TargetInfo::TargetInfo(const std::string &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;
@@ -59,6 +60,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
SigAtomicType = SignedInt;
+ ProcessIDType = SignedInt;
UseSignedCharForObjCBool = true;
UseBitFieldTypeAlignment = true;
UseZeroLengthBitfieldAlignment = false;
@@ -363,6 +365,8 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
+ case '#': // Ignore as constraint.
+ case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
@@ -482,6 +486,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
break;
case '?': // Disparage slightly code.
case '!': // Disparage severely.
+ case '#': // Ignore as constraint.
+ case '*': // Ignore for choosing register preferences.
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1d495f1f6412..f36ef826d0b2 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -92,6 +92,9 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
+ // AddressSanitizer doesn't play well with source fortification, which is on
+ // by default on Darwin.
+ if (Opts.SanitizeAddress) Builder.defineMacro("_FORTIFY_SOURCE", "0");
if (!Opts.ObjCAutoRefCount) {
// __weak is always defined, for use in blocks and with objc pointers.
@@ -316,7 +319,7 @@ protected:
DefineStd(Builder, "linux", Opts);
Builder.defineMacro("__gnu_linux__");
Builder.defineMacro("__ELF__");
- if (Triple.getEnvironment() == llvm::Triple::ANDROIDEABI)
+ if (Triple.getEnvironment() == llvm::Triple::Android)
Builder.defineMacro("__ANDROID__", "1");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
@@ -587,6 +590,48 @@ public:
: OSTargetInfo<Target>(triple) {}
};
+template <typename Target>
+class NaClTargetInfo : public OSTargetInfo<Target> {
+ protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__native_client__");
+ }
+ public:
+ NaClTargetInfo(const std::string &triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->UIntMaxType = TargetInfo::UnsignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ this->RegParmMax = 2;
+ this->LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
+ }
+ virtual typename Target::CallingConvCheckResult checkCallingConvention(
+ CallingConv CC) const {
+ return CC == CC_PnaclCall ? Target::CCCR_OK :
+ Target::checkCallingConvention(CC);
+ }
+};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -641,6 +686,8 @@ public:
.Case("970", true)
.Case("g5", true)
.Case("a2", true)
+ .Case("e500mc", true)
+ .Case("e5500", true)
.Case("pwr6", true)
.Case("pwr7", true)
.Case("ppc", true)
@@ -990,6 +1037,9 @@ public:
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
+
+ // PPC32 supports atomics up to 4 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
virtual BuiltinVaListKind getBuiltinVaListKind() const {
@@ -1007,13 +1057,20 @@ public:
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
- 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-v128:128:128-n32:64";
if (getTriple().getOS() == llvm::Triple::FreeBSD) {
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-"
+ "v128:128:128-n32:64";
+ } else
+ 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:128:128-"
+ "v128:128:128-n32:64";
+
+ // PPC64 supports atomics up to 8 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual BuiltinVaListKind getBuiltinVaListKind() const {
return TargetInfo::CharPtrBuiltinVaList;
@@ -1047,6 +1104,8 @@ public:
: 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-"
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
}
};
} // end anonymous namespace.
@@ -1172,6 +1231,71 @@ namespace {
}
namespace {
+
+static const unsigned R600AddrSpaceMap[] = {
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+
+class R600TargetInfo : public TargetInfo {
+public:
+ R600TargetInfo(const std::string& triple) : TargetInfo(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-f80:32:32"
+ "-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"
+ "-n8:16:32:64";
+ AddrSpaceMap = &R600AddrSpaceMap;
+ }
+
+ virtual const char * getClobbers() const {
+ return "";
+ }
+
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &numNames) const {
+ Names = NULL;
+ numNames = 0;
+ }
+
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = NULL;
+ NumAliases = 0;
+ }
+
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ return true;
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = NULL;
+ NumRecords = 0;
+ }
+
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__R600__");
+ }
+
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+};
+
+} // end anonymous namespace
+
+namespace {
// MBlaze abstract base class
class MBlazeTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
@@ -1351,10 +1475,12 @@ class X86TargetInfo : public TargetInfo {
bool HasBMI;
bool HasBMI2;
bool HasPOPCNT;
+ bool HasRTM;
bool HasSSE4a;
bool HasFMA4;
bool HasFMA;
bool HasXOP;
+ bool HasF16C;
/// \brief Enumeration of all of the X86 CPUs supported by Clang.
///
@@ -1500,8 +1626,9 @@ 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), HasSSE4a(false),
- HasFMA4(false), HasFMA(false), HasXOP(false), CPU(CK_Generic) {
+ HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false),
+ HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false),
+ HasF16C(false), CPU(CK_Generic) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1544,9 +1671,10 @@ public:
virtual bool hasFeature(StringRef Feature) const;
virtual void HandleTargetFeatures(std::vector<std::string> &Features);
virtual const char* getABI() const {
- if (PointerWidth == 64 && SSELevel >= AVX)
+ if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
- else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow)
+ else if (getTriple().getArch() == llvm::Triple::x86 &&
+ MMX3DNowLevel == NoMMX3DNow)
return "no-mmx";
return "";
}
@@ -1640,7 +1768,7 @@ public:
case CK_AthlonMP:
case CK_Geode:
// Only accept certain architectures when compiling in 32-bit mode.
- if (PointerWidth != 32)
+ if (getTriple().getArch() != llvm::Triple::x86)
return false;
// Fallthrough
@@ -1668,6 +1796,19 @@ public:
}
llvm_unreachable("Unhandled CPU kind");
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ // We accept all non-ARM calling conventions
+ return (CC == CC_X86ThisCall ||
+ CC == CC_X86FastCall ||
+ CC == CC_X86StdCall ||
+ CC == CC_C ||
+ CC == CC_X86Pascal) ? CCCR_OK : CCCR_Warning;
+ }
+
+ virtual CallingConv getDefaultCallingConv() const {
+ return CC_C;
+ }
};
void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
@@ -1691,14 +1832,16 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["bmi"] = false;
Features["bmi2"] = false;
Features["popcnt"] = false;
+ Features["rtm"] = false;
Features["fma4"] = false;
Features["fma"] = false;
Features["xop"] = false;
+ Features["f16c"] = false;
// FIXME: This *really* should not be here.
// X86_64 always has SSE2.
- if (PointerWidth == 64)
+ if (getTriple().getArch() == llvm::Triple::x86_64)
Features["sse2"] = Features["sse"] = Features["mmx"] = true;
switch (CPU) {
@@ -1770,6 +1913,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "rdrnd", true);
setFeatureEnabled(Features, "bmi", true);
setFeatureEnabled(Features, "bmi2", true);
+ setFeatureEnabled(Features, "rtm", true);
setFeatureEnabled(Features, "fma", true);
break;
case CK_K6:
@@ -1904,6 +2048,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
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 == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
@@ -1964,6 +2112,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
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;
}
return true;
@@ -2015,6 +2167,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "rtm") {
+ HasRTM = true;
+ continue;
+ }
+
if (Feature == "sse4a") {
HasSSE4a = true;
continue;
@@ -2035,6 +2192,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "f16c") {
+ HasF16C = true;
+ continue;
+ }
+
assert(Features[i][0] == '+' && "Invalid target feature!");
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
.Case("avx2", AVX2)
@@ -2071,7 +2233,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
- if (PointerWidth == 64) {
+ if (getTriple().getArch() == llvm::Triple::x86_64) {
Builder.defineMacro("__amd64__");
Builder.defineMacro("__amd64");
Builder.defineMacro("__x86_64");
@@ -2231,6 +2393,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasPOPCNT)
Builder.defineMacro("__POPCNT__");
+ if (HasRTM)
+ Builder.defineMacro("__RTM__");
+
if (HasSSE4a)
Builder.defineMacro("__SSE4A__");
@@ -2243,6 +2408,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasXOP)
Builder.defineMacro("__XOP__");
+ if (HasF16C)
+ Builder.defineMacro("__F16C__");
+
// Each case falls through to the previous one here.
switch (SSELevel) {
case AVX2:
@@ -2267,7 +2435,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
break;
}
- if (Opts.MicrosoftExt && PointerWidth == 32) {
+ if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) {
switch (SSELevel) {
case AVX2:
case AVX:
@@ -2315,6 +2483,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("mmx", MMX3DNowLevel >= MMX)
.Case("pclmul", HasPCLMUL)
.Case("popcnt", HasPOPCNT)
+ .Case("rtm", HasRTM)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
.Case("sse3", SSELevel >= SSE3)
@@ -2323,9 +2492,10 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("sse42", SSELevel >= SSE42)
.Case("sse4a", HasSSE4a)
.Case("x86", true)
- .Case("x86_32", PointerWidth == 32)
- .Case("x86_64", PointerWidth == 64)
+ .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
+ .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
.Case("xop", HasXOP)
+ .Case("f16c", HasF16C)
.Default(false);
}
@@ -2595,7 +2765,9 @@ public:
SizeType = UnsignedLong;
IntPtrType = SignedLong;
PtrDiffType = SignedLong;
+ ProcessIDType = SignedLong;
this->UserLabelPrefix = "";
+ this->TLSSupported = false;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -2703,6 +2875,15 @@ public:
if (RegNo == 1) return 1;
return -1;
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ return TargetInfo::checkCallingConvention(CC);
+ }
+
+ virtual CallingConv getDefaultCallingConv() const {
+ return CC_Default;
+ }
+
};
} // end anonymous namespace
@@ -2820,14 +3001,14 @@ namespace {
class ARMTargetInfo : public TargetInfo {
// Possible FPU choices.
enum FPUMode {
- NoFPU,
- VFP2FPU,
- VFP3FPU,
- NeonFPU
+ VFP2FPU = (1 << 0),
+ VFP3FPU = (1 << 1),
+ VFP4FPU = (1 << 2),
+ NeonFPU = (1 << 3)
};
static bool FPUModeIsVFP(FPUMode Mode) {
- return Mode >= VFP2FPU && Mode <= NeonFPU;
+ return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU);
}
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -2835,8 +3016,9 @@ class ARMTargetInfo : public TargetInfo {
std::string ABI, CPU;
- unsigned FPU : 3;
+ unsigned FPU : 4;
+ unsigned IsAAPCS : 1;
unsigned IsThumb : 1;
// Initialized via features.
@@ -2847,7 +3029,7 @@ class ARMTargetInfo : public TargetInfo {
public:
ARMTargetInfo(const std::string &TripleStr)
- : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s")
+ : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true)
{
BigEndian = false;
SizeType = UnsignedInt;
@@ -2910,6 +3092,8 @@ public:
/// gcc.
ZeroLengthBitfieldBoundary = 32;
+ IsAAPCS = false;
+
if (IsThumb) {
// Thumb1 add sp, #imm requires the immediate value be multiple of 4,
// so set preferred for small types to 32.
@@ -2923,10 +3107,11 @@ public:
}
// FIXME: Override "preferred align" for double and long long.
- } else if (Name == "aapcs") {
+ } else if (Name == "aapcs" || Name == "aapcs-vfp") {
+ IsAAPCS = true;
// FIXME: Enumerated types are variable width in straight AAPCS.
} else if (Name == "aapcs-linux") {
- ;
+ IsAAPCS = true;
} else
return false;
@@ -2936,16 +3121,21 @@ public:
void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
- else if (CPU == "cortex-a8" || CPU == "cortex-a9")
+ else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
+ CPU == "cortex-a9" || CPU == "cortex-a9-mp")
+ Features["neon"] = true;
+ else if (CPU == "swift") {
+ Features["vfp4"] = true;
Features["neon"] = 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 == "neon" || Name == "d16" ||
- Name == "neonfp") {
+ Name == "vfp2" || Name == "vfp3" || Name == "vfp4" || Name == "neon" ||
+ Name == "d16" || Name == "neonfp") {
Features[Name] = Enabled;
} else
return false;
@@ -2954,7 +3144,7 @@ public:
}
virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
- FPU = NoFPU;
+ FPU = 0;
SoftFloat = SoftFloatABI = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
if (Features[i] == "+soft-float")
@@ -2962,11 +3152,13 @@ public:
else if (Features[i] == "+soft-float-abi")
SoftFloatABI = true;
else if (Features[i] == "+vfp2")
- FPU = VFP2FPU;
+ FPU |= VFP2FPU;
else if (Features[i] == "+vfp3")
- FPU = VFP3FPU;
+ FPU |= VFP3FPU;
+ else if (Features[i] == "+vfp4")
+ FPU |= VFP4FPU;
else if (Features[i] == "+neon")
- FPU = NeonFPU;
+ FPU |= NeonFPU;
}
// Remove front-end specific options which the backend handles differently.
@@ -2988,6 +3180,7 @@ public:
StringRef(getCPUDefineSuffix(CPU)).startswith("7"))
.Default(false);
}
+ // FIXME: Should we actually have some table instead of these switches?
static const char *getCPUDefineSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
.Cases("arm8", "arm810", "4")
@@ -3004,12 +3197,19 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a8", "cortex-a9", "7A")
- .Case("cortex-m3", "7M")
- .Case("cortex-m4", "7M")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "7A")
+ .Case("cortex-a9-mp", "7F")
+ .Case("swift", "7S")
+ .Cases("cortex-m3", "cortex-m4", "7M")
.Case("cortex-m0", "6M")
.Default(0);
}
+ static const char *getCPUProfile(StringRef Name) {
+ return llvm::StringSwitch<const char*>(Name)
+ .Cases("cortex-a8", "cortex-a9", "A")
+ .Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
+ .Default("");
+ }
virtual bool setCPU(const std::string &Name) {
if (!getCPUDefineSuffix(Name))
return false;
@@ -3030,7 +3230,11 @@ public:
StringRef CPUArch = getCPUDefineSuffix(CPU);
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
-
+ Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
+ StringRef CPUProfile = getCPUProfile(CPU);
+ if (!CPUProfile.empty())
+ Builder.defineMacro("__ARM_ARCH_PROFILE", CPUProfile);
+
// Subtarget options.
// FIXME: It's more complicated than this and we don't really support
@@ -3038,8 +3242,15 @@ public:
if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
Builder.defineMacro("__THUMB_INTERWORK__");
- if (ABI == "aapcs" || ABI == "aapcs-linux")
- Builder.defineMacro("__ARM_EABI__");
+ if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
+ // M-class CPUs on Darwin follow AAPCS, but not EABI.
+ if (!(getTriple().isOSDarwin() && CPUProfile == "M"))
+ Builder.defineMacro("__ARM_EABI__");
+ Builder.defineMacro("__ARM_PCS", "1");
+
+ if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp")
+ Builder.defineMacro("__ARM_PCS_VFP", "1");
+ }
if (SoftFloat)
Builder.defineMacro("__SOFTFP__");
@@ -3058,14 +3269,21 @@ public:
// Note, this is always on in gcc, even though it doesn't make sense.
Builder.defineMacro("__APCS_32__");
- if (FPUModeIsVFP((FPUMode) FPU))
+ if (FPUModeIsVFP((FPUMode) FPU)) {
Builder.defineMacro("__VFP_FP__");
-
+ if (FPU & VFP2FPU)
+ Builder.defineMacro("__ARM_VFPV2__");
+ if (FPU & VFP3FPU)
+ Builder.defineMacro("__ARM_VFPV3__");
+ if (FPU & VFP4FPU)
+ Builder.defineMacro("__ARM_VFPV4__");
+ }
+
// This only gets set when Neon instructions are actually available, unlike
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
- if (FPU == NeonFPU && !SoftFloat && IsARMv7)
+ if ((FPU & NeonFPU) && !SoftFloat && IsARMv7)
Builder.defineMacro("__ARM_NEON__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -3075,7 +3293,7 @@ public:
}
virtual bool isCLZForZeroUndef() const { return false; }
virtual BuiltinVaListKind getBuiltinVaListKind() const {
- return TargetInfo::VoidPtrBuiltinVaList;
+ return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList;
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
@@ -3127,10 +3345,38 @@ public:
}
return R;
}
+ virtual bool validateConstraintModifier(StringRef Constraint,
+ const char Modifier,
+ unsigned Size) const {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' ||
+ Constraint[0] == '+' ||
+ Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ switch (Constraint[0]) {
+ default: break;
+ case 'r': {
+ switch (Modifier) {
+ default:
+ return Size == 32;
+ case 'q':
+ // A register of size 32 cannot fit a vector type.
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
virtual const char *getClobbers() const {
// FIXME: Is this really right?
return "";
}
+
+ virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning;
+ }
};
const char * const ARMTargetInfo::GCCRegNames[] = {
@@ -3701,8 +3947,12 @@ public:
Features[CPU] = true;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
switch (FloatABI) {
case HardFloat:
Builder.defineMacro("__mips_hard_float", Twine(1));
@@ -3736,10 +3986,11 @@ public:
Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
+
+ Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
+ Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const = 0;
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
Records = BuiltinInfo;
@@ -3859,9 +4110,9 @@ public:
} else
return false;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- MipsTargetInfoBase::getArchDefines(Opts, Builder);
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getTargetDefines(Opts, Builder);
if (ABI == "o32") {
Builder.defineMacro("__mips_o32");
@@ -3921,12 +4172,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -3939,12 +4187,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -3974,9 +4219,12 @@ public:
return true;
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- MipsTargetInfoBase::getArchDefines(Opts, Builder);
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getTargetDefines(Opts, Builder);
+
+ Builder.defineMacro("__mips64");
+ Builder.defineMacro("__mips64__");
if (ABI == "n32") {
Builder.defineMacro("__mips_n32");
@@ -4048,12 +4296,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
@@ -4075,12 +4320,9 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
- Builder.defineMacro("_mips");
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- getArchDefines(Opts, Builder);
+ Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
}
};
} // end anonymous namespace.
@@ -4118,15 +4360,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
-
Builder.defineMacro("__LITTLE_ENDIAN__");
- Builder.defineMacro("__native_client__");
getArchDefines(Opts, Builder);
}
virtual bool hasFeature(StringRef Feature) const {
@@ -4199,6 +4433,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new BitrigTargetInfo<ARMTargetInfo>(T);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<ARMTargetInfo>(T);
+ case llvm::Triple::NativeClient:
+ return new NaClTargetInfo<ARMTargetInfo>(T);
default:
return new ARMTargetInfo(T);
}
@@ -4269,7 +4505,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::le32:
switch (os) {
case llvm::Triple::NativeClient:
- return new PNaClTargetInfo(T);
+ return new NaClTargetInfo<PNaClTargetInfo>(T);
default:
return NULL;
}
@@ -4316,6 +4552,9 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::mblaze:
return new MBlazeTargetInfo(T);
+ case llvm::Triple::r600:
+ return new R600TargetInfo(T);
+
case llvm::Triple::sparc:
switch (os) {
case llvm::Triple::Linux:
@@ -4374,6 +4613,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new HaikuX86_32TargetInfo(T);
case llvm::Triple::RTEMS:
return new RTEMSX86_32TargetInfo(T);
+ case llvm::Triple::NativeClient:
+ return new NaClTargetInfo<X86_32TargetInfo>(T);
default:
return new X86_32TargetInfo(T);
}
@@ -4403,6 +4644,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
return new VisualStudioWindowsX86_64TargetInfo(T);
+ case llvm::Triple::NativeClient:
+ return new NaClTargetInfo<X86_64TargetInfo>(T);
default:
return new X86_64TargetInfo(T);
}
@@ -4421,6 +4664,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Diags.Report(diag::err_target_unknown_triple) << Triple.str();
return 0;
}
+ Target->setTargetOpts(Opts);
// Set the target CPU if specified.
if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) {
@@ -4447,8 +4691,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Apply the user specified deltas.
// First the enables.
- for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
- ie = Opts.Features.end(); it != ie; ++it) {
+ 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] != '+')
@@ -4462,8 +4708,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
}
// Then the disables.
- for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
- ie = Opts.Features.end(); it != ie; ++it) {
+ 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] == '+')
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 9daa30a4cad0..286e96e0f376 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -32,7 +32,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/trunk/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_32/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 86f53803d527..da6d035dfaf0 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -16,7 +16,7 @@
namespace llvm {
class Value;
class LLVMContext;
- class TargetData;
+ class DataLayout;
}
namespace clang {
@@ -70,46 +70,52 @@ namespace clang {
private:
Kind TheKind;
llvm::Type *TypeData;
- llvm::Type *PaddingType; // Currently allowed only for Direct.
+ 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,
- llvm::Type* P)
+ bool PIR, llvm::Type* P)
: TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
- BoolData1(B1), InReg(IR) {}
+ 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, Padding);
+ return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding);
}
- static ABIArgInfo getDirectInReg(llvm::Type *T) {
- return ABIArgInfo(Direct, T, 0, false, false, true, 0);
+ 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, 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, 0);
+ return ABIArgInfo(Extend, T, 0, false, false, true, false, 0);
}
static ABIArgInfo getIgnore() {
- return ABIArgInfo(Ignore, 0, 0, false, false, false, 0);
+ return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, 0);
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0);
}
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0);
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
}
static ABIArgInfo getExpand() {
- return ABIArgInfo(Expand, 0, 0, false, false, false, 0);
+ 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; }
@@ -133,6 +139,10 @@ namespace clang {
return PaddingType;
}
+ bool getPaddingInReg() const {
+ return PaddingInReg;
+ }
+
llvm::Type *getCoerceToType() const {
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
@@ -178,7 +188,7 @@ namespace clang {
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
- const llvm::TargetData &getTargetData() const;
+ const llvm::DataLayout &getDataLayout() const;
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 0a1915b485d7..62f87c983bfa 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -27,7 +27,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -54,36 +54,67 @@ class EmitAssemblyHelper {
mutable FunctionPassManager *PerFunctionPasses;
private:
- PassManager *getCodeGenPasses() const {
+ PassManager *getCodeGenPasses(TargetMachine *TM) const {
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
- CodeGenPasses->add(new TargetData(TheModule));
+ CodeGenPasses->add(new DataLayout(TheModule));
+ // Add TargetTransformInfo.
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ CodeGenPasses->add(TTI);
+ }
}
return CodeGenPasses;
}
- PassManager *getPerModulePasses() const {
+ PassManager *getPerModulePasses(TargetMachine *TM) const {
if (!PerModulePasses) {
PerModulePasses = new PassManager();
- PerModulePasses->add(new TargetData(TheModule));
+ PerModulePasses->add(new DataLayout(TheModule));
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ PerModulePasses->add(TTI);
+ }
}
return PerModulePasses;
}
- FunctionPassManager *getPerFunctionPasses() const {
+ FunctionPassManager *getPerFunctionPasses(TargetMachine *TM) const {
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
- PerFunctionPasses->add(new TargetData(TheModule));
+ PerFunctionPasses->add(new DataLayout(TheModule));
+ if (TM) {
+ TargetTransformInfo *TTI =
+ new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo());
+ PerFunctionPasses->add(TTI);
+ }
}
return PerFunctionPasses;
}
- void CreatePasses();
+
+ void CreatePasses(TargetMachine *TM);
+
+ /// CreateTargetMachine - Generates the TargetMachine.
+ /// Returns Null if it is unable to create the target machine.
+ /// Some of our clang tests specify triples which are not built
+ /// into clang. This is okay because these tests check the generated
+ /// IR, and they require DataLayout which depends on the triple.
+ /// In this case, we allow this method to fail and not report an error.
+ /// When MustCreateTM is used, we print an error if we are unable to load
+ /// the requested target.
+ TargetMachine *CreateTargetMachine(bool MustCreateTM);
/// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
///
/// \return True on success.
- bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS);
+ bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS,
+ TargetMachine *TM);
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
@@ -137,9 +168,9 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PM.add(createThreadSanitizerPass());
}
-void EmitAssemblyHelper::CreatePasses() {
+void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
- CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
+ CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining();
// Handle disabling of LLVM optimization, where we want to preserve the
// internal module before any optimization.
@@ -174,14 +205,14 @@ void EmitAssemblyHelper::CreatePasses() {
addBoundsCheckingPass);
}
- if (LangOpts.AddressSanitizer) {
- PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
+ if (LangOpts.SanitizeAddress) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addAddressSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addAddressSanitizerPass);
}
- if (LangOpts.ThreadSanitizer) {
+ if (LangOpts.SanitizeThread) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -218,38 +249,36 @@ void EmitAssemblyHelper::CreatePasses() {
break;
}
-
// Set up the per-function pass manager.
- FunctionPassManager *FPM = getPerFunctionPasses();
+ FunctionPassManager *FPM = getPerFunctionPasses(TM);
if (CodeGenOpts.VerifyModule)
FPM->add(createVerifierPass());
PMBuilder.populateFunctionPassManager(*FPM);
// Set up the per-module pass manager.
- PassManager *MPM = getPerModulePasses();
+ PassManager *MPM = getPerModulePasses(TM);
if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
CodeGenOpts.EmitGcovArcs,
TargetTriple.isMacOSX()));
- if (CodeGenOpts.DebugInfo == CodeGenOptions::NoDebugInfo)
+ if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
}
-
-
+
PMBuilder.populateModulePassManager(*MPM);
}
-bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
- formatted_raw_ostream &OS) {
+TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
// Create the TargetMachine for generating code.
std::string Error;
std::string Triple = TheModule->getTargetTriple();
const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
if (!TheTarget) {
- Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return false;
+ if (MustCreateTM)
+ Diags.Report(diag::err_fe_unable_to_create_target) << Error;
+ return 0;
}
// FIXME: Expose these capabilities via actual APIs!!!! Aside from just
@@ -361,7 +390,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
break;
case LangOptions::FPC_Fast:
Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
- break;
+ break;
}
Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD;
@@ -375,6 +404,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
+ Options.SSPBufferSize = CodeGenOpts.SSPBufferSize;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
@@ -391,15 +421,27 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
if (CodeGenOpts.NoExecStack)
TM->setMCNoExecStack(true);
+ return TM;
+}
+
+bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
+ formatted_raw_ostream &OS,
+ TargetMachine *TM) {
+
// Create the code generator passes.
- PassManager *PM = getCodeGenPasses();
+ PassManager *PM = getCodeGenPasses(TM);
// Add LibraryInfo.
- TargetLibraryInfo *TLI = new TargetLibraryInfo();
+ llvm::Triple TargetTriple(TheModule->getTargetTriple());
+ TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
TLI->disableAllFunctions();
PM->add(TLI);
+ // Add TargetTransformInfo.
+ PM->add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
+ TM->getVectorTargetTransformInfo()));
+
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
@@ -430,23 +472,28 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);
llvm::formatted_raw_ostream FormattedOS;
- CreatePasses();
+ bool UsesCodeGen = (Action != Backend_EmitNothing &&
+ Action != Backend_EmitBC &&
+ Action != Backend_EmitLL);
+ TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
+ CreatePasses(TM);
+
switch (Action) {
case Backend_EmitNothing:
break;
case Backend_EmitBC:
- getPerModulePasses()->add(createBitcodeWriterPass(*OS));
+ getPerModulePasses(TM)->add(createBitcodeWriterPass(*OS));
break;
case Backend_EmitLL:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- getPerModulePasses()->add(createPrintModulePass(&FormattedOS));
+ getPerModulePasses(TM)->add(createPrintModulePass(&FormattedOS));
break;
default:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- if (!AddEmitPasses(Action, FormattedOS))
+ if (!AddEmitPasses(Action, FormattedOS, TM))
return;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 37ef4af24690..6742f36cf80f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <algorithm>
using namespace clang;
@@ -27,7 +27,8 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), StructureType(0), Block(block),
+ HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
+ StructureType(0), Block(block),
DominatingIP(0) {
// Skip asm prefix, if any. 'name' is usually taken directly from
@@ -56,7 +57,18 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
}
-/// Build the block descriptor constant for a block.
+/// buildBlockDescriptor - Build the block descriptor meta-data for a block.
+/// 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.
+/// 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_layout_info; // encoding of captured block variables.
+/// };
static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
ASTContext &C = CGM.getContext();
@@ -92,8 +104,12 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
CGM.GetAddrOfConstantCString(typeAtEncoding), i8p));
// GC layout.
- if (C.getLangOpts().ObjC1)
- elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ if (C.getLangOpts().ObjC1) {
+ if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
+ elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
+ else
+ elements.push_back(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo));
+ }
else
elements.push_back(llvm::Constant::getNullValue(i8p));
@@ -293,7 +309,10 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
info.CanBeGlobal = true;
return;
}
-
+ else if (C.getLangOpts().ObjC1 &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC)
+ info.HasCapturedVariableLayout = true;
+
// Collect the layout chunks.
SmallVector<BlockLayoutChunk, 16> layout;
layout.reserve(block->capturesCXXThis() +
@@ -652,6 +671,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// Compute the initial on-stack block flags.
BlockFlags flags = BLOCK_HAS_SIGNATURE;
+ if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT;
if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
@@ -1001,8 +1021,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
// Check if we should generate debug info for this block function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
CurGD = GD;
BlockInfo = &blockInfo;
@@ -1135,7 +1154,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const VarDecl *variable = ci->getVariable();
DI->EmitLocation(Builder, variable->getLocation());
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) {
DI->EmitDeclareOfAutoVariable(variable, LocalDeclMap[variable],
@@ -1207,8 +1227,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
= &CGM.getContext().Idents.get("__copy_helper_block_");
// Check if we should generate debug info for this block helper function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
@@ -1243,7 +1262,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
const Expr *copyExpr = ci->getCopyExpr();
BlockFieldFlags flags;
- bool isARCWeakCapture = false;
+ bool useARCWeakCopy = false;
+ bool useARCStrongCopy = false;
if (copyExpr) {
assert(!ci->isByRef());
@@ -1256,21 +1276,35 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
} else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
- if (type->isBlockPointerType())
+ bool isBlockPointer = type->isBlockPointerType();
+ if (isBlockPointer)
flags = BLOCK_FIELD_IS_BLOCK;
// Special rules for ARC captures:
if (getLangOpts().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
- // Don't generate special copy logic for a captured object
- // unless it's __strong or __weak.
- if (!qs.hasStrongOrWeakObjCLifetime())
+ // We need to register __weak direct captures with the runtime.
+ if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ useARCWeakCopy = true;
+
+ // We need to retain the copied value for __strong direct captures.
+ } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // If it's a block pointer, we have to copy the block and
+ // assign that to the destination pointer, so we might as
+ // well use _Block_object_assign. Otherwise we can avoid that.
+ if (!isBlockPointer)
+ useARCStrongCopy = true;
+
+ // Otherwise the memcpy is fine.
+ } else {
continue;
+ }
- // Support __weak direct captures.
- if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
- isARCWeakCapture = true;
+ // Non-ARC captures of retainable pointers are strong and
+ // therefore require a call to _Block_object_assign.
+ } else {
+ // fall through
}
} else {
continue;
@@ -1283,14 +1317,36 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// If there's an explicit copy expression, we do that.
if (copyExpr) {
EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
- } else if (isARCWeakCapture) {
+ } else if (useARCWeakCopy) {
EmitARCCopyWeak(dstField, srcField);
} else {
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
- srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
- llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
- Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ if (useARCStrongCopy) {
+ // At -O0, store null into the destination field (so that the
+ // storeStrong doesn't over-release) and then call storeStrong.
+ // This is a workaround to not having an initStrong call.
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::PointerType *ty = cast<llvm::PointerType>(srcValue->getType());
+ llvm::Value *null = llvm::ConstantPointerNull::get(ty);
+ Builder.CreateStore(null, dstField);
+ EmitARCStoreStrongCall(dstField, srcValue, true);
+
+ // With optimization enabled, take advantage of the fact that
+ // the blocks runtime guarantees a memcpy of the block data, and
+ // just emit a retain of the src field.
+ } else {
+ EmitARCRetainNonBlock(srcValue);
+
+ // We don't need this anymore, so kill it. It's not quite
+ // worth the annoyance to avoid creating it in the first place.
+ cast<llvm::Instruction>(dstField)->eraseFromParent();
+ }
+ } else {
+ srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
+ llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
+ Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
+ llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ }
}
}
@@ -1321,8 +1377,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
"__destroy_helper_block_", &CGM.getModule());
// Check if we should generate debug info for this block destroy function.
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
+ maybeInitializeDebugInfo();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1356,7 +1411,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
BlockFieldFlags flags;
const CXXDestructorDecl *dtor = 0;
- bool isARCWeakCapture = false;
+ bool useARCWeakDestroy = false;
+ bool useARCStrongDestroy = false;
if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
@@ -1382,7 +1438,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// Support __weak direct captures.
if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
- isARCWeakCapture = true;
+ useARCWeakDestroy = true;
+
+ // Tools really want us to use objc_storeStrong here.
+ else
+ useARCStrongDestroy = true;
}
} else {
continue;
@@ -1396,9 +1456,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
PushDestructorCleanup(dtor, srcField);
// If this is a __weak capture, emit the release directly.
- } else if (isARCWeakCapture) {
+ } else if (useARCWeakDestroy) {
EmitARCDestroyWeak(srcField);
+ // Destroy strong objects with a call if requested.
+ } else if (useARCStrongDestroy) {
+ EmitARCDestroyStrong(srcField, /*precise*/ false);
+
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
// that things were done in reverse.
@@ -1497,10 +1561,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
- value->setAlignment(Alignment.getQuantity());
-
- CGF.EmitARCRelease(value, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, /*precise*/ false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1530,10 +1591,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
- value->setAlignment(Alignment.getQuantity());
-
- CGF.EmitARCRelease(value, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, /*precise*/ false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1612,6 +1670,8 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_None,
false, false);
+ // Initialize debug info if necessary.
+ CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@@ -1682,6 +1742,8 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SC_Static,
SC_None,
false, false);
+ // Initialize debug info if necessary.
+ CGF.maybeInitializeDebugInfo();
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsDispose()) {
@@ -1879,7 +1941,7 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// And either 2 or 4 pointers.
CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
- CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
+ CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
// Align the offset.
unsigned AlignedOffsetInBytes =
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 095cfdb259c3..f85701af781a 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -33,7 +33,7 @@ namespace llvm {
class Constant;
class Function;
class GlobalValue;
- class TargetData;
+ class DataLayout;
class FunctionType;
class PointerType;
class Value;
@@ -47,12 +47,24 @@ namespace CodeGen {
class CodeGenModule;
class CGBlockInfo;
-enum BlockFlag_t {
+// Flags stored in __block variables.
+enum BlockByrefFlags {
+ BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler
+ BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler
+ BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),
+ BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28),
+ BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),
+ BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),
+ BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28)
+};
+
+enum BlockLiteralFlags {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_USE_STRET = (1 << 29),
- BLOCK_HAS_SIGNATURE = (1 << 30)
+ BLOCK_HAS_SIGNATURE = (1 << 30),
+ BLOCK_HAS_EXTENDED_LAYOUT = (1 << 31)
};
class BlockFlags {
uint32_t flags;
@@ -60,7 +72,7 @@ class BlockFlags {
BlockFlags(uint32_t flags) : flags(flags) {}
public:
BlockFlags() : flags(0) {}
- BlockFlags(BlockFlag_t flag) : flags(flag) {}
+ BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
@@ -76,7 +88,7 @@ public:
return (l.flags & r.flags);
}
};
-inline BlockFlags operator|(BlockFlag_t l, BlockFlag_t r) {
+inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
return BlockFlags(l) | BlockFlags(r);
}
@@ -182,6 +194,10 @@ public:
/// UsesStret : True if the block uses an stret return. Mutable
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
+
+ /// HasCapturedVariableLayout : True if block has captured variables
+ /// and their layout meta-data has been generated.
+ bool HasCapturedVariableLayout : 1;
/// The mapping of allocated indexes within the block.
llvm::DenseMap<const VarDecl*, Capture> Captures;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 59ed31361616..e8c05d3a46d0 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -20,7 +20,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -86,8 +86,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF,
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
@@ -121,8 +120,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
llvm::IntegerType *IntType =
llvm::IntegerType::get(CGF.getLLVMContext(),
@@ -148,7 +146,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>();
assert(ValTyP && "isn't scalar fp type!");
-
+
StringRef FnName;
switch (ValTyP->getKind()) {
default: llvm_unreachable("Isn't a scalar fp type!");
@@ -156,7 +154,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
case BuiltinType::Double: FnName = "fabs"; break;
case BuiltinType::LongDouble: FnName = "fabsl"; break;
}
-
+
// The prototype is something that takes and returns whatever V's type is.
llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
false);
@@ -214,7 +212,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
DstPtr, SrcPtr));
}
- case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
@@ -229,18 +227,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
-
+
case Builtin::BI__builtin_conj:
case Builtin::BI__builtin_conjf:
case Builtin::BI__builtin_conjl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
Value *Real = ComplexVal.first;
Value *Imag = ComplexVal.second;
- Value *Zero =
- Imag->getType()->isFPOrFPVectorTy()
+ Value *Zero =
+ Imag->getType()->isFPOrFPVectorTy()
? llvm::ConstantFP::getZeroValueForNegation(Imag->getType())
: llvm::Constant::getNullValue(Imag->getType());
-
+
Imag = Builder.CreateFSub(Zero, Imag, "sub");
return RValue::getComplex(std::make_pair(Real, Imag));
}
@@ -250,14 +248,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.first);
}
-
+
case Builtin::BI__builtin_cimag:
case Builtin::BI__builtin_cimagf:
case Builtin::BI__builtin_cimagl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.second);
}
-
+
case Builtin::BI__builtin_ctzs:
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
@@ -356,6 +354,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
"expval");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
@@ -371,15 +370,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
llvm::Type *ResType = ConvertType(E->getType());
-
+
// LLVM only supports 0 and 2, make sure that we pass along that
// as a boolean.
Value *Ty = EmitScalarExpr(E->getArg(1));
ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
assert(CI);
uint64_t val = CI->getZExtValue();
- CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
-
+ CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
+
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType);
return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)),CI));
}
@@ -402,9 +401,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::trap);
return RValue::get(Builder.CreateCall(F));
}
+ case Builtin::BI__debugbreak: {
+ Value *F = CGM.getIntrinsic(Intrinsic::debugtrap);
+ return RValue::get(Builder.CreateCall(F));
+ }
case Builtin::BI__builtin_unreachable: {
- if (CatchUndefined)
- EmitBranch(getTrapBB());
+ if (getLangOpts().SanitizeUnreachable)
+ EmitCheck(Builder.getFalse(), "builtin_unreachable",
+ EmitCheckSourceLocation(E->getExprLoc()),
+ llvm::ArrayRef<llvm::Value *>());
else
Builder.CreateUnreachable();
@@ -413,7 +418,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(0);
}
-
+
case Builtin::BI__builtin_powi:
case Builtin::BI__builtin_powif:
case Builtin::BI__builtin_powil: {
@@ -464,16 +469,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
V = Builder.CreateFCmpUNO(V, V, "cmp");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
-
+
case Builtin::BI__builtin_isinf: {
// isinf(x) --> fabs(x) == infinity
Value *V = EmitScalarExpr(E->getArg(0));
V = EmitFAbs(*this, V, E->getArg(0)->getType());
-
+
V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
-
+
// TODO: BI__builtin_isinf_sign
// isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0
@@ -499,11 +504,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// isfinite(x) --> x == x && fabs(x) != infinity;
Value *V = EmitScalarExpr(E->getArg(0));
Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq");
-
+
Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType());
Value *IsNotInf =
Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf");
-
+
V = Builder.CreateAnd(Eq, IsNotInf, "and");
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
@@ -565,7 +570,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.SetInsertPoint(End);
return RValue::get(Result);
}
-
+
case Builtin::BIalloca:
case Builtin::BI__builtin_alloca: {
Value *Size = EmitScalarExpr(E->getArg(0));
@@ -573,85 +578,90 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *SizeVal = EmitScalarExpr(E->getArg(1));
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, Builder.getInt8(0), SizeVal, Align, false);
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, Builder.getInt8(0), SizeVal,
+ Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemcpy:
case Builtin::BI__builtin_memcpy: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *SrcAddr = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemCpy(Address, SrcAddr, SizeVal, Align, false);
- return RValue::get(Address);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
-
+
case Builtin::BI__builtin___memcpy_chk: {
- // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2.
llvm::APSInt Size, DstSize;
if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
!E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
if (Size.ugt(DstSize))
break;
- Value *Dest = EmitScalarExpr(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemCpy(Dest, Src, SizeVal, Align, false);
- return RValue::get(Dest);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
-
+
case Builtin::BI__builtin_objc_memmove_collectable: {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
+ CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this,
Address, SrcAddr, SizeVal);
return RValue::get(Address);
}
case Builtin::BI__builtin___memmove_chk: {
- // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ // fold __builtin_memmove_chk(x, y, cst1, cst2) to memmove iff cst1<=cst2.
llvm::APSInt Size, DstSize;
if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) ||
!E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext()))
break;
if (Size.ugt(DstSize))
break;
- Value *Dest = EmitScalarExpr(E->getArg(0));
- Value *Src = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemMove(Dest, Src, SizeVal, Align, false);
- return RValue::get(Dest);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove: {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *SrcAddr = EmitScalarExpr(E->getArg(1));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Src =
+ EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
- GetPointeeAlignment(E->getArg(1)));
- Builder.CreateMemMove(Address, SrcAddr, SizeVal, Align, false);
- return RValue::get(Address);
+ unsigned Align = std::min(Dest.second, Src.second);
+ Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
+ return RValue::get(Dest.first);
}
case Builtin::BImemset:
case Builtin::BI__builtin_memset: {
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BI__builtin___memset_chk: {
// fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
@@ -661,14 +671,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
if (Size.ugt(DstSize))
break;
- Value *Address = EmitScalarExpr(E->getArg(0));
+ std::pair<llvm::Value*, unsigned> Dest =
+ EmitPointerWithAlignment(E->getArg(0));
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- unsigned Align = GetPointeeAlignment(E->getArg(0));
- Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
-
- return RValue::get(Address);
+ Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
+ return RValue::get(Dest.first);
}
case Builtin::BI__builtin_dwarf_cfa: {
// The offset in bytes from the first argument to the CFA.
@@ -682,7 +691,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
int32_t Offset = 0;
Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa);
- return RValue::get(Builder.CreateCall(F,
+ return RValue::get(Builder.CreateCall(F,
llvm::ConstantInt::get(Int32Ty, Offset)));
}
case Builtin::BI__builtin_return_address: {
@@ -907,9 +916,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_val_compare_and_swap_16: {
QualType T = E->getType();
llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
-
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
+
llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
@@ -935,9 +943,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_bool_compare_and_swap_16: {
QualType T = E->getArg(1)->getType();
llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace();
-
+ unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace();
+
llvm::IntegerType *IntType =
llvm::IntegerType::get(getLLVMContext(),
getContext().getTypeSize(T));
@@ -982,7 +989,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
StoreSize.getQuantity() * 8);
Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
- llvm::StoreInst *Store =
+ llvm::StoreInst *Store =
Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr);
Store->setAlignment(StoreSize.getQuantity());
Store->setAtomic(llvm::Release);
@@ -993,7 +1000,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We assume this is supposed to correspond to a C++0x-style
// sequentially-consistent fence (i.e. this is only usable for
// synchonization, not device I/O or anything like that). This intrinsic
- // is really badly designed in the sense that in theory, there isn't
+ // is really badly designed in the sense that in theory, there isn't
// any way to safely use it... but in practice, it mostly works
// to use it with non-atomic loads and stores to get acquire/release
// semantics.
@@ -1033,8 +1040,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
Value *Ptr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
Value *NewVal = Builder.getInt8(1);
Value *Order = EmitScalarExpr(E->getArg(1));
@@ -1120,8 +1126,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
Value *Ptr = EmitScalarExpr(E->getArg(0));
- unsigned AddrSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace();
Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
Value *NewVal = Builder.getInt8(0);
Value *Order = EmitScalarExpr(E->getArg(1));
@@ -1310,6 +1315,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__noop:
+ return RValue::get(0);
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -1318,7 +1325,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
return emitLibraryCall(*this, FD, E,
CGM.getBuiltinLibFunction(FD, BuiltinID));
-
+
// If this is a predefined lib function (e.g. malloc), emit the call
// using exactly the normal call path.
if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -1350,7 +1357,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
if ((ICEArguments & (1 << i)) == 0) {
ArgValue = EmitScalarExpr(E->getArg(i));
} else {
- // If this is required to be a constant, constant fold it so that we
+ // If this is required to be a constant, constant fold it so that we
// know that the generated intrinsic gets a ConstantInt.
llvm::APSInt Result;
bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result,getContext());
@@ -1375,7 +1382,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
QualType BuiltinRetType = E->getType();
llvm::Type *RetTy = VoidTy;
- if (!BuiltinRetType->isVoidType())
+ if (!BuiltinRetType->isVoidType())
RetTy = ConvertType(BuiltinRetType);
if (RetTy != V->getType()) {
@@ -1457,10 +1464,10 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
return Builder.CreateCall(F, Ops, name);
}
-Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
+Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
bool neg) {
int SV = cast<ConstantInt>(V)->getSExtValue();
-
+
llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV);
return llvm::ConstantVector::getSplat(VTy->getNumElements(), C);
@@ -1469,34 +1476,56 @@ Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
/// GetPointeeAlignment - Given an expression with a pointer type, find the
/// alignment of the type referenced by the pointer. Skip over implicit
/// casts.
-unsigned CodeGenFunction::GetPointeeAlignment(const Expr *Addr) {
- unsigned Align = 1;
- // Check if the type is a pointer. The implicit cast operand might not be.
- while (Addr->getType()->isPointerType()) {
- QualType PtTy = Addr->getType()->getPointeeType();
-
- // Can't get alignment of incomplete types.
- if (!PtTy->isIncompleteType()) {
- unsigned NewA = getContext().getTypeAlignInChars(PtTy).getQuantity();
- if (NewA > Align)
- Align = NewA;
+std::pair<llvm::Value*, unsigned>
+CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) {
+ assert(Addr->getType()->isPointerType());
+ Addr = Addr->IgnoreParens();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Addr)) {
+ if ((ICE->getCastKind() == CK_BitCast || ICE->getCastKind() == CK_NoOp) &&
+ ICE->getSubExpr()->getType()->isPointerType()) {
+ std::pair<llvm::Value*, unsigned> Ptr =
+ EmitPointerWithAlignment(ICE->getSubExpr());
+ Ptr.first = Builder.CreateBitCast(Ptr.first,
+ ConvertType(Addr->getType()));
+ return Ptr;
+ } else if (ICE->getCastKind() == CK_ArrayToPointerDecay) {
+ LValue LV = EmitLValue(ICE->getSubExpr());
+ unsigned Align = LV.getAlignment().getQuantity();
+ if (!Align) {
+ // FIXME: Once LValues are fixed to always set alignment,
+ // zap this code.
+ QualType PtTy = ICE->getSubExpr()->getType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+ else
+ Align = 1;
+ }
+ return std::make_pair(LV.getAddress(), Align);
}
-
- // If the address is an implicit cast, repeat with the cast operand.
- if (const ImplicitCastExpr *CastAddr = dyn_cast<ImplicitCastExpr>(Addr)) {
- Addr = CastAddr->getSubExpr();
- continue;
+ }
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Addr)) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ LValue LV = EmitLValue(UO->getSubExpr());
+ unsigned Align = LV.getAlignment().getQuantity();
+ if (!Align) {
+ // FIXME: Once LValues are fixed to always set alignment,
+ // zap this code.
+ QualType PtTy = UO->getSubExpr()->getType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+ else
+ Align = 1;
+ }
+ return std::make_pair(LV.getAddress(), Align);
}
- break;
}
- return Align;
-}
-/// GetPointeeAlignmentValue - Given an expression with a pointer type, find
-/// the alignment of the type referenced by the pointer. Skip over implicit
-/// casts. Return the alignment as an llvm::Value.
-Value *CodeGenFunction::GetPointeeAlignmentValue(const Expr *Addr) {
- return llvm::ConstantInt::get(Int32Ty, GetPointeeAlignment(Addr));
+ unsigned Align = 1;
+ QualType PtTy = Addr->getType()->getPointeeType();
+ if (!PtTy->isIncompleteType())
+ Align = getContext().getTypeAlignInChars(PtTy).getQuantity();
+
+ return std::make_pair(EmitScalarExpr(Addr), Align);
}
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
@@ -1549,8 +1578,69 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
SmallVector<Value*, 4> Ops;
- for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
+ llvm::Value *Align = 0;
+ for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
+ if (i == 0) {
+ switch (BuiltinID) {
+ case ARM::BI__builtin_neon_vld1_v:
+ case ARM::BI__builtin_neon_vld1q_v:
+ case ARM::BI__builtin_neon_vld1q_lane_v:
+ case ARM::BI__builtin_neon_vld1_lane_v:
+ case ARM::BI__builtin_neon_vld1_dup_v:
+ case ARM::BI__builtin_neon_vld1q_dup_v:
+ case ARM::BI__builtin_neon_vst1_v:
+ case ARM::BI__builtin_neon_vst1q_v:
+ case ARM::BI__builtin_neon_vst1q_lane_v:
+ case ARM::BI__builtin_neon_vst1_lane_v:
+ case ARM::BI__builtin_neon_vst2_v:
+ case ARM::BI__builtin_neon_vst2q_v:
+ case ARM::BI__builtin_neon_vst2_lane_v:
+ case ARM::BI__builtin_neon_vst2q_lane_v:
+ case ARM::BI__builtin_neon_vst3_v:
+ case ARM::BI__builtin_neon_vst3q_v:
+ case ARM::BI__builtin_neon_vst3_lane_v:
+ case ARM::BI__builtin_neon_vst3q_lane_v:
+ case ARM::BI__builtin_neon_vst4_v:
+ case ARM::BI__builtin_neon_vst4q_v:
+ case ARM::BI__builtin_neon_vst4_lane_v:
+ case ARM::BI__builtin_neon_vst4q_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 ARM::BI__builtin_neon_vld2_v:
+ case ARM::BI__builtin_neon_vld2q_v:
+ case ARM::BI__builtin_neon_vld3_v:
+ case ARM::BI__builtin_neon_vld3q_v:
+ case ARM::BI__builtin_neon_vld4_v:
+ case ARM::BI__builtin_neon_vld4q_v:
+ case ARM::BI__builtin_neon_vld2_lane_v:
+ case ARM::BI__builtin_neon_vld2q_lane_v:
+ case ARM::BI__builtin_neon_vld3_lane_v:
+ case ARM::BI__builtin_neon_vld3q_lane_v:
+ case ARM::BI__builtin_neon_vld4_lane_v:
+ case ARM::BI__builtin_neon_vld4q_lane_v:
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ case ARM::BI__builtin_neon_vld3_dup_v:
+ case ARM::BI__builtin_neon_vld4_dup_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)));
+ }
// vget_lane and vset_lane are not overloaded and do not have an extra
// argument that specifies the vector type.
@@ -1596,7 +1686,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = FloatTy;
else
Ty = DoubleTy;
-
+
// Determine whether this is an unsigned conversion or not.
bool usgn = Result.getZExtValue() == 1;
unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr;
@@ -1605,7 +1695,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Int, Ty);
return Builder.CreateCall(F, Ops, "vcvtr");
}
-
+
// Determine the type of this overloaded NEON intrinsic.
NeonTypeFlags Type(Result.getZExtValue());
bool usgn = Type.isUnsigned();
@@ -1620,6 +1710,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
unsigned Int;
switch (BuiltinID) {
default: return 0;
+ case ARM::BI__builtin_neon_vbsl_v:
+ case ARM::BI__builtin_neon_vbslq_v:
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty),
+ Ops, "vbsl");
case ARM::BI__builtin_neon_vabd_v:
case ARM::BI__builtin_neon_vabdq_v:
Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds;
@@ -1690,7 +1784,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vcvtq_f32_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
+ return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
case ARM::BI__builtin_neon_vcvt_s32_v:
case ARM::BI__builtin_neon_vcvt_u32_v:
@@ -1699,7 +1793,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *FloatTy =
GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
- return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
+ return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
: Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
}
case ARM::BI__builtin_neon_vcvt_n_f32_v:
@@ -1730,7 +1824,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
Indices.push_back(ConstantInt::get(Int32Ty, i+CV));
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Value *SV = llvm::ConstantVector::get(Indices);
@@ -1746,7 +1840,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhsub");
case ARM::BI__builtin_neon_vld1_v:
case ARM::BI__builtin_neon_vld1q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty),
Ops, "vld1");
case ARM::BI__builtin_neon_vld1q_lane_v:
@@ -1761,8 +1855,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Load the value as a one-element vector.
Ty = llvm::VectorType::get(VTy->getElementType(), 1);
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty);
- Value *Ld = Builder.CreateCall2(F, Ops[0],
- GetPointeeAlignmentValue(E->getArg(0)));
+ Value *Ld = Builder.CreateCall2(F, Ops[0], Align);
// Combine them.
SmallVector<Constant*, 2> Indices;
Indices.push_back(ConstantInt::get(Int32Ty, 1-Lane));
@@ -1776,7 +1869,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
LoadInst *Ld = Builder.CreateLoad(Ops[0]);
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
}
@@ -1786,7 +1878,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
LoadInst *Ld = Builder.CreateLoad(Ops[0]);
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
@@ -1795,7 +1886,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld2_v:
case ARM::BI__builtin_neon_vld2q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1804,7 +1894,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld3_v:
case ARM::BI__builtin_neon_vld3q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1813,7 +1902,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld4_v:
case ARM::BI__builtin_neon_vld4q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1824,7 +1912,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1836,7 +1924,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1849,7 +1937,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateBitCast(Ops[5], Ty);
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
+ Ops.push_back(Align);
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1861,47 +1949,46 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Handle 64-bit elements as a special-case. There is no "dup" needed.
if (VTy->getElementType()->getPrimitiveSizeInBits() == 64) {
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_dup_v:
- Int = Intrinsic::arm_neon_vld2;
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ Int = Intrinsic::arm_neon_vld2;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld3;
+ Int = Intrinsic::arm_neon_vld3;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld4;
+ Int = Intrinsic::arm_neon_vld4;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
- Value *Align = GetPointeeAlignmentValue(E->getArg(1));
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 ARM::BI__builtin_neon_vld2_dup_v:
- Int = Intrinsic::arm_neon_vld2lane;
+ case ARM::BI__builtin_neon_vld2_dup_v:
+ Int = Intrinsic::arm_neon_vld2lane;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld3lane;
+ Int = Intrinsic::arm_neon_vld3lane;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld4lane;
+ Int = Intrinsic::arm_neon_vld4lane;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
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(GetPointeeAlignmentValue(E->getArg(1)));
-
+ 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) {
@@ -1944,6 +2031,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
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");
+ case ARM::BI__builtin_neon_vfma_v:
+ case ARM::BI__builtin_neon_vfmaq_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);
+ return Builder.CreateCall3(F, Ops[0], Ops[1], Ops[2]);
+ }
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
@@ -2016,7 +2111,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = usgn ? Intrinsic::arm_neon_vqrshiftu : Intrinsic::arm_neon_vqrshifts;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshl");
case ARM::BI__builtin_neon_vqrshrn_n_v:
- Int = usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
+ Int =
+ usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n",
1, true);
case ARM::BI__builtin_neon_vqrshrun_n_v:
@@ -2086,7 +2182,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, true);
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
- Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
+ Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
case ARM::BI__builtin_neon_vrsubhn_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty),
@@ -2101,7 +2197,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vshl_n_v:
case ARM::BI__builtin_neon_vshlq_n_v:
Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false);
- return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1], "vshl_n");
+ return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1],
+ "vshl_n");
case ARM::BI__builtin_neon_vshrn_n_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftn, Ty),
Ops, "vshrn_n", 1, true);
@@ -2133,7 +2230,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateAdd(Ops[0], Ops[1]);
case ARM::BI__builtin_neon_vst1_v:
case ARM::BI__builtin_neon_vst1q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst1q_lane_v:
@@ -2143,7 +2240,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Value *SV = llvm::ConstantVector::get(cast<llvm::Constant>(Ops[2]));
Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV);
- Ops[2] = GetPointeeAlignmentValue(E->getArg(0));
+ Ops[2] = Align;
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1,
Ops[1]->getType()), Ops);
}
@@ -2154,38 +2251,37 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
StoreInst *St = Builder.CreateStore(Ops[1],
Builder.CreateBitCast(Ops[0], Ty));
- Value *Align = GetPointeeAlignmentValue(E->getArg(0));
St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return St;
}
case ARM::BI__builtin_neon_vst2_v:
case ARM::BI__builtin_neon_vst2q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst2_lane_v:
case ARM::BI__builtin_neon_vst2q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_v:
case ARM::BI__builtin_neon_vst3q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_lane_v:
case ARM::BI__builtin_neon_vst3q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_v:
case ARM::BI__builtin_neon_vst4q_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_lane_v:
case ARM::BI__builtin_neon_vst4q_lane_v:
- Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
+ Ops.push_back(Align);
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vsubhn_v:
@@ -2220,7 +2316,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
- Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
+ Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
ConstantAggregateZero::get(Ty));
return Builder.CreateSExt(Ops[0], Ty, "vtst");
}
@@ -2250,7 +2346,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Value *SV = 0;
-
+
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
@@ -2263,13 +2359,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
return SV;
}
- case ARM::BI__builtin_neon_vzip_v:
+ case ARM::BI__builtin_neon_vzip_v:
case ARM::BI__builtin_neon_vzipq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Value *SV = 0;
-
+
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
@@ -2382,62 +2478,62 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_palignr: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
-
+
// If palignr is shifting the pair of input vectors less than 9 bytes,
// emit a shuffle instruction.
if (shiftVal <= 8) {
SmallVector<llvm::Constant*, 8> Indices;
for (unsigned i = 0; i != 8; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
-
+
Value* SV = llvm::ConstantVector::get(Indices);
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
}
-
+
// If palignr is shifting the pair of input vectors more than 8 but less
// than 16 bytes, emit a logical right shift of the destination.
if (shiftVal < 16) {
// MMX has these as 1 x i64 vectors for some odd optimization reasons.
llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1);
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
-
+
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
-
+
// If palignr is shifting the pair of vectors more than 16 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
case X86::BI__builtin_ia32_palignr128: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
-
+
// If palignr is shifting the pair of input vectors less than 17 bytes,
// emit a shuffle instruction.
if (shiftVal <= 16) {
SmallVector<llvm::Constant*, 16> Indices;
for (unsigned i = 0; i != 16; ++i)
Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i));
-
+
Value* SV = llvm::ConstantVector::get(Indices);
return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
}
-
+
// If palignr is shifting the pair of input vectors more than 16 but less
// than 32 bytes, emit a logical right shift of the destination.
if (shiftVal < 32) {
llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2);
-
+
Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8);
-
+
// create i32 constant
llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq);
return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
}
-
+
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index aba5d755d5c4..91795b9ded29 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -189,7 +189,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *ptr,
llvm::Value *&numElements,
llvm::Value *&allocPtr, CharUnits &cookieSize) {
// Derive a char* in the same address space as the pointer.
- unsigned AS = cast<llvm::PointerType>(ptr->getType())->getAddressSpace();
+ unsigned AS = ptr->getType()->getPointerAddressSpace();
llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
ptr = CGF.Builder.CreateBitCast(ptr, charPtrTy);
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index a0dcdfdcc686..570aeb040f55 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -154,6 +154,15 @@ protected:
llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
public:
+ /// Adjust the given non-null pointer to an object of polymorphic
+ /// type to point to the complete object.
+ ///
+ /// The IR type of the result should be a pointer but is otherwise
+ /// irrelevant.
+ virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) = 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
@@ -196,6 +205,9 @@ public:
/// Gets the pure virtual member call function.
virtual StringRef GetPureVirtualCallName() = 0;
+ /// Gets the deleted virtual member call name.
+ virtual StringRef GetDeletedVirtualCallName() = 0;
+
/**************************** Array cookies ******************************/
/// Returns the extra size required in order to store the array
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 7d2b9d355ec6..2d1d152894fd 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -25,7 +25,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/InlineAsm.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
@@ -148,6 +148,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (PcsAttr *PCS = D->getAttr<PcsAttr>())
return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
+ if (D->hasAttr<PnaclCallAttr>())
+ return CC_PnaclCall;
+
return CC_C;
}
@@ -588,9 +591,9 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr,
// If the first elt is at least as large as what we're looking for, or if the
// first element is the same size as the whole struct, we can enter it.
uint64_t FirstEltSize =
- CGF.CGM.getTargetData().getTypeAllocSize(FirstElt);
+ CGF.CGM.getDataLayout().getTypeAllocSize(FirstElt);
if (FirstEltSize < DstSize &&
- FirstEltSize < CGF.CGM.getTargetData().getTypeAllocSize(SrcSTy))
+ FirstEltSize < CGF.CGM.getDataLayout().getTypeAllocSize(SrcSTy))
return SrcPtr;
// GEP into the first element.
@@ -653,14 +656,14 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
if (SrcTy == Ty)
return CGF.Builder.CreateLoad(SrcPtr);
- uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty);
+ uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
SrcPtr = EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF);
SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
}
- uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
// If the source and destination are integer or pointer types, just do an
// extension or truncation to the desired type.
@@ -740,7 +743,7 @@ static void CreateCoercedStore(llvm::Value *Src,
return;
}
- uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy);
+ uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
DstPtr = EnterStructPointerForCoercedAccess(DstPtr, DstSTy, SrcSize, CGF);
@@ -756,7 +759,7 @@ static void CreateCoercedStore(llvm::Value *Src,
return;
}
- uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy);
+ uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(DstTy);
// If store is legal, just bitcast the src pointer.
if (SrcSize <= DstSize) {
@@ -864,6 +867,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
ie = FI.arg_end(); it != ie; ++it) {
const ABIArgInfo &argAI = it->info;
+ // Insert a padding type to ensure proper alignment.
+ if (llvm::Type *PaddingType = argAI.getPaddingType())
+ argTypes.push_back(PaddingType);
+
switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
break;
@@ -877,9 +884,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Insert a padding type to ensure proper alignment.
- if (llvm::Type *PaddingType = argAI.getPaddingType())
- argTypes.push_back(PaddingType);
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
@@ -924,50 +928,52 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
unsigned &CallingConv) {
- llvm::Attributes FuncAttrs;
- llvm::Attributes RetAttrs;
+ llvm::AttrBuilder FuncAttrs;
+ llvm::AttrBuilder RetAttrs;
CallingConv = FI.getEffectiveCallingConvention();
if (FI.isNoReturn())
- FuncAttrs |= llvm::Attribute::NoReturn;
+ FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs |= llvm::Attribute::ReturnsTwice;
+ FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
if (TargetDecl->hasAttr<NoThrowAttr>())
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && FPT->isNothrow(getContext()))
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
}
if (TargetDecl->hasAttr<NoReturnAttr>())
- FuncAttrs |= llvm::Attribute::NoReturn;
+ FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs |= llvm::Attribute::ReturnsTwice;
+ FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
// 'const' and 'pure' attribute functions are also nounwind.
if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs |= llvm::Attribute::ReadNone;
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
} else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs |= llvm::Attribute::ReadOnly;
- FuncAttrs |= llvm::Attribute::NoUnwind;
+ FuncAttrs.addAttribute(llvm::Attributes::ReadOnly);
+ FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
}
if (TargetDecl->hasAttr<MallocAttr>())
- RetAttrs |= llvm::Attribute::NoAlias;
+ RetAttrs.addAttribute(llvm::Attributes::NoAlias);
}
if (CodeGenOpts.OptimizeSize)
- FuncAttrs |= llvm::Attribute::OptimizeForSize;
+ FuncAttrs.addAttribute(llvm::Attributes::OptimizeForSize);
+ if (CodeGenOpts.OptimizeSize == 2)
+ FuncAttrs.addAttribute(llvm::Attributes::MinSize);
if (CodeGenOpts.DisableRedZone)
- FuncAttrs |= llvm::Attribute::NoRedZone;
+ FuncAttrs.addAttribute(llvm::Attributes::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs |= llvm::Attribute::NoImplicitFloat;
+ FuncAttrs.addAttribute(llvm::Attributes::NoImplicitFloat);
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
@@ -975,24 +981,28 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
if (RetTy->hasSignedIntegerRepresentation())
- RetAttrs |= llvm::Attribute::SExt;
+ RetAttrs.addAttribute(llvm::Attributes::SExt);
else if (RetTy->hasUnsignedIntegerRepresentation())
- RetAttrs |= llvm::Attribute::ZExt;
+ RetAttrs.addAttribute(llvm::Attributes::ZExt);
break;
case ABIArgInfo::Direct:
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Indirect: {
- llvm::Attributes SRETAttrs = llvm::Attribute::StructRet;
+ llvm::AttrBuilder SRETAttrs;
+ SRETAttrs.addAttribute(llvm::Attributes::StructRet);
if (RetAI.getInReg())
- SRETAttrs |= llvm::Attribute::InReg;
- PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs));
+ SRETAttrs.addAttribute(llvm::Attributes::InReg);
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(Index,
+ llvm::Attributes::get(getLLVMContext(),
+ SRETAttrs)));
++Index;
// sret disables readnone and readonly
- FuncAttrs &= ~(llvm::Attribute::ReadOnly |
- llvm::Attribute::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
+ .removeAttribute(llvm::Attributes::ReadNone);
break;
}
@@ -1000,14 +1010,29 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument");
}
- if (RetAttrs)
- PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
+ if (RetAttrs.hasAttributes())
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ RetAttrs)));
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
QualType ParamType = it->type;
const ABIArgInfo &AI = it->info;
- llvm::Attributes Attrs;
+ llvm::AttrBuilder Attrs;
+
+ if (AI.getPaddingType()) {
+ if (AI.getPaddingInReg()) {
+ llvm::AttrBuilder PadAttrs;
+ PadAttrs.addAttribute(llvm::Attributes::InReg);
+
+ llvm::Attributes A =llvm::Attributes::get(getLLVMContext(), PadAttrs);
+ PAL.push_back(llvm::AttributeWithIndex::get(Index, A));
+ }
+ // Increment Index if there is padding.
+ ++Index;
+ }
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
// have the corresponding parameter variable. It doesn't make
@@ -1015,38 +1040,40 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (AI.getKind()) {
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerOrEnumerationType())
- Attrs |= llvm::Attribute::SExt;
+ Attrs.addAttribute(llvm::Attributes::SExt);
else if (ParamType->isUnsignedIntegerOrEnumerationType())
- Attrs |= llvm::Attribute::ZExt;
+ Attrs.addAttribute(llvm::Attributes::ZExt);
// FALL THROUGH
case ABIArgInfo::Direct:
if (AI.getInReg())
- Attrs |= llvm::Attribute::InReg;
+ Attrs.addAttribute(llvm::Attributes::InReg);
// FIXME: handle sseregparm someday...
- // Increment Index if there is padding.
- Index += (AI.getPaddingType() != 0);
-
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
- if (Attrs != llvm::Attribute::None)
+ if (Attrs.hasAttributes())
for (unsigned I = 0; I < Extra; ++I)
- PAL.push_back(llvm::AttributeWithIndex::get(Index + I, Attrs));
+ PAL.push_back(llvm::AttributeWithIndex::get(Index + I,
+ llvm::Attributes::get(getLLVMContext(),
+ Attrs)));
Index += Extra;
}
break;
case ABIArgInfo::Indirect:
+ if (AI.getInReg())
+ Attrs.addAttribute(llvm::Attributes::InReg);
+
if (AI.getIndirectByVal())
- Attrs |= llvm::Attribute::ByVal;
+ Attrs.addAttribute(llvm::Attributes::ByVal);
+
+ Attrs.addAlignmentAttr(AI.getIndirectAlign());
- Attrs |=
- llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign());
// byval disables readnone and readonly.
- FuncAttrs &= ~(llvm::Attribute::ReadOnly |
- llvm::Attribute::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
+ .removeAttribute(llvm::Attributes::ReadNone);
break;
case ABIArgInfo::Ignore:
@@ -1064,12 +1091,17 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
}
- if (Attrs)
- PAL.push_back(llvm::AttributeWithIndex::get(Index, Attrs));
+ if (Attrs.hasAttributes())
+ PAL.push_back(llvm::AttributeWithIndex::get(Index,
+ llvm::Attributes::get(getLLVMContext(),
+ Attrs)));
++Index;
}
- if (FuncAttrs)
- PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs));
+ if (FuncAttrs.hasAttributes())
+ PAL.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ FuncAttrs)));
}
/// An argument came in as a promoted argument; demote it back to its
@@ -1117,7 +1149,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
- AI->addAttr(llvm::Attribute::NoAlias);
+ AI->addAttr(llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoAlias));
++AI;
}
@@ -1134,6 +1167,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
bool isPromoted =
isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted();
+ // Skip the dummy padding argument.
+ if (ArgI.getPaddingType())
+ ++AI;
+
switch (ArgI.getKind()) {
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
@@ -1175,9 +1212,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Skip the dummy padding argument.
- if (ArgI.getPaddingType())
- ++AI;
// If we have the trivial case, handle it with no muss and fuss.
if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
@@ -1187,7 +1221,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *V = AI;
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::Attribute::NoAlias);
+ AI->addAttr(llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoAlias));
// Ensure the argument is the correct type.
if (V->getType() != ArgI.getCoerceToType())
@@ -1205,7 +1240,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// The alignment we need to use is the max of the requested alignment for
// the argument plus the alignment required by our access code below.
unsigned AlignmentToUse =
- CGM.getTargetData().getABITypeAlignment(ArgI.getCoerceToType());
+ CGM.getDataLayout().getABITypeAlignment(ArgI.getCoerceToType());
AlignmentToUse = std::max(AlignmentToUse,
(unsigned)getContext().getDeclAlign(Arg).getQuantity());
@@ -1226,10 +1261,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// and the optimizer generally likes scalar values better than FCAs.
llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
if (STy && STy->getNumElements() > 1) {
- uint64_t SrcSize = CGM.getTargetData().getTypeAllocSize(STy);
+ uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy);
llvm::Type *DstTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
- uint64_t DstSize = CGM.getTargetData().getTypeAllocSize(DstTy);
+ uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(DstTy);
if (SrcSize <= DstSize) {
Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
@@ -1363,12 +1398,23 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
.objc_retainAutoreleasedReturnValue) {
doRetainAutorelease = false;
- // Look for an inline asm immediately preceding the call and kill it, too.
- llvm::Instruction *prev = call->getPrevNode();
- if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev))
- if (asmCall->getCalledValue()
- == CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker)
- insnsToKill.push_back(prev);
+ // If we emitted an assembly marker for this call (and the
+ // ARCEntrypoints field should have been set if so), go looking
+ // for that call. If we can't find it, we can't do this
+ // optimization. But it should always be the immediately previous
+ // instruction, unless we needed bitcasts around the call.
+ if (CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker) {
+ llvm::Instruction *prev = call->getPrevNode();
+ assert(prev);
+ if (isa<llvm::BitCastInst>(prev)) {
+ prev = prev->getPrevNode();
+ assert(prev);
+ }
+ assert(isa<llvm::CallInst>(prev));
+ assert(cast<llvm::CallInst>(prev)->getCalledValue() ==
+ CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker);
+ insnsToKill.push_back(prev);
+ }
} else {
return 0;
}
@@ -1755,7 +1801,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
- assert(getContext().getLangOpts().ObjCAutoRefCount);
+ assert(getLangOpts().ObjCAutoRefCount);
assert(getContext().hasSameType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
@@ -1943,6 +1989,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned TypeAlign =
getContext().getTypeAlignInChars(I->Ty).getQuantity();
+
+ // Insert a padding argument to ensure proper alignment.
+ if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
+ Args.push_back(llvm::UndefValue::get(PaddingType));
+ ++IRArgNo;
+ }
+
switch (ArgInfo.getKind()) {
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
@@ -1969,7 +2022,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// we cannot force it to be sufficiently aligned.
llvm::Value *Addr = RV.getAggregateAddr();
unsigned Align = ArgInfo.getIndirectAlign();
- const llvm::TargetData *TD = &CGM.getTargetData();
+ const llvm::DataLayout *TD = &CGM.getDataLayout();
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
(ArgInfo.getIndirectByVal() && TypeAlign < Align &&
llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
@@ -1998,12 +2051,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
- // Insert a padding argument to ensure proper alignment.
- if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
- Args.push_back(llvm::UndefValue::get(PaddingType));
- ++IRArgNo;
- }
-
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
ArgInfo.getDirectOffset() == 0) {
@@ -2049,8 +2096,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// and the optimizer generally likes scalar values better than FCAs.
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
- SrcPtr = Builder.CreateBitCast(SrcPtr,
- llvm::PointerType::getUnqual(STy));
+ llvm::Type *SrcTy =
+ cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
+ uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
+ uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
+
+ // If the source type is smaller than the destination type of the
+ // coerce-to logic, copy the source value into a temp alloca the size
+ // of the destination type to allow loading all of it. The bits past
+ // the source value are left undef.
+ if (SrcSize < DstSize) {
+ llvm::AllocaInst *TempAlloca
+ = CreateTempAlloca(STy, SrcPtr->getName() + ".coerce");
+ Builder.CreateMemCpy(TempAlloca, SrcPtr, SrcSize, 0);
+ SrcPtr = TempAlloca;
+ } else {
+ SrcPtr = Builder.CreateBitCast(SrcPtr,
+ llvm::PointerType::getUnqual(STy));
+ }
+
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
@@ -2113,10 +2177,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
- llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList);
+ llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(getLLVMContext(),
+ AttributeList);
llvm::BasicBlock *InvokeDest = 0;
- if (!(Attrs.getFnAttributes() & llvm::Attribute::NoUnwind))
+ if (!Attrs.getFnAttributes().hasAttribute(llvm::Attributes::NoUnwind))
InvokeDest = getInvokeDest();
llvm::CallSite CS;
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index e37fa3ab72b7..b2225e48e361 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -542,12 +542,6 @@ namespace {
};
}
-static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record,
- bool Moving) {
- return Moving ? Record->hasTrivialMoveConstructor() :
- Record->hasTrivialCopyConstructor();
-}
-
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
@@ -588,12 +582,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
if (Array && Constructor->isImplicitlyDefined() &&
Constructor->isCopyOrMoveConstructor()) {
QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
- const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
+ CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
if (BaseElementTy.isPODType(CGF.getContext()) ||
- (Record && hasTrivialCopyOrMoveConstructor(Record,
- Constructor->isMoveConstructor()))) {
- // Find the source pointer. We knows it's the last argument because
- // we know we're in a copy constructor.
+ (CE && CE->getConstructor()->isTrivial())) {
+ // Find the source pointer. We know it's the last argument because
+ // we know we're in an implicit copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
llvm::Value *SrcPtr
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
@@ -952,8 +945,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
}
// -fapple-kext must inline any call to this dtor into
// the caller's body.
- if (getContext().getLangOpts().AppleKext)
- CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
+ if (getLangOpts().AppleKext)
+ CurFn->addFnAttr(llvm::Attributes::AlwaysInline);
break;
}
@@ -1238,7 +1231,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CGDebugInfo *DI = getDebugInfo();
if (DI &&
- CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) {
+ 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();
@@ -1268,7 +1261,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, ArgBeg, ArgEnd);
}
void
@@ -1413,14 +1408,16 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
ForVirtualBase);
llvm::Value *Callee = 0;
- if (getContext().getLangOpts().AppleKext)
+ if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
DD->getParent());
if (!Callee)
Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
- EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
+ // FIXME: Provide a source location here.
+ EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, 0, 0);
}
namespace {
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index fd1c7a339807..80fa09be7473 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGBlocks.h"
+#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
@@ -34,7 +35,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -157,7 +158,7 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
OS << OID->getName();
} else if (const ObjCCategoryImplDecl *OCD =
dyn_cast<const ObjCCategoryImplDecl>(DC)){
- OS << ((NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
+ OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' <<
OCD->getIdentifier()->getNameStart() << ')';
}
OS << ' ' << OMD->getSelector().getAsString() << ']';
@@ -254,9 +255,13 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
return PLoc.isValid()? PLoc.getLine() : 0;
}
-/// getColumnNumber - Get column number for the location. If location is
-/// invalid then use current location.
+/// getColumnNumber - Get column number for the location.
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+ // We may not want column information at all.
+ if (!CGM.getCodeGenOpts().DebugColumnInfo)
+ return 0;
+
+ // If the location is invalid then use the current column.
if (Loc.isInvalid() && CurLoc.isInvalid())
return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
@@ -347,44 +352,60 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
return DBuilder.
- createNullPtrType(BT->getName(CGM.getContext().getLangOpts()));
+ createNullPtrType(BT->getName(CGM.getLangOpts()));
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU,
- getOrCreateMainFile(), 0);
+ if (ClassTy.Verify())
+ return ClassTy;
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
+ return ClassTy;
case BuiltinType::ObjCId: {
// typedef struct objc_class *Class;
// typedef struct objc_object {
// Class isa;
// } *id;
- // TODO: Cache these two types to avoid duplicates.
- llvm::DIType OCTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU, getOrCreateMainFile(), 0);
+ if (ObjTy.Verify())
+ return ObjTy;
+
+ if (!ClassTy.Verify())
+ 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(OCTy, Size);
+ llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
+
+ llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
+ getOrCreateMainFile(),
+ 0, 0, 0, 0,
+ llvm::DIArray());
- SmallVector<llvm::Value *, 16> EltTys;
+ llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
+ SmallVector<llvm::Value *, 1> EltTys;
llvm::DIType FieldTy =
- DBuilder.createMemberType(getOrCreateMainFile(), "isa",
+ DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
getOrCreateMainFile(), 0, Size,
0, 0, 0, ISATy);
EltTys.push_back(FieldTy);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
- return DBuilder.createStructType(TheCU, "objc_object",
- getOrCreateMainFile(),
- 0, 0, 0, 0, Elements);
+
+ ObjNode->replaceOperandWith(10, Elements);
+ ObjTy = llvm::DIType(ObjNode);
+ return ObjTy;
}
case BuiltinType::ObjCSel: {
- return
+ if (SelTy.Verify())
+ return SelTy;
+ SelTy =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
"objc_selector", TheCU, getOrCreateMainFile(),
0);
+ return SelTy;
}
case BuiltinType::UChar:
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
@@ -417,7 +438,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::ULong: BTName = "long unsigned int"; break;
case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
default:
- BTName = BT->getName(CGM.getContext().getLangOpts());
+ BTName = BT->getName(CGM.getLangOpts());
break;
}
// Bit size, align and offset of the type.
@@ -498,21 +519,17 @@ llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
llvm::DIDescriptor Ctx) {
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = RD->getName();
+ StringRef RDName = getClassName(RD);
- // Get the tag.
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
unsigned Tag = 0;
- if (CXXDecl) {
- RDName = getClassName(RD);
- Tag = llvm::dwarf::DW_TAG_class_type;
- }
- else if (RD->isStruct())
+ if (RD->isStruct() || RD->isInterface())
Tag = llvm::dwarf::DW_TAG_structure_type;
else if (RD->isUnion())
Tag = llvm::dwarf::DW_TAG_union_type;
- else
- llvm_unreachable("Unknown RecordDecl type!");
+ else {
+ assert(RD->isClass());
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
// Create the type.
return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line);
@@ -550,7 +567,7 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
/// then emit record's fwd if debug info size reduction is enabled.
llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
llvm::DIFile Unit) {
- if (CGM.getCodeGenOpts().DebugInfo != CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo)
return getOrCreateType(PointeeTy, Unit);
// Limit debug info for the pointee type.
@@ -777,8 +794,6 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
const LambdaExpr::Capture C = *I;
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this'.
if (C.capturesVariable()) {
VarDecl *V = C.getCapturedVar();
llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
@@ -793,10 +808,24 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
Field->getAccess(), layout.getFieldOffset(fieldno),
VUnit, RecordTy);
elements.push_back(fieldType);
+ } else {
+ // TODO: Need to handle 'this' in some way by probably renaming the
+ // this of the lambda class and having a field member of 'this' or
+ // by using AT_object_pointer for the function and having that be
+ // used as 'this' for semantic references.
+ assert(C.capturesThis() && "Field that isn't captured and isn't this?");
+ FieldDecl *f = *Field;
+ llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
+ QualType type = f->getType();
+ llvm::DIType fieldType
+ = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
+ layout.getFieldOffset(fieldNo), VUnit, RecordTy);
+
+ elements.push_back(fieldType);
}
}
} else {
- bool IsMsStruct = record->hasAttr<MsStructAttr>();
+ bool IsMsStruct = record->isMsStruct(CGM.getContext());
const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator I = record->field_begin(),
E = record->field_end();
@@ -875,12 +904,12 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
// TODO: This and the artificial type below are misleading, the
// types aren't artificial the argument is, but the current
// metadata doesn't represent that.
- ThisPtrType = DBuilder.createArtificialType(ThisPtrType);
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
} else {
llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- ThisPtrType = DBuilder.createArtificialType(ThisPtrType);
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
Elts.push_back(ThisPtrType);
}
}
@@ -995,12 +1024,8 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
if (D->isImplicit() && !D->isUsed())
continue;
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- // Only emit debug information for user provided functions, we're
- // unlikely to want info for artificial functions.
- if (Method->isUserProvided())
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
- }
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
SE = FTD->spec_end(); SI != SE; ++SI)
@@ -1182,7 +1207,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// getOrCreateRecordType - Emit record type's standalone debug info.
llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
return T;
}
@@ -1191,7 +1216,7 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// debug info.
llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
SourceLocation Loc) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
DBuilder.retainType(T);
return T;
@@ -1388,12 +1413,21 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
FieldAlign = CGM.getContext().getTypeAlign(FType);
}
- // We can't know the offset of our ivar in the structure if we're using
- // the non-fragile abi and the debugger should ignore the value anyways.
- // Call it the FieldNo+1 due to how debuggers use the information,
- // e.g. negating the value when it needs a lookup in the dynamic table.
- uint64_t FieldOffset = CGM.getLangOpts().ObjCRuntime.isNonFragile()
- ? FieldNo+1 : RL.getFieldOffset(FieldNo);
+ uint64_t FieldOffset;
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
+ // We don't know the runtime offset of an ivar if we're using the
+ // non-fragile ABI. For bitfields, use the bit offset into the first
+ // byte of storage of the bitfield. For other fields, use zero.
+ if (Field->isBitField()) {
+ FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset(
+ CGM, ID, Field);
+ FieldOffset %= CGM.getContext().getCharWidth();
+ } else {
+ FieldOffset = 0;
+ }
+ } else {
+ FieldOffset = RL.getFieldOffset(FieldNo);
+ }
unsigned Flags = 0;
if (Field->getAccessControl() == ObjCIvarDecl::Protected)
@@ -1570,9 +1604,29 @@ llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
/// CreateEnumType - get enumeration type.
llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
- SmallVector<llvm::Value *, 16> Enumerators;
+ uint64_t Size = 0;
+ uint64_t Align = 0;
+ if (!ED->getTypeForDecl()->isIncompleteType()) {
+ Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
+ Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
+ }
+
+ // If this is just a forward declaration, construct an appropriately
+ // marked node and just return it.
+ if (!ED->getDefinition()) {
+ llvm::DIDescriptor EDContext;
+ EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext()));
+ llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
+ unsigned Line = getLineNumber(ED->getLocation());
+ StringRef EDName = ED->getName();
+ return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
+ EDName, EDContext, DefUnit, Line, 0,
+ Size, Align);
+ }
// Create DIEnumerator elements for each enumerator.
+ SmallVector<llvm::Value *, 16> Enumerators;
+ ED = ED->getDefinition();
for (EnumDecl::enumerator_iterator
Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
Enum != EnumEnd; ++Enum) {
@@ -1586,21 +1640,14 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
- uint64_t Size = 0;
- uint64_t Align = 0;
- if (!ED->getTypeForDecl()->isIncompleteType()) {
- Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
- Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
- }
llvm::DIDescriptor EnumContext =
getContextDescriptor(cast<Decl>(ED->getDeclContext()));
llvm::DIType ClassTy = ED->isScopedUsingClassTag() ?
getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType();
- unsigned Flags = !ED->isCompleteDefinition() ? llvm::DIDescriptor::FlagFwdDecl : 0;
llvm::DIType DbgTy =
DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line,
Size, Align, EltArray,
- ClassTy, Flags);
+ ClassTy);
return DbgTy;
}
@@ -1838,10 +1885,10 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
unsigned Line = getLineNumber(RD->getLocation());
- StringRef RDName = RD->getName();
+ StringRef RDName = getClassName(RD);
llvm::DIDescriptor RDContext;
- if (CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo)
RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
else
RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
@@ -1859,9 +1906,7 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, llvm::DIArray());
- else if (CXXDecl) {
- RDName = getClassName(RD);
-
+ 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,
@@ -1969,7 +2014,7 @@ 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,
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
QualType FnType,
llvm::DIFile F) {
@@ -1982,9 +2027,11 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D,
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
// "self" pointer is always first argument.
- Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F));
- // "cmd" pointer is always second argument.
- Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F));
+ llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
+ Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
+ // "_cmd" pointer is always second argument.
+ 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(),
PE = OMethod->param_end(); PI != PE; ++PI)
@@ -2007,14 +2054,22 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
+ // Function may lack declaration in source code if it is created by Clang
+ // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
+ bool HasDecl = (D != 0);
// Use the location of the declaration.
- SourceLocation Loc = D->getLocation();
-
+ SourceLocation Loc;
+ if (HasDecl)
+ Loc = D->getLocation();
+
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(Loc);
llvm::DIDescriptor FDContext(Unit);
llvm::DIArray TParamsArray;
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (!HasDecl) {
+ // Use llvm function name.
+ Name = 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
FI = SPCache.find(FD->getCanonicalDecl());
@@ -2035,10 +2090,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
Flags |= llvm::DIDescriptor::FlagPrototyped;
}
if (LinkageName == Name ||
- CGM.getCodeGenOpts().DebugInfo <= CodeGenOptions::DebugLineTablesOnly)
+ CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
LinkageName = StringRef();
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
@@ -2061,12 +2116,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
Name = Name.substr(1);
unsigned LineNo = getLineNumber(Loc);
- if (D->isImplicit())
+ if (!HasDecl || D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
llvm::DIType DIFnType;
llvm::DISubprogram SPDecl;
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (HasDecl &&
+ CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
DIFnType = getOrCreateFunctionType(D, FnType, Unit);
SPDecl = getFunctionDeclaration(D);
} else {
@@ -2089,7 +2145,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Push function on region stack.
llvm::MDNode *SPN = SP;
LexicalBlockStack.push_back(SPN);
- RegionMap[D] = llvm::WeakVH(SP);
+ if (HasDecl)
+ RegionMap[D] = llvm::WeakVH(SP);
}
/// EmitLocation - Emit metadata to indicate a change in line/column
@@ -2242,7 +2299,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Value *Storage,
unsigned ArgNo, CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
@@ -2253,7 +2310,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
else
Ty = getOrCreateType(VD->getType(), Unit);
- // If there is not any debug info for type then do not emit debug info
+ // If there is no debug info for this type then do not emit debug info
// for this variable.
if (!Ty)
return;
@@ -2279,8 +2336,16 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
unsigned Flags = 0;
if (VD->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
+ // If this is the first argument and it is implicit then
+ // give it an object pointer flag.
+ // FIXME: There has to be a better way to do this, but for static
+ // functions there won't be an implicit param at arg1 and
+ // otherwise it is 'self' or 'this'.
+ if (isa<ImplicitParamDecl>(VD) && ArgNo == 1)
+ Flags |= llvm::DIDescriptor::FlagObjectPointer;
+
llvm::MDNode *Scope = LexicalBlockStack.back();
-
+
StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
@@ -2376,14 +2441,15 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
}
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
- const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
if (Builder.GetInsertBlock() == 0)
@@ -2399,11 +2465,16 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
else
Ty = getOrCreateType(VD->getType(), Unit);
+ // Self is passed along as an implicit non-arg variable in a
+ // block. Mark it as the object pointer.
+ if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
+ Ty = DBuilder.createObjectPointerType(Ty);
+
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
unsigned Column = getColumnNumber(VD->getLocation());
- const llvm::TargetData &target = CGM.getTargetData();
+ const llvm::DataLayout &target = CGM.getDataLayout();
CharUnits offset = CharUnits::fromQuantity(
target.getStructLayout(blockInfo.StructureType)
@@ -2418,7 +2489,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
offset = CGM.getContext()
- .toCharUnitsFromBits(target.getPointerSizeInBits());
+ .toCharUnitsFromBits(target.getPointerSizeInBits(0));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
@@ -2444,7 +2515,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
unsigned ArgNo,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
}
@@ -2461,7 +2532,7 @@ namespace {
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
llvm::Value *addr,
CGBuilderTy &Builder) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
const BlockDecl *blockDecl = block.getBlockDecl();
@@ -2475,7 +2546,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
const llvm::StructLayout *blockLayout =
- CGM.getTargetData().getStructLayout(block.StructureType);
+ CGM.getDataLayout().getStructLayout(block.StructureType);
SmallVector<llvm::Value*, 16> fields;
fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public,
@@ -2606,7 +2677,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
unsigned LineNo = getLineNumber(D->getLocation());
@@ -2640,7 +2711,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit information about an objective-c interface.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
ObjCInterfaceDecl *ID) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
unsigned LineNo = getLineNumber(ID->getLocation());
@@ -2666,7 +2737,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit global variable's debug info.
void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
llvm::Constant *Init) {
- assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo);
+ assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
// Create the descriptor for the variable.
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
StringRef Name = VD->getName();
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 44cc49ade123..2e88a7376a6c 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -50,6 +50,9 @@ class CGDebugInfo {
llvm::DICompileUnit TheCU;
SourceLocation CurLoc, PrevLoc;
llvm::DIType VTablePtrType;
+ llvm::DIType ClassTy;
+ llvm::DIType ObjTy;
+ llvm::DIType SelTy;
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index be6638e0e57b..887058753e14 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -24,7 +24,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -121,7 +121,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
// 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 (getContext().getLangOpts().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
Linkage = CurFn->getLinkage();
@@ -141,7 +141,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
- if (CGF.getContext().getLangOpts().CPlusPlus) {
+ if (CGF.getLangOpts().CPlusPlus) {
StringRef Name = CGM.getMangledName(&D);
return Name.str();
}
@@ -184,12 +184,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
Name = GetStaticDeclName(*this, D, Separator);
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
+ unsigned AddrSpace =
+ CGM.GetGlobalVarAddressSpace(&D, CGM.getContext().getTargetAddressSpace(Ty));
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(Ty));
+ AddrSpace);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (Linkage != llvm::GlobalValue::InternalLinkage)
GV->setVisibility(CurFn->getVisibility());
@@ -220,7 +222,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
// If constant emission failed, then this should be a C++ static
// initializer.
if (!Init) {
- if (!getContext().getLangOpts().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else if (Builder.GetInsertBlock()) {
// Since we have a static initializer, this global variable can't
@@ -331,7 +333,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
if (DI &&
- CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
DI->EmitGlobalVariable(var, &D);
}
@@ -704,9 +706,8 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
/// stores that would be required.
static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
bool isVolatile, CGBuilderTy &Builder) {
- // Zero doesn't require a store.
- if (Init->isNullValue() || isa<llvm::UndefValue>(Init))
- return;
+ assert(!Init->isNullValue() && !isa<llvm::UndefValue>(Init) &&
+ "called emitStoresForInitAfterMemset for zero or undef value.");
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
@@ -719,10 +720,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
dyn_cast<llvm::ConstantDataSequential>(Init)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
llvm::Constant *Elt = CDS->getElementAsConstant(i);
-
- // Get a pointer to the element and emit it.
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+
+ // If necessary, get a pointer to the element and emit it.
+ if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
+ emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
+ isVolatile, Builder);
}
return;
}
@@ -732,9 +734,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
- // Get a pointer to the element and emit it.
- emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
- isVolatile, Builder);
+
+ // If necessary, get a pointer to the element and emit it.
+ if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt))
+ emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
+ isVolatile, Builder);
}
}
@@ -791,7 +795,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getContext().getLangOpts().ElideConstructors &&
+ bool NRVO = getLangOpts().ElideConstructors &&
D.isNRVOVariable();
// If this value is a POD array or struct with a statically
@@ -910,7 +914,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Emit debug info for local var declaration.
if (HaveInsertPoint())
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
if (Target.useGlobalsForAutomaticVariables()) {
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr),
@@ -1056,10 +1061,11 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
// If the initializer is all or mostly zeros, codegen with memset then do
// a few stores afterward.
if (shouldUseMemSetPlusStoresToInitialize(constant,
- CGM.getTargetData().getTypeAllocSize(constant->getType()))) {
+ CGM.getDataLayout().getTypeAllocSize(constant->getType()))) {
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
alignment.getQuantity(), isVolatile);
- if (!constant->isNullValue()) {
+ // Zero and undef don't require a stores.
+ if (!constant->isNullValue() && !isa<llvm::UndefValue>(constant)) {
Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo());
emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder);
}
@@ -1493,8 +1499,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
LocalDeclMap[&D] = Arg;
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >=
- CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
}
@@ -1576,7 +1582,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Emit debug info for param declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) {
+ if (CGM.getCodeGenOpts().getDebugInfo()
+ >= CodeGenOptions::LimitedDebugInfo) {
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 492b95ad155b..65be3c19fb88 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -16,6 +16,7 @@
#include "CGCXXABI.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;
@@ -163,6 +164,9 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM,
CodeGenFunction CGF(CGM);
+ // Initialize debug info if needed.
+ CGF.maybeInitializeDebugInfo();
+
CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn,
CGM.getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -218,7 +222,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &CGM.getModule());
- if (!CGM.getContext().getLangOpts().AppleKext) {
+ if (!CGM.getLangOpts().AppleKext) {
// Set the section if needed.
if (const char *Section =
CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier())
@@ -228,8 +232,8 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (CGM.getLangOpts().AddressSanitizer)
- Fn->addFnAttr(llvm::Attribute::AddressSafety);
+ if (CGM.getLangOpts().SanitizeAddress)
+ Fn->addFnAttr(llvm::Attributes::AddressSafety);
return Fn;
}
@@ -252,8 +256,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
- }
- else {
+ } else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
DelayedCXXInitPosition.find(D);
if (I == DelayedCXXInitPosition.end()) {
@@ -276,28 +279,50 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- // Create our global initialization function.
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
+ // Create our global initialization function.
if (!PrioritizedCXXGlobalInits.empty()) {
SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
- PrioritizedCXXGlobalInits.end());
- for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) {
- llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second;
- LocalCXXGlobalInits.push_back(Fn);
- }
- LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end());
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ PrioritizedCXXGlobalInits.end());
+ // Iterate over "chunks" of ctors with same priority and emit each chunk
+ // into separate function. Note - everything is sorted first by priority,
+ // second - by lex order, so we emit ctor functions in proper order.
+ for (SmallVectorImpl<GlobalInitData >::iterator
+ I = PrioritizedCXXGlobalInits.begin(),
+ E = PrioritizedCXXGlobalInits.end(); I != E; ) {
+ SmallVectorImpl<GlobalInitData >::iterator
+ PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp());
+
+ LocalCXXGlobalInits.clear();
+ unsigned Priority = I->first.priority;
+ // Compute the function suffix from priority. Prepend with zeroes to make
+ // sure the function names are also ordered as priorities.
+ std::string PrioritySuffix = llvm::utostr(Priority);
+ // Priority is always <= 65535 (enforced by sema)..
+ PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
+ llvm::Function *Fn =
+ CreateGlobalInitOrDestructFunction(*this, FTy,
+ "_GLOBAL__I_" + PrioritySuffix);
+
+ for (; I < PrioE; ++I)
+ LocalCXXGlobalInits.push_back(I->second);
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&LocalCXXGlobalInits[0],
LocalCXXGlobalInits.size());
+ AddGlobalCtor(Fn, Priority);
+ }
}
- else
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
- &CXXGlobalInits[0],
- CXXGlobalInits.size());
+
+ llvm::Function *Fn =
+ CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
+
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
+ &CXXGlobalInits[0],
+ CXXGlobalInits.size());
AddGlobalCtor(Fn);
+
CXXGlobalInits.clear();
PrioritizedCXXGlobalInits.clear();
}
@@ -321,8 +346,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit) {
- if (CGM.getModuleDebugInfo() && !D->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ // Check if we need to emit debug info for variable initializer.
+ if (!D->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
@@ -344,6 +370,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
@@ -369,6 +398,9 @@ void 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());
@@ -405,6 +437,9 @@ 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());
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index ba9c2967cd3d..86dee5a4ab98 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -307,14 +307,15 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
/// aggressive about only using the ObjC++ personality in a function
/// when it really needs it.
void CodeGenModule::SimplifyPersonality() {
- // For now, this is really a Darwin-specific operation.
- if (!Context.getTargetInfo().getTriple().isOSDarwin())
- return;
-
// If we're not in ObjC++ -fexceptions, there's nothing to do.
if (!LangOpts.CPlusPlus || !LangOpts.ObjC1 || !LangOpts.Exceptions)
return;
+ // Both the problem this endeavors to fix and the way the logic
+ // above works is specific to the NeXT runtime.
+ if (!LangOpts.ObjCRuntime.isNeXTFamily())
+ return;
+
const EHPersonality &ObjCXX = EHPersonality::get(LangOpts);
const EHPersonality &CXX = getCXXPersonality(LangOpts);
if (&ObjCXX == &CXX)
@@ -534,7 +535,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
llvm::Value *zero = CGF.Builder.getInt32(0);
llvm::Value *failsFilter =
CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails");
- CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock());
+ CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock(false));
CGF.EmitBlock(unexpectedBB);
}
@@ -614,7 +615,7 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) {
// The dispatch block for the end of the scope chain is a block that
// just resumes unwinding.
if (si == EHStack.stable_end())
- return getEHResumeBlock();
+ return getEHResumeBlock(true);
// Otherwise, we should look at the actual scope.
EHScope &scope = *EHStack.find(si);
@@ -1546,7 +1547,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
return TerminateHandler;
}
-llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
+llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
if (EHResumeBlock) return EHResumeBlock;
CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
@@ -1560,7 +1561,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
- if (RethrowName != 0) {
+ if (RethrowName != 0 && !isCleanup) {
Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
getExceptionFromSlot())
->setDoesNotReturn();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 1fe4c18badc6..63cc5b515da8 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -26,7 +26,8 @@
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/MDBuilder.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
+#include "llvm/ADT/Hashing.h"
using namespace clang;
using namespace CodeGen;
@@ -156,50 +157,6 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
}
}
-namespace {
-/// \brief An adjustment to be made to the temporary created when emitting a
-/// reference binding, which accesses a particular subobject of that temporary.
- struct SubobjectAdjustment {
- enum {
- DerivedToBaseAdjustment,
- FieldAdjustment,
- MemberPointerAdjustment
- } Kind;
-
- union {
- struct {
- const CastExpr *BasePath;
- const CXXRecordDecl *DerivedClass;
- } DerivedToBase;
-
- FieldDecl *Field;
-
- struct {
- const MemberPointerType *MPT;
- llvm::Value *Ptr;
- } Ptr;
- };
-
- SubobjectAdjustment(const CastExpr *BasePath,
- const CXXRecordDecl *DerivedClass)
- : Kind(DerivedToBaseAdjustment) {
- DerivedToBase.BasePath = BasePath;
- DerivedToBase.DerivedClass = DerivedClass;
- }
-
- SubobjectAdjustment(FieldDecl *Field)
- : Kind(FieldAdjustment) {
- this->Field = Field;
- }
-
- SubobjectAdjustment(const MemberPointerType *MPT, llvm::Value *Ptr)
- : Kind(MemberPointerAdjustment) {
- this->Ptr.MPT = MPT;
- this->Ptr.Ptr = Ptr;
- }
- };
-}
-
static llvm::Value *
CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
const NamedDecl *InitializedDecl) {
@@ -232,32 +189,18 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
const CXXDestructorDecl *&ReferenceTemporaryDtor,
QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
- // Look through single-element init lists that claim to be lvalues. They're
- // just syntactic wrappers in this case.
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue())
- E = ILE->getInit(0);
- }
-
- // Look through expressions for materialized temporaries (for now).
- if (const MaterializeTemporaryExpr *M
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- // 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 (CGF.getContext().getLangOpts().ObjCAutoRefCount &&
- E->getType()->isObjCLifetimeType() &&
- (E->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
- E->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
- E->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing))
- ObjCARCReferenceLifetimeType = E->getType();
-
- E = M->GetTemporaryExpr();
- }
+ const MaterializeTemporaryExpr *M = NULL;
+ E = E->findMaterializedTemporary(M);
+ // 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 CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
- E = DAE->getExpr();
-
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
CGF.enterFullExpression(EWC);
CodeGenFunction::RunCleanupsScope Scope(CGF);
@@ -335,54 +278,13 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return ReferenceTemporary;
}
-
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- while (true) {
- E = E->IgnoreParens();
-
- if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
- if ((CE->getCastKind() == CK_DerivedToBase ||
- CE->getCastKind() == CK_UncheckedDerivedToBase) &&
- E->getType()->isRecordType()) {
- E = CE->getSubExpr();
- CXXRecordDecl *Derived
- = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
- Adjustments.push_back(SubobjectAdjustment(CE, Derived));
- continue;
- }
-
- if (CE->getCastKind() == CK_NoOp) {
- E = CE->getSubExpr();
- continue;
- }
- } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
- assert(ME->getBase()->getType()->isRecordType());
- if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- E = ME->getBase();
- Adjustments.push_back(SubobjectAdjustment(Field));
- continue;
- }
- }
- } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- if (BO->isPtrMemOp()) {
- assert(BO->getLHS()->isRValue());
- E = BO->getLHS();
- const MemberPointerType *MPT =
- BO->getRHS()->getType()->getAs<MemberPointerType>();
- llvm::Value *Ptr = CGF.EmitScalarExpr(BO->getRHS());
- Adjustments.push_back(SubobjectAdjustment(MPT, Ptr));
- }
- }
- if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
- if (opaque->getType()->isRecordType())
- return CGF.EmitOpaqueValueLValue(opaque).getAddress();
+ 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();
- // Nothing changed.
- break;
- }
-
// Create a reference temporary if necessary.
AggValueSlot AggSlot = AggValueSlot::ignored();
if (CGF.hasAggregateLLVMType(E->getType()) &&
@@ -446,8 +348,9 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
}
case SubobjectAdjustment::MemberPointerAdjustment: {
+ llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS);
Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress(
- CGF, Object, Adjustment.Ptr.Ptr, Adjustment.Ptr.MPT);
+ CGF, Object, Ptr, Adjustment.Ptr.MPT);
break;
}
}
@@ -486,6 +389,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
ReferenceTemporaryDtor,
ObjCARCReferenceLifetimeType,
InitializedDecl);
+ 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
+ // an existing object or function of an appropriate type nor a region of
+ // storage of suitable size and alignment to contain an object of the
+ // reference's type, the behavior is undefined.
+ QualType Ty = E->getType();
+ EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty);
+ }
if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
return RValue::get(Value);
@@ -549,22 +461,133 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
->getZExtValue();
}
-void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
- if (!CatchUndefined)
+/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h.
+static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
+ llvm::Value *High) {
+ llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL);
+ llvm::Value *K47 = Builder.getInt64(47);
+ llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul);
+ llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0);
+ llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul);
+ llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0);
+ return Builder.CreateMul(B1, KMul);
+}
+
+void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
+ llvm::Value *Address,
+ QualType Ty, CharUnits Alignment) {
+ if (!SanitizePerformTypeCheck)
return;
- // This needs to be to the standard address space.
- Address = Builder.CreateBitCast(Address, Int8PtrTy);
+ // Don't check pointers outside the default address space. The null check
+ // isn't correct, the object-size check isn't supported by LLVM, and we can't
+ // communicate the addresses to the runtime handler for the vptr check.
+ if (Address->getType()->getPointerAddressSpace())
+ return;
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy);
+ llvm::Value *Cond = 0;
- llvm::Value *Min = Builder.getFalse();
- llvm::Value *C = Builder.CreateCall2(F, Address, Min);
- llvm::BasicBlock *Cont = createBasicBlock();
- Builder.CreateCondBr(Builder.CreateICmpUGE(C,
- llvm::ConstantInt::get(IntPtrTy, Size)),
- Cont, getTrapBB());
- EmitBlock(Cont);
+ if (getLangOpts().SanitizeNull) {
+ // The glvalue must not be an empty glvalue.
+ Cond = Builder.CreateICmpNE(
+ Address, llvm::Constant::getNullValue(Address->getType()));
+ }
+
+ if (getLangOpts().SanitizeObjectSize && !Ty->isIncompleteType()) {
+ uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
+
+ // 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);
+ llvm::Value *Min = Builder.getFalse();
+ llvm::Value *CastAddr = Builder.CreateBitCast(Address, Int8PtrTy);
+ llvm::Value *LargeEnough =
+ Builder.CreateICmpUGE(Builder.CreateCall2(F, CastAddr, Min),
+ llvm::ConstantInt::get(IntPtrTy, Size));
+ Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough;
+ }
+
+ uint64_t AlignVal = 0;
+
+ if (getLangOpts().SanitizeAlignment) {
+ AlignVal = Alignment.getQuantity();
+ if (!Ty->isIncompleteType() && !AlignVal)
+ AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
+
+ // The glvalue must be suitably aligned.
+ if (AlignVal) {
+ llvm::Value *Align =
+ Builder.CreateAnd(Builder.CreatePtrToInt(Address, IntPtrTy),
+ llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
+ llvm::Value *Aligned =
+ Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
+ Cond = Cond ? Builder.CreateAnd(Cond, Aligned) : Aligned;
+ }
+ }
+
+ if (Cond) {
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ llvm::ConstantInt::get(SizeTy, AlignVal),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ EmitCheck(Cond, "type_mismatch", StaticData, Address);
+ }
+
+ // If possible, check that the vptr indicates that there is a subobject of
+ // type Ty at offset zero within this object.
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (getLangOpts().SanitizeVptr && TCK != TCK_ConstructorCall &&
+ RD && RD->hasDefinition() && RD->isDynamicClass()) {
+ // Compute a hash of the mangled name of the type.
+ //
+ // FIXME: This is not guaranteed to be deterministic! Move to a
+ // fingerprinting mechanism once LLVM provides one. For the time
+ // being the implementation happens to be deterministic.
+ llvm::SmallString<64> MangledName;
+ llvm::raw_svector_ostream Out(MangledName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
+ Out);
+ llvm::hash_code TypeHash = hash_value(Out.str());
+
+ // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
+ llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
+ llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
+ llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy);
+ llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
+ llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
+
+ llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
+ Hash = Builder.CreateTrunc(Hash, IntPtrTy);
+
+ // Look the hash up in our cache.
+ const int CacheSize = 128;
+ llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
+ llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
+ "__ubsan_vptr_type_cache");
+ llvm::Value *Slot = Builder.CreateAnd(Hash,
+ llvm::ConstantInt::get(IntPtrTy,
+ CacheSize-1));
+ llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
+ llvm::Value *CacheVal =
+ Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices));
+
+ // If the hash isn't in the cache, call a runtime handler to perform the
+ // hard work of checking whether the vptr is for an object of the right
+ // type. This will either fill in the cache and return, or produce a
+ // diagnostic.
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ llvm::Value *DynamicData[] = { Address, Hash };
+ EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
+ "dynamic_type_cache_miss", StaticData, DynamicData, true);
+ }
}
@@ -641,11 +664,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
return MakeAddrLValue(llvm::UndefValue::get(Ty), E->getType());
}
-LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) {
+LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
- EmitCheck(LV.getAddress(),
- getContext().getTypeSizeInChars(E->getType()).getQuantity());
+ EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(),
+ E->getType(), LV.getAlignment());
return LV;
}
@@ -672,7 +695,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
llvm_unreachable("cannot emit a property reference directly");
case Expr::ObjCSelectorExprClass:
- return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
+ return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
case Expr::ObjCIsaExprClass:
return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
@@ -709,6 +732,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
case Expr::CXXBindTemporaryExprClass:
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
+ case Expr::CXXUuidofExprClass:
+ return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E));
case Expr::LambdaExprClass:
return EmitLambdaLValue(cast<LambdaExpr>(E));
@@ -1124,7 +1149,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// Get the output type.
llvm::Type *ResLTy = ConvertType(LV.getType());
- unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
+ unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
// Compute the result as an OR of all of the individual component accesses.
llvm::Value *Res = 0;
@@ -1322,7 +1347,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// Get the output type.
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
+ unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
@@ -1645,6 +1670,21 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
CharUnits Alignment = getContext().getDeclAlign(ND);
QualType T = E->getType();
+ // A DeclRefExpr for a reference initialized by a constant expression can
+ // appear without being odr-used. Directly emit the constant initializer.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ const Expr *Init = VD->getAnyInitializer(VD);
+ if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
+ VD->isUsableInConstantExpressions(getContext()) &&
+ VD->checkInitIsICE()) {
+ llvm::Constant *Val =
+ CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this);
+ assert(Val && "failed to emit reference constant expression");
+ // FIXME: Eventually we will want to emit vector element references.
+ return MakeAddrLValue(Val, T, Alignment);
+ }
+ }
+
// FIXME: We should be able to assert this for FunctionDecls as well!
// FIXME: We should be able to assert this for all DeclRefExprs, not just
// those with a valid source location.
@@ -1655,7 +1695,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (ND->hasAttr<WeakRefAttr>()) {
const ValueDecl *VD = cast<ValueDecl>(ND);
llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD);
- return MakeAddrLValue(Aliasee, E->getType(), Alignment);
+ return MakeAddrLValue(Aliasee, T, Alignment);
}
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
@@ -1683,9 +1723,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
}
assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
- CharUnits alignment = getContext().getDeclAlign(VD);
return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable),
- E->getType(), alignment);
+ T, Alignment);
}
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
@@ -1736,8 +1775,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
// of a pointer to object; as in void foo (__weak id *param); *param = 0;
// But, we continue to generate __strong write barrier on indirect write
// into a pointer to object.
- if (getContext().getLangOpts().ObjC1 &&
- getContext().getLangOpts().getGC() != LangOptions::NonGC &&
+ if (getLangOpts().ObjC1 &&
+ getLangOpts().getGC() != LangOptions::NonGC &&
LV.isObjCWeak())
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
return LV;
@@ -1815,8 +1854,9 @@ GetAddrOfConstantWideString(StringRef Str,
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32>& Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
- char* ResultPtr = &Target[0];
- bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr);
+ char *ResultPtr = &Target[0];
+ const UTF8 *ErrorPtr;
+ bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
(void)success;
assert(success);
Target.resize(ResultPtr - &Target[0]);
@@ -1888,33 +1928,167 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
}
}
-llvm::BasicBlock *CodeGenFunction::getTrapBB() {
- const CodeGenOptions &GCO = CGM.getCodeGenOpts();
+/// Emit a type description suitable for use by a runtime sanitizer library. The
+/// format of a type descriptor is
+///
+/// \code
+/// { i16 TypeKind, i16 TypeInfo }
+/// \endcode
+///
+/// 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.
+ uint16_t TypeKind = -1;
+ uint16_t TypeInfo = 0;
+
+ if (T->isIntegerType()) {
+ TypeKind = 0;
+ TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
+ T->isSignedIntegerType();
+ } else if (T->isFloatingType()) {
+ TypeKind = 1;
+ TypeInfo = getContext().getTypeSize(T);
+ }
+
+ // Format the type name as if for a diagnostic, including quotes and
+ // optionally an 'aka'.
+ llvm::SmallString<32> Buffer;
+ CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
+ (intptr_t)T.getAsOpaquePtr(),
+ 0, 0, 0, 0, 0, 0, Buffer,
+ ArrayRef<intptr_t>());
+
+ llvm::Constant *Components[] = {
+ Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
+ llvm::ConstantDataArray::getString(getLLVMContext(), Buffer)
+ };
+ llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalVariable::PrivateLinkage,
+ Descriptor);
+ GV->setUnnamedAddr(true);
+ return GV;
+}
- // If we are not optimzing, don't collapse all calls to trap in the function
- // to the same call, that way, in the debugger they can see which operation
- // did in fact fail. If we are optimizing, we collapse all calls to trap down
- // to just one per function to save on codesize.
- if (GCO.OptimizationLevel && TrapBB)
- return TrapBB;
+llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
+ llvm::Type *TargetTy = IntPtrTy;
+
+ // Integers which fit in intptr_t are zero-extended and passed directly.
+ if (V->getType()->isIntegerTy() &&
+ V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
+ return Builder.CreateZExt(V, TargetTy);
+
+ // Pointers are passed directly, everything else is passed by address.
+ if (!V->getType()->isPointerTy()) {
+ llvm::Value *Ptr = Builder.CreateAlloca(V->getType());
+ Builder.CreateStore(V, Ptr);
+ V = Ptr;
+ }
+ return Builder.CreatePtrToInt(V, TargetTy);
+}
+
+/// \brief Emit a representation of a SourceLocation for passing to a handler
+/// in a sanitizer runtime library. The format for this data is:
+/// \code
+/// struct SourceLocation {
+/// const char *Filename;
+/// int32_t Line, Column;
+/// };
+/// \endcode
+/// For an invalid SourceLocation, the Filename pointer is null.
+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()))
+ : llvm::Constant::getNullValue(Int8PtrTy),
+ Builder.getInt32(PLoc.getLine()),
+ Builder.getInt32(PLoc.getColumn())
+ };
- llvm::BasicBlock *Cont = 0;
- if (HaveInsertPoint()) {
- Cont = createBasicBlock("cont");
- EmitBranch(Cont);
+ return llvm::ConstantStruct::getAnon(Data);
+}
+
+void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
+ llvm::ArrayRef<llvm::Constant *> StaticArgs,
+ llvm::ArrayRef<llvm::Value *> DynamicArgs,
+ bool Recoverable) {
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+
+ llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
+ Builder.CreateCondBr(Checked, Cont, Handler);
+ EmitBlock(Handler);
+
+ llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
+ llvm::GlobalValue *InfoPtr =
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, Info);
+ InfoPtr->setUnnamedAddr(true);
+
+ llvm::SmallVector<llvm::Value *, 4> Args;
+ llvm::SmallVector<llvm::Type *, 4> ArgTypes;
+ Args.reserve(DynamicArgs.size() + 1);
+ ArgTypes.reserve(DynamicArgs.size() + 1);
+
+ // Handler functions take an i8* pointing to the (handler-specific) static
+ // information block, followed by a sequence of intptr_t arguments
+ // representing operand values.
+ Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
+ ArgTypes.push_back(Int8PtrTy);
+ for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
+ Args.push_back(EmitCheckValue(DynamicArgs[i]));
+ ArgTypes.push_back(IntPtrTy);
+ }
+
+ llvm::FunctionType *FnType =
+ llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
+ llvm::AttrBuilder B;
+ if (!Recoverable) {
+ B.addAttribute(llvm::Attributes::NoReturn)
+ .addAttribute(llvm::Attributes::NoUnwind);
+ }
+ B.addAttribute(llvm::Attributes::UWTable);
+ llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType,
+ ("__ubsan_handle_" + CheckName).str(),
+ llvm::Attributes::get(getLLVMContext(),
+ B));
+ llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
+ if (Recoverable) {
+ Builder.CreateBr(Cont);
+ } else {
+ HandlerCall->setDoesNotReturn();
+ HandlerCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
}
- TrapBB = createBasicBlock("trap");
- EmitBlock(TrapBB);
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
- llvm::CallInst *TrapCall = Builder.CreateCall(F);
- TrapCall->setDoesNotReturn();
- TrapCall->setDoesNotThrow();
- Builder.CreateUnreachable();
+ EmitBlock(Cont);
+}
- if (Cont)
- EmitBlock(Cont);
- return TrapBB;
+void CodeGenFunction::EmitTrapvCheck(llvm::Value *Checked) {
+ llvm::BasicBlock *Cont = createBasicBlock("cont");
+
+ // If we're optimizing, collapse all calls to trap down to just one per
+ // function to save on code size.
+ if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) {
+ TrapBB = createBasicBlock("trap");
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ EmitBlock(TrapBB);
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap);
+ llvm::CallInst *TrapCall = Builder.CreateCall(F);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ } else {
+ Builder.CreateCondBr(Checked, Cont, TrapBB);
+ }
+
+ EmitBlock(Cont);
}
/// isSimpleArrayDecayOperand - If the specified expr is a simple decay from an
@@ -2007,14 +2181,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// Propagate the alignment from the array itself to the result.
ArrayAlignment = ArrayLV.getAlignment();
- if (getContext().getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx");
} else {
// The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase());
- if (getContext().getLangOpts().isSignedOverflowDefined())
+ if (getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
@@ -2037,8 +2211,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace());
- if (getContext().getLangOpts().ObjC1 &&
- getContext().getLangOpts().getGC() != LangOptions::NonGC) {
+ if (getLangOpts().ObjC1 &&
+ getLangOpts().getGC() != LangOptions::NonGC) {
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
setObjCGCLValueClass(getContext(), E, LV);
}
@@ -2114,11 +2288,13 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
LValue BaseLV;
- if (E->isArrow())
- BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr),
- BaseExpr->getType()->getPointeeType());
- else
- BaseLV = EmitLValue(BaseExpr);
+ if (E->isArrow()) {
+ llvm::Value *Ptr = EmitScalarExpr(BaseExpr);
+ QualType PtrTy = BaseExpr->getType()->getPointeeType();
+ EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Ptr, PtrTy);
+ BaseLV = MakeNaturalAlignAddrLValue(Ptr, PtrTy);
+ } else
+ BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
NamedDecl *ND = E->getMemberDecl();
if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
@@ -2355,7 +2531,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
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:
@@ -2546,7 +2725,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXPseudoDestructorExpr *PseudoDtor
= dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
- if (getContext().getLangOpts().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
DestroyedType->isObjCLifetimeType() &&
(DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
@@ -2635,7 +2814,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
}
RValue RV = EmitAnyExpr(E->getRHS());
- LValue LV = EmitLValue(E->getLHS());
+ LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
EmitStoreThroughLValue(RV, LV);
return LV;
}
@@ -2677,6 +2856,14 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
return MakeAddrLValue(EmitCXXTypeidExpr(E), E->getType());
}
+llvm::Value *CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
+ return CGM.GetAddrOfUuidDescriptor(E);
+}
+
+LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {
+ return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType());
+}
+
LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
@@ -2977,11 +3164,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
uint64_t Size = sizeChars.getQuantity();
CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
unsigned Align = alignChars.getQuantity();
- unsigned MaxInlineWidth =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
- bool UseLibcall = (Size != Align || Size > MaxInlineWidth);
-
-
+ unsigned MaxInlineWidthInBits =
+ getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ bool UseLibcall = (Size != Align ||
+ getContext().toBits(sizeChars) > MaxInlineWidthInBits);
llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
Ptr = EmitScalarExpr(E->getPtr());
@@ -3177,6 +3363,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
return ConvertTempToRValue(*this, E->getType(), Dest);
}
+ bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store_n;
+ bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load_n;
+
llvm::Type *IPtrTy =
llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
llvm::Value *OrigDest = Dest;
@@ -3194,14 +3387,20 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
break;
case 1: // memory_order_consume
case 2: // memory_order_acquire
+ if (IsStore)
+ break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::Acquire);
break;
case 3: // memory_order_release
+ if (IsLoad)
+ break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::Release);
break;
case 4: // memory_order_acq_rel
+ if (IsLoad || IsStore)
+ break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::AcquireRelease);
break;
@@ -3221,13 +3420,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Long case, when Order isn't obviously constant.
- bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store_n;
- bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load_n;
-
// Create all the relevant BB's
llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
*AcqRelBB = 0, *SeqCstBB = 0;
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 61f7362ecaef..718e8f999ce7 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -549,8 +549,10 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_Dynamic: {
+ // FIXME: Can this actually happen? We have no test coverage for it.
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
- LValue LV = CGF.EmitCheckedLValue(E->getSubExpr());
+ LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(),
+ CodeGenFunction::TCK_Load);
// FIXME: Do we also need to handle property references here?
if (LV.isSimple())
CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E));
@@ -645,6 +647,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -771,7 +774,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
Visit(E->getRHS());
// Now emit the LHS and copy into it.
- LValue LHS = CGF.EmitLValue(E->getLHS());
+ LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
@@ -1205,7 +1208,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return;
// C++ objects with a user-declared constructor don't need zero'ing.
- if (CGF.getContext().getLangOpts().CPlusPlus)
+ if (CGF.getLangOpts().CPlusPlus)
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(E->getType())->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -1271,10 +1274,11 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Value *SrcPtr, QualType Ty,
bool isVolatile,
- CharUnits alignment) {
+ CharUnits alignment,
+ bool isAssignment) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
- if (getContext().getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
assert((Record->hasTrivialCopyConstructor() ||
@@ -1300,9 +1304,13 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// implementation handles this case safely. If there is a libc that does not
// safely handle this, we can add a target hook.
- // Get size and alignment info for this aggregate.
- std::pair<CharUnits, CharUnits> TypeInfo =
- getContext().getTypeInfoInChars(Ty);
+ // Get data size and alignment info for this aggregate. If this is an
+ // assignment don't copy the tail padding. Otherwise copying it is fine.
+ std::pair<CharUnits, CharUnits> TypeInfo;
+ if (isAssignment)
+ TypeInfo = getContext().getTypeInfoDataSizeInChars(Ty);
+ else
+ TypeInfo = getContext().getTypeInfoInChars(Ty);
if (alignment.isZero())
alignment = TypeInfo.second;
@@ -1359,11 +1367,17 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
}
}
}
+
+ // Determine the metadata to describe the position of any padding in this
+ // memcpy, as well as the TBAA tags for the members of the struct, in case
+ // the optimizer wishes to expand it in to scalar memory operations.
+ llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty);
Builder.CreateMemCpy(DestPtr, SrcPtr,
llvm::ConstantInt::get(IntPtrTy,
TypeInfo.first.getQuantity()),
- alignment.getQuantity(), isVolatile);
+ alignment.getQuantity(), isVolatile,
+ /*TBAATag=*/0, TBAAStructTag);
}
void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 31ea1b5448a7..7f640f6e6433 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -24,6 +24,7 @@ using namespace clang;
using namespace CodeGen;
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -33,6 +34,13 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
+ // C++11 [class.mfct.non-static]p2:
+ // If a non-static member function of a class X is called for an object that
+ // is not of type X, or of a type derived from X, the behavior is undefined.
+ EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
+ : TCK_MemberCall,
+ CallLoc, This, getContext().getRecordType(MD->getParent()));
+
CallArgList Args;
// Push the this ptr.
@@ -168,8 +176,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
CGDebugInfo *DI = getDebugInfo();
- if (DI && CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo
- && !isa<CallExpr>(ME->getBase())) {
+ 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(),
@@ -235,7 +244,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// We don't like to generate the trivial copy/move assignment operator
// when it isn't necessary; just produce the proper effect here.
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
- EmitAggregateCopy(This, RHS, CE->getType());
+ EmitAggregateAssign(This, RHS, CE->getType());
return RValue::get(This);
}
@@ -251,16 +260,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
// Compute the function type we're calling.
+ const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD;
const CGFunctionInfo *FInfo = 0;
- if (isa<CXXDestructorDecl>(MD))
- FInfo = &CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
+ if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor,
Dtor_Complete);
- else if (isa<CXXConstructorDecl>(MD))
- FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(
- cast<CXXConstructorDecl>(MD),
- Ctor_Complete);
+ else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl))
+ FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor,
+ Ctor_Complete);
else
- FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(MD);
+ FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo);
@@ -277,7 +286,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (UseVirtualCall) {
Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
} else {
- if (getContext().getLangOpts().AppleKext &&
+ if (getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -295,7 +304,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
} else if (UseVirtualCall) {
Callee = BuildVirtualCall(MD, This, Ty);
} else {
- if (getContext().getLangOpts().AppleKext &&
+ if (getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -306,8 +315,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
}
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- CE->arg_begin(), CE->arg_end());
+ return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, CE->arg_begin(), CE->arg_end());
}
RValue
@@ -337,6 +346,9 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
else
This = EmitLValue(BaseExpr).getAddress();
+ EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This,
+ QualType(MPT->getClass(), 0));
+
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, This, MemFnPtr, MPT);
@@ -370,13 +382,13 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
MD->isTrivial()) {
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
+ EmitAggregateAssign(This, Src, Ty);
return RValue::get(This);
}
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
- E->arg_begin() + 1, E->arg_end());
+ return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
+ /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -457,7 +469,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// Elide the constructor if we're constructing from a temporary.
// The temporary check is required because Sema sets this on NRVO
// returns.
- if (getContext().getLangOpts().ElideConstructors && E->isElidable()) {
+ if (getLangOpts().ElideConstructors && E->isElidable()) {
assert(getContext().hasSameUnqualifiedType(E->getType(),
E->getArg(0)->getType()));
if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) {
@@ -878,7 +890,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
if (constNum->getZExtValue() <= initializerElements) {
// If there was a cleanup, deactivate it.
if (cleanupDominator)
- DeactivateCleanupBlock(cleanup, cleanupDominator);;
+ DeactivateCleanupBlock(cleanup, cleanupDominator);
return;
}
} else {
@@ -949,7 +961,6 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (E->isArray()) {
if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
CXXConstructorDecl *Ctor = CCE->getConstructor();
- bool RequiresZeroInitialization = false;
if (Ctor->isTrivial()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
@@ -962,13 +973,11 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
return;
}
-
- RequiresZeroInitialization = true;
}
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
CCE->arg_begin(), CCE->arg_end(),
- RequiresZeroInitialization);
+ CCE->requiresZeroInitialization());
return;
} else if (Init && isa<ImplicitValueInitExpr>(Init) &&
CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
@@ -1230,8 +1239,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::BasicBlock *contBB = 0;
llvm::Value *allocation = RV.getScalarVal();
- unsigned AS =
- cast<llvm::PointerType>(allocation->getType())->getAddressSpace();
+ unsigned AS = allocation->getType()->getPointerAddressSpace();
// The null-check means that the initializer is conditionally
// evaluated.
@@ -1377,8 +1385,14 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (UseGlobalDelete) {
// If we're supposed to call the global delete, make sure we do so
// even if the destructor throws.
+
+ // Derive the complete-object pointer, which is what we need
+ // to pass to the deallocation function.
+ llvm::Value *completePtr =
+ CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType);
+
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
- Ptr, OperatorDelete,
+ completePtr, OperatorDelete,
ElementType);
}
@@ -1390,8 +1404,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
= CGF.BuildVirtualCall(Dtor,
UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
Ptr, Ty);
- CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
- 0, 0);
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
+ Ptr, /*VTT=*/0, 0, 0);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 0233745afa91..66b6f8629a52 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -427,6 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -640,7 +641,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
LValue LV = EmitCompoundAssignLValue(E, Func, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -675,7 +676,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LV = EmitBinAssignLValue(E, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index a17a43639ad7..206f74a30258 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -24,7 +24,7 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -79,12 +79,12 @@ private:
CharUnits getAlignment(const llvm::Constant *C) const {
if (Packed) return CharUnits::One();
return CharUnits::fromQuantity(
- CGM.getTargetData().getABITypeAlignment(C->getType()));
+ CGM.getDataLayout().getABITypeAlignment(C->getType()));
}
CharUnits getSizeInChars(const llvm::Constant *C) const {
return CharUnits::fromQuantity(
- CGM.getTargetData().getTypeAllocSize(C->getType()));
+ CGM.getDataLayout().getTypeAllocSize(C->getType()));
}
};
@@ -204,7 +204,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
if (!FitsCompletelyInPreviousByte) {
unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
Tmp = Tmp.lshr(NewFieldWidth);
Tmp = Tmp.trunc(BitsInPreviousByte);
@@ -220,7 +220,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
}
Tmp = Tmp.zext(CharWidth);
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
if (FitsCompletelyInPreviousByte)
Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
} else {
@@ -269,7 +269,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
while (FieldValue.getBitWidth() > CharWidth) {
llvm::APInt Tmp;
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
// We want the high bits.
Tmp =
FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth);
@@ -292,7 +292,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
"Should not have more than a byte left!");
if (FieldValue.getBitWidth() < CharWidth) {
- if (CGM.getTargetData().isBigEndian()) {
+ if (CGM.getDataLayout().isBigEndian()) {
unsigned BitWidth = FieldValue.getBitWidth();
FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth);
@@ -337,7 +337,7 @@ void ConstStructBuilder::ConvertStructToPacked() {
llvm::Constant *C = Elements[i];
CharUnits ElementAlign = CharUnits::fromQuantity(
- CGM.getTargetData().getABITypeAlignment(C->getType()));
+ CGM.getDataLayout().getABITypeAlignment(C->getType()));
CharUnits AlignedElementOffsetInChars =
ElementOffsetInChars.RoundUpToAlignment(ElementAlign);
@@ -379,7 +379,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
unsigned FieldNo = 0;
unsigned ElementNo = 0;
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(CGM.getContext());
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -478,7 +478,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
unsigned FieldNo = 0;
const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ bool IsMsStruct = RD->isMsStruct(CGM.getContext());
uint64_t OffsetBits = CGM.getContext().toBits(Offset);
for (RecordDecl::field_iterator Field = RD->field_begin(),
@@ -665,8 +665,8 @@ public:
SmallVector<llvm::Type*, 2> Types;
Elts.push_back(C);
Types.push_back(C->getType());
- unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
- unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(destType);
+ unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType());
+ unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destType);
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
@@ -691,6 +691,9 @@ public:
case CK_Dependent: llvm_unreachable("saw dependent cast!");
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
case CK_ReinterpretMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
@@ -811,11 +814,7 @@ public:
return llvm::ConstantArray::get(AType, Elts);
}
- llvm::Constant *EmitStructInitialization(InitListExpr *ILE) {
- return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
- }
-
- llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) {
+ llvm::Constant *EmitRecordInitialization(InitListExpr *ILE) {
return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
@@ -828,10 +827,7 @@ public:
return EmitArrayInitialization(ILE);
if (ILE->getType()->isRecordType())
- return EmitStructInitialization(ILE);
-
- if (ILE->getType()->isUnionType())
- return EmitUnionInitialization(ILE);
+ return EmitRecordInitialization(ILE);
return 0;
}
@@ -999,6 +995,9 @@ public:
T = Typeid->getExprOperand()->getType();
return CGM.GetAddrOfRTTIDescriptor(T);
}
+ case Expr::CXXUuidofExprClass: {
+ return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));
+ }
}
return 0;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 1cccafe0d787..b429b1d6e47e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -28,7 +28,7 @@
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Support/CFG.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdarg>
using namespace clang;
@@ -45,6 +45,7 @@ struct BinOpInfo {
Value *RHS;
QualType Ty; // Computation Type.
BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
+ bool FPContractable;
const Expr *E; // Entire expr, for error unsupported. May not be binop.
};
@@ -80,7 +81,11 @@ public:
llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); }
LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); }
- LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); }
+ LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::TypeCheckKind TCK) {
+ return CGF.EmitCheckedLValue(E, TCK);
+ }
+
+ void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
Value *EmitLoadOfLValue(LValue LV) {
return CGF.EmitLoadOfLValue(LV).getScalarVal();
@@ -90,13 +95,19 @@ public:
/// 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));
+ return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load));
}
/// EmitConversionToBool - Convert the specified expression value to a
/// boolean (i1) truth value. This is equivalent to "Val != 0".
Value *EmitConversionToBool(Value *Src, QualType DstTy);
+ /// \brief Emit a check that a conversion to or from a floating-point type
+ /// does not overflow.
+ void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType,
+ Value *Src, QualType SrcType,
+ QualType DstType, llvm::Type *DstTy);
+
/// EmitScalarConversion - Emit a conversion from the specified type to the
/// specified destination type, both of which are LLVM scalar types.
Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy);
@@ -391,34 +402,26 @@ public:
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(Ops);
}
}
-
+
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
- bool isTrapvOverflowBehavior() {
- return CGF.getContext().getLangOpts().getSignedOverflowBehavior()
- == LangOptions::SOB_Trapping;
- }
/// Create a binary op that checks for overflow.
/// Currently only supports +, - and *.
Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops);
- // Emit the overflow BB when -ftrapv option is activated.
- void EmitOverflowBB(llvm::BasicBlock *overflowBB) {
- Builder.SetInsertPoint(overflowBB);
- llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap);
- Builder.CreateCall(Trap);
- Builder.CreateUnreachable();
- }
+
// Check for undefined division and modulus behaviors.
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
@@ -537,6 +540,110 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
return EmitPointerToBoolConversion(Src);
}
+void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
+ QualType OrigSrcType,
+ Value *Src, QualType SrcType,
+ QualType DstType,
+ llvm::Type *DstTy) {
+ using llvm::APFloat;
+ using llvm::APSInt;
+
+ llvm::Type *SrcTy = Src->getType();
+
+ llvm::Value *Check = 0;
+ if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
+ // Integer to floating-point. This can fail for unsigned short -> __half
+ // or unsigned __int128 -> float.
+ assert(DstType->isFloatingType());
+ bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType();
+
+ APFloat LargestFloat =
+ APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType));
+ APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned);
+
+ bool IsExact;
+ if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero,
+ &IsExact) != APFloat::opOK)
+ // The range of representable values of this floating point type includes
+ // all values of this integer type. Don't need an overflow check.
+ return;
+
+ llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt);
+ if (SrcIsUnsigned)
+ Check = Builder.CreateICmpULE(Src, Max);
+ else {
+ llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt);
+ llvm::Value *GE = Builder.CreateICmpSGE(Src, Min);
+ llvm::Value *LE = Builder.CreateICmpSLE(Src, Max);
+ Check = Builder.CreateAnd(GE, LE);
+ }
+ } else {
+ // Floating-point to integer or floating-point to floating-point. This has
+ // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the
+ // destination type.
+ const llvm::fltSemantics &SrcSema =
+ CGF.getContext().getFloatTypeSemantics(OrigSrcType);
+ APFloat MaxSrc(SrcSema, APFloat::uninitialized);
+ APFloat MinSrc(SrcSema, APFloat::uninitialized);
+
+ if (isa<llvm::IntegerType>(DstTy)) {
+ unsigned Width = CGF.getContext().getIntWidth(DstType);
+ bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
+
+ APSInt Min = APSInt::getMinValue(Width, Unsigned);
+ if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
+ APFloat::opOverflow)
+ // Don't need an overflow check for lower bound. Just check for
+ // -Inf/NaN.
+ MinSrc = APFloat::getLargest(SrcSema, true);
+
+ APSInt Max = APSInt::getMaxValue(Width, Unsigned);
+ if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
+ APFloat::opOverflow)
+ // Don't need an overflow check for upper bound. Just check for
+ // +Inf/NaN.
+ MaxSrc = APFloat::getLargest(SrcSema, false);
+ } else {
+ const llvm::fltSemantics &DstSema =
+ CGF.getContext().getFloatTypeSemantics(DstType);
+ bool IsInexact;
+
+ MinSrc = APFloat::getLargest(DstSema, true);
+ if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
+ APFloat::opOverflow)
+ MinSrc = APFloat::getLargest(SrcSema, true);
+
+ MaxSrc = APFloat::getLargest(DstSema, false);
+ if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
+ APFloat::opOverflow)
+ MaxSrc = APFloat::getLargest(SrcSema, false);
+ }
+
+ // If we're converting from __half, convert the range to float to match
+ // the type of src.
+ if (OrigSrcType->isHalfType()) {
+ const llvm::fltSemantics &Sema =
+ CGF.getContext().getFloatTypeSemantics(SrcType);
+ bool IsInexact;
+ MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ }
+
+ llvm::Value *GE =
+ Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
+ Check = Builder.CreateAnd(GE, LE);
+ }
+
+ // FIXME: Provide a SourceLocation.
+ llvm::Constant *StaticArgs[] = {
+ CGF.EmitCheckTypeDescriptor(OrigSrcType),
+ CGF.EmitCheckTypeDescriptor(DstType)
+ };
+ CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc);
+}
+
/// EmitScalarConversion - Emit a conversion from the specified type to the
/// specified destination type, both of which are LLVM scalar types.
Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
@@ -547,6 +654,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (DstType->isVoidType()) return 0;
+ llvm::Value *OrigSrc = Src;
+ QualType OrigSrcType = SrcType;
llvm::Type *SrcTy = Src->getType();
// Floating casts might be a bit special: if we're doing casts to / from half
@@ -620,6 +729,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
Value *Res = NULL;
llvm::Type *ResTy = DstTy;
+ // An overflowing conversion has undefined behavior if either the source type
+ // or the destination type is a floating-point type.
+ if (CGF.getLangOpts().SanitizeFloatCastOverflow &&
+ (OrigSrcType->isFloatingType() || DstType->isFloatingType()))
+ EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy);
+
// Cast to half via float
if (DstType->isHalfType())
DstTy = CGF.FloatTy;
@@ -686,6 +801,54 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
return llvm::Constant::getNullValue(ConvertType(Ty));
}
+/// \brief Emit a sanitization check for the given "binary" operation (which
+/// might actually be a unary increment which has been lowered to a binary
+/// operation). The check passes if \p Check, which is an \c i1, is \c true.
+void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+ StringRef CheckName;
+ llvm::SmallVector<llvm::Constant *, 4> StaticData;
+ llvm::SmallVector<llvm::Value *, 2> DynamicData;
+
+ BinaryOperatorKind Opcode = Info.Opcode;
+ if (BinaryOperator::isCompoundAssignmentOp(Opcode))
+ Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode);
+
+ StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc()));
+ const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E);
+ if (UO && UO->getOpcode() == UO_Minus) {
+ CheckName = "negate_overflow";
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType()));
+ DynamicData.push_back(Info.RHS);
+ } else {
+ if (BinaryOperator::isShiftOp(Opcode)) {
+ // Shift LHS negative or too large, or RHS out of bounds.
+ CheckName = "shift_out_of_bounds";
+ const BinaryOperator *BO = cast<BinaryOperator>(Info.E);
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType()));
+ StaticData.push_back(
+ CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType()));
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {
+ // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1).
+ CheckName = "divrem_overflow";
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ } else {
+ // Signed arithmetic overflow (+, -, *).
+ switch (Opcode) {
+ case BO_Add: CheckName = "add_overflow"; break;
+ case BO_Sub: CheckName = "sub_overflow"; break;
+ case BO_Mul: CheckName = "mul_overflow"; break;
+ default: llvm_unreachable("unexpected opcode for bin op check");
+ }
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ }
+ DynamicData.push_back(Info.LHS);
+ DynamicData.push_back(Info.RHS);
+ }
+
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData);
+}
+
//===----------------------------------------------------------------------===//
// Visitor Methods
//===----------------------------------------------------------------------===//
@@ -802,7 +965,8 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
// debug info size.
CGDebugInfo *DI = CGF.getDebugInfo();
if (DI &&
- CGF.CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) {
+ 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()))
@@ -1032,7 +1196,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// are in the same order as in the CastKind enum.
switch (Kind) {
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
-
+ case CK_BuiltinFnToFnPtr:
+ llvm_unreachable("builtin functions are handled elsewhere");
+
case CK_LValueBitCast:
case CK_ObjCObjectLValueCast: {
Value *V = EmitLValue(E).getAddress();
@@ -1055,19 +1221,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));
case CK_BaseToDerived: {
- const CXXRecordDecl *DerivedClassDecl =
- DestTy->getCXXRecordDeclForPointerType();
-
- return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
+ assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
+
+ return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- const RecordType *DerivedClassTy =
- E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
- cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+ const CXXRecordDecl *DerivedClassDecl =
+ E->getType()->getPointeeCXXRecordDecl();
+ assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!");
return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
CE->path_begin(), CE->path_end(),
@@ -1248,17 +1413,20 @@ llvm::Value *ScalarExprEmitter::
EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
llvm::Value *InVal,
llvm::Value *NextVal, bool IsInc) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
+ // Fall through.
case LangOptions::SOB_Trapping:
BinOpInfo BinOp;
BinOp.LHS = InVal;
BinOp.RHS = NextVal;
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Add;
+ BinOp.FPContractable = false;
BinOp.E = E;
return EmitOverflowCheckedBinOp(BinOp);
}
@@ -1300,7 +1468,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Most common case by far: integer increment.
} else if (type->isIntegerType()) {
- llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
+ llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
// Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here.
@@ -1320,7 +1488,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
= CGF.getContext().getAsVariableArrayType(type)) {
llvm::Value *numElts = CGF.getVLASize(vla).first;
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
@@ -1330,7 +1498,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *amt = Builder.getInt32(amount);
value = CGF.EmitCastToVoidPtr(value);
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
@@ -1339,7 +1507,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// For everything else, we can just do a simple increment.
} else {
llvm::Value *amt = Builder.getInt32(amount);
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.ptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
@@ -1400,7 +1568,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *sizeValue =
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
- if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
else
value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
@@ -1444,6 +1612,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub;
+ BinOp.FPContractable = false;
BinOp.E = E;
return EmitSub(BinOp);
}
@@ -1652,6 +1821,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
Result.RHS = Visit(E->getRHS());
Result.Ty = E->getType();
Result.Opcode = E->getOpcode();
+ Result.FPContractable = E->isFPContractable();
Result.E = E;
return Result;
}
@@ -1678,9 +1848,10 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.RHS = Visit(E->getRHS());
OpInfo.Ty = E->getComputationResultType();
OpInfo.Opcode = E->getOpcode();
+ OpInfo.FPContractable = false;
OpInfo.E = E;
// Load/convert the LHS.
- LValue LHSLV = EmitCheckedLValue(E->getLHS());
+ LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
@@ -1740,7 +1911,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -1752,56 +1923,44 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
}
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
- const BinOpInfo &Ops,
- llvm::Value *Zero, bool isDiv) {
- llvm::Function::iterator insertPt = Builder.GetInsertBlock();
- llvm::BasicBlock *contBB =
- CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn,
- llvm::next(insertPt));
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
+ const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
+ llvm::Value *Cond = 0;
+
+ if (CGF.getLangOpts().SanitizeDivideByZero)
+ Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
- llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
+ if (CGF.getLangOpts().SanitizeSignedIntegerOverflow &&
+ Ops.Ty->hasSignedIntegerRepresentation()) {
+ llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::Value *IntMin =
Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth()));
llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL);
- llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero);
- llvm::Value *LHSCmp = Builder.CreateICmpEQ(Ops.LHS, IntMin);
- llvm::Value *RHSCmp = Builder.CreateICmpEQ(Ops.RHS, NegOne);
- llvm::Value *Cond2 = Builder.CreateAnd(LHSCmp, RHSCmp, "and");
- Builder.CreateCondBr(Builder.CreateOr(Cond1, Cond2, "or"),
- overflowBB, contBB);
- } else {
- CGF.Builder.CreateCondBr(Builder.CreateICmpEQ(Ops.RHS, Zero),
- overflowBB, contBB);
+ llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin);
+ llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
+ llvm::Value *Overflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
+ Cond = Cond ? Builder.CreateAnd(Cond, Overflow, "and") : Overflow;
}
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(contBB);
+
+ if (Cond)
+ EmitBinOpCheck(Cond, Ops);
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (isTrapvOverflowBehavior()) {
+ if (CGF.getLangOpts().SanitizeDivideByZero ||
+ CGF.getLangOpts().SanitizeSignedIntegerOverflow) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- else if (Ops.Ty->isRealFloatingType()) {
- llvm::Function::iterator insertPt = Builder.GetInsertBlock();
- llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn,
- llvm::next(insertPt));
- llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow",
- CGF.CurFn);
- CGF.Builder.CreateCondBr(Builder.CreateFCmpOEQ(Ops.RHS, Zero),
- overflowBB, DivCont);
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(DivCont);
- }
+ else if (CGF.getLangOpts().SanitizeDivideByZero &&
+ Ops.Ty->isRealFloatingType())
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
}
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
- if (CGF.getContext().getLangOpts().OpenCL) {
+ if (CGF.getLangOpts().OpenCL) {
// OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp
llvm::Type *ValTy = Val->getType();
if (ValTy->isFloatTy() ||
@@ -1819,7 +1978,7 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
- if (isTrapvOverflowBehavior()) {
+ if (CGF.getLangOpts().SanitizeDivideByZero) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
@@ -1866,6 +2025,19 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Value *result = Builder.CreateExtractValue(resultAndOverflow, 0);
Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1);
+ // Handle overflow with llvm.trap if no custom handler has been specified.
+ const std::string *handlerName =
+ &CGF.getLangOpts().OverflowHandler;
+ if (handlerName->empty()) {
+ // If the signed-integer-overflow sanitizer is enabled, emit a call to its
+ // runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
+ if (CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
+ else
+ CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
+ return result;
+ }
+
// Branch in case of overflow.
llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
llvm::Function::iterator insertPt = initialBB;
@@ -1875,15 +2047,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.CreateCondBr(overflow, overflowBB, continueBB);
- // Handle overflow with llvm.trap.
- const std::string *handlerName =
- &CGF.getContext().getLangOpts().OverflowHandler;
- if (handlerName->empty()) {
- EmitOverflowBB(overflowBB);
- Builder.SetInsertPoint(continueBB);
- return result;
- }
-
// If an overflow handler is set, then we want to call it and then use its
// result, if it returns.
Builder.SetInsertPoint(overflowBB);
@@ -2001,24 +2164,106 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
}
+// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
+// Addend. Use negMul and negAdd to negate the first operand of the Mul or
+// the add operand respectively. This allows fmuladd to represent a*b-c, or
+// c-a*b. Patterns in LLVM should catch the negated forms and translate them to
+// efficient operations.
+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) {
+ MulOp0 =
+ Builder.CreateFSub(
+ llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0,
+ "neg");
+ } else if (negAdd) {
+ Addend =
+ Builder.CreateFSub(
+ llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend,
+ "neg");
+ }
+
+ Value *FMulAdd =
+ Builder.CreateCall3(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()),
+ MulOp0, MulOp1, Addend);
+ MulOp->eraseFromParent();
+
+ return FMulAdd;
+}
+
+// Check whether it would be legal to emit an fmuladd intrinsic call to
+// represent op and if so, build the fmuladd.
+//
+// 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,
+ const CodeGenFunction &CGF, CGBuilderTy &Builder,
+ bool isSub=false) {
+
+ assert((op.Opcode == BO_Add || op.Opcode == BO_AddAssign ||
+ op.Opcode == BO_Sub || op.Opcode == BO_SubAssign) &&
+ "Only fadd/fsub can be the root of an fmuladd.");
+
+ // Check whether this op is marked as fusable.
+ if (!op.FPContractable)
+ return 0;
+
+ // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
+ // either disabled, or handled entirely by the LLVM backend).
+ if (CGF.getLangOpts().getFPContractMode() != LangOptions::FPC_On)
+ return 0;
+
+ // We have a potentially fusable op. Look for a mul on one of the operands.
+ if (llvm::BinaryOperator* LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
+ if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+ assert(LHSBinOp->getNumUses() == 0 &&
+ "Operations with multiple uses shouldn't be contracted.");
+ return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub);
+ }
+ } else if (llvm::BinaryOperator* RHSBinOp =
+ dyn_cast<llvm::BinaryOperator>(op.RHS)) {
+ if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) {
+ assert(RHSBinOp->getNumUses() == 0 &&
+ "Operations with multiple uses shouldn't be contracted.");
+ return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false);
+ }
+ }
+
+ return 0;
+}
+
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.LHS->getType()->isPointerTy() ||
op.RHS->getType()->isPointerTy())
return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
- if (op.LHS->getType()->isFPOrFPVectorTy())
+ if (op.LHS->getType()->isFPOrFPVectorTy()) {
+ // Try to form an fmuladd.
+ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
+ return FMulAdd;
+
return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ }
return Builder.CreateAdd(op.LHS, op.RHS, "add");
}
@@ -2027,18 +2272,24 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// The LHS is always a pointer if either side is.
if (!op.LHS->getType()->isPointerTy()) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined:
- return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
+ switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
+ case LangOptions::SOB_Undefined:
+ if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
+ // Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
- if (op.LHS->getType()->isFPOrFPVectorTy())
+ if (op.LHS->getType()->isFPOrFPVectorTy()) {
+ // Try to form an fmuladd.
+ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
+ return FMulAdd;
return Builder.CreateFSub(op.LHS, op.RHS, "sub");
+ }
return Builder.CreateSub(op.LHS, op.RHS, "sub");
}
@@ -2108,14 +2359,34 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.CatchUndefined
- && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ if (CGF.getLangOpts().SanitizeShift &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
- llvm::ConstantInt::get(RHS->getType(), Width)),
- Cont, CGF.getTrapBB());
- CGF.EmitBlock(Cont);
+ llvm::Value *WidthMinusOne =
+ llvm::ConstantInt::get(RHS->getType(), Width - 1);
+ // FIXME: Emit the branching explicitly rather than emitting the check
+ // twice.
+ EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops);
+
+ if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ // Check whether we are shifting any non-zero bits off the top of the
+ // integer.
+ llvm::Value *BitsShiftedOff =
+ Builder.CreateLShr(Ops.LHS,
+ Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
+ /*NUW*/true, /*NSW*/true),
+ "shl.check");
+ if (CGF.getLangOpts().CPlusPlus) {
+ // In C99, we are not permitted to shift a 1 bit into the sign bit.
+ // Under C++11's rules, shifting a 1 bit into the sign bit is
+ // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't
+ // define signed left shifts, so we use the C99 and C++11 rules there).
+ llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1);
+ BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
+ }
+ llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
+ EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
+ }
}
return Builder.CreateShl(Ops.LHS, RHS, "shl");
@@ -2128,14 +2399,11 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.CatchUndefined
- && isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ if (CGF.getLangOpts().SanitizeShift &&
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS,
- llvm::ConstantInt::get(RHS->getType(), Width)),
- Cont, CGF.getTrapBB());
- CGF.EmitBlock(Cont);
+ llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
+ EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
}
if (Ops.Ty->hasUnsignedIntegerRepresentation())
@@ -2326,7 +2594,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
break;
@@ -2336,7 +2604,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// __block variables need to have the rhs evaluated first, plus
// this should improve codegen just a little.
RHS = Visit(E->getRHS());
- LHS = EmitCheckedLValue(E->getLHS());
+ LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
@@ -2353,7 +2621,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOpts().CPlusPlus)
+ if (!CGF.getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -2567,7 +2835,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// OpenCL: If the condition is a vector, we can treat this condition like
// the select function.
- if (CGF.getContext().getLangOpts().OpenCL
+ if (CGF.getLangOpts().OpenCL
&& condExpr->getType()->isVectorType()) {
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 4ac172d1cbb5..c90e4eca8476 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -21,7 +21,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
@@ -440,8 +440,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
SourceLocation StartLoc) {
FunctionArgList args;
// Check if we should generate debug info for this method.
- if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ if (!OMD->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
@@ -613,7 +613,16 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
// which translates to objc_storeStrong. This isn't required, but
// it's slightly nicer.
} else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) {
- Kind = Expression;
+ // Using standard expression emission for the setter is only
+ // acceptable if the ivar is __strong, which won't be true if
+ // the property is annotated with __attribute__((NSObject)).
+ // TODO: falling all the way back to objc_setProperty here is
+ // just laziness, though; we could still use objc_storeStrong
+ // if we hacked it right.
+ if (ivarType.getObjCLifetime() == Qualifiers::OCL_Strong)
+ Kind = Expression;
+ else
+ Kind = SetPropertyAndExpressionGet;
return;
// Otherwise, we need to at least use setProperty. However, if
@@ -801,6 +810,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
+ // We don't need to do anything for a zero-size struct.
+ if (strategy.getIvarSize().isZero())
+ return;
+
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
// Currently, all atomic accesses have to be through integer
@@ -1032,12 +1045,7 @@ static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
static bool UseOptimizedSetter(CodeGenModule &CGM) {
if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
return false;
- const TargetInfo &Target = CGM.getContext().getTargetInfo();
-
- if (Target.getPlatformName() != "macosx")
- return false;
-
- return Target.getPlatformMinVersion() >= VersionTuple(10, 8);
+ return CGM.getLangOpts().ObjCRuntime.hasOptimizedSetter();
}
void
@@ -1064,6 +1072,10 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
+ // We don't need to do anything for a zero-size struct.
+ if (strategy.getIvarSize().isZero())
+ return;
+
llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()];
LValue ivarLValue =
@@ -1097,7 +1109,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
llvm::Value *setOptimizedPropertyFn = 0;
llvm::Value *setPropertyFn = 0;
if (UseOptimizedSetter(CGM)) {
- // 10.8 code and GC is off
+ // 10.8 and iOS 6.0 code and GC is off
setOptimizedPropertyFn =
CGM.getObjCRuntime()
.GetOptimizedPropertySetFunction(strategy.isAtomic(),
@@ -1209,7 +1221,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
ivarRef.getType(), VK_RValue, OK_Ordinary,
- SourceLocation());
+ SourceLocation(), false);
EmitStmt(&assign);
}
@@ -1697,11 +1709,11 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
// references to the runtime support library. We don't really
// permit this to fail, but we need a particular relocation style.
if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) {
- if (!CGM.getLangOpts().ObjCRuntime.hasARC())
+ if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC())
f->setLinkage(llvm::Function::ExternalWeakLinkage);
// set nonlazybind attribute for these APIs for performance.
if (fnName == "objc_retain" || fnName == "objc_release")
- f->addFnAttr(llvm::Attribute::NonLazyBind);
+ f->addFnAttr(llvm::Attributes::NonLazyBind);
}
return fn;
@@ -1945,6 +1957,28 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
}
}
+/// Destroy a __strong variable.
+///
+/// At -O0, emit a call to store 'null' into the address;
+/// instrumenting tools prefer this because the address is exposed,
+/// but it's relatively cumbersome to optimize.
+///
+/// At -O1 and above, just load and call objc_release.
+///
+/// call void \@objc_storeStrong(i8** %addr, i8* null)
+void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) {
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
+ llvm::Value *null = llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(addrTy->getElementType()));
+ EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
+ return;
+ }
+
+ llvm::Value *value = Builder.CreateLoad(addr);
+ EmitARCRelease(value, precise);
+}
+
/// Store into a strong object. Always calls this:
/// call void \@objc_storeStrong(i8** %addr, i8* %value)
llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
@@ -2218,15 +2252,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
- CGF.EmitARCRelease(ptr, /*precise*/ true);
+ CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
- CGF.EmitARCRelease(ptr, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2730,7 +2762,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
// Keep track of the current cleanup stack depth.
RunCleanupsScope Scope(*this);
- if (CGM.getLangOpts().ObjCRuntime.hasARC()) {
+ if (CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
} else {
@@ -2826,9 +2858,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
"__assign_helper_atomic_property_",
&CGM.getModule());
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
-
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -2845,8 +2876,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
Expr *Args[2] = { &DST, &SRC };
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
- Args, 2, DestTy->getPointeeType(),
- VK_LValue, SourceLocation());
+ Args, DestTy->getPointeeType(),
+ VK_LValue, SourceLocation(), false);
EmitStmt(&TheCall);
@@ -2912,9 +2943,8 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__copy_helper_atomic_property_", &CGM.getModule());
- if (CGM.getModuleDebugInfo())
- DebugInfo = CGM.getModuleDebugInfo();
-
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -2940,7 +2970,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
CXXConstructExpr::Create(C, Ty, SourceLocation(),
CXXConstExpr->getConstructor(),
CXXConstExpr->isElidable(),
- &ConstructorArgs[0], ConstructorArgs.size(),
+ ConstructorArgs,
CXXConstExpr->hadMultipleCandidates(),
CXXConstExpr->isListInitialization(),
CXXConstExpr->requiresZeroInitialization(),
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 6d129d02a561..68d234dde6ea 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -33,7 +33,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdarg>
@@ -224,6 +224,25 @@ protected:
llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size());
return MakeGlobal(ArrayTy, V, Name, linkage);
}
+ /// Returns a property name and encoding string.
+ llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
+ const Decl *Container) {
+ ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ if ((R.getKind() == ObjCRuntime::GNUstep) &&
+ (R.getVersion() >= VersionTuple(1, 6))) {
+ std::string NameAndAttributes;
+ std::string TypeStr;
+ CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr);
+ NameAndAttributes += '\0';
+ NameAndAttributes += TypeStr.length() + 3;
+ NameAndAttributes += TypeStr;
+ NameAndAttributes += '\0';
+ NameAndAttributes += PD->getNameAsString();
+ return llvm::ConstantExpr::getGetElementPtr(
+ CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
+ }
+ return MakeConstantString(PD->getNameAsString());
+ }
/// Ensures that the value has the required type, by inserting a bitcast if
/// required. This function lets us avoid inserting bitcasts that are
/// redundant.
@@ -514,7 +533,10 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
-
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ return NULLPtr;
+ }
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
return 0;
}
@@ -578,6 +600,8 @@ class CGObjCGNUstep : public CGObjCGNU {
/// Type of an slot structure pointer. This is returned by the various
/// lookup functions.
llvm::Type *SlotTy;
+ public:
+ virtual llvm::Constant *GetEHType(QualType T);
protected:
virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
llvm::Value *&Receiver,
@@ -653,11 +677,40 @@ class CGObjCGNUstep : public CGObjCGNU {
}
};
-/// The ObjFW runtime, which closely follows the GCC runtime's
-/// compiler ABI. Support here is due to Jonathan Schleifer, the
-/// ObjFW maintainer.
-class CGObjCObjFW : public CGObjCGCC {
- /// Emit class references unconditionally as direct symbol references.
+/// Support for the ObjFW runtime. Support here is due to
+/// Jonathan Schleifer <js@webkeks.org>, the ObjFW maintainer.
+class CGObjCObjFW: public CGObjCGNU {
+protected:
+ /// The GCC ABI message lookup function. Returns an IMP pointing to the
+ /// method implementation for this message.
+ LazyRuntimeFunction MsgLookupFn;
+ /// 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;
+
+ virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
+ llvm::Value *&Receiver,
+ llvm::Value *cmd,
+ llvm::MDNode *node) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *args[] = {
+ EnforceType(Builder, Receiver, IdTy),
+ EnforceType(Builder, cmd, SelectorTy) };
+ llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ imp->setMetadata(msgSendMDKind, node);
+ return imp.getInstruction();
+ }
+
+ virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
+ llvm::Value *ObjCSuper,
+ llvm::Value *cmd) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
+ PtrToObjCSuperTy), cmd};
+ return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ }
+
virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
const std::string &Name, bool isWeak) {
if (isWeak)
@@ -678,7 +731,13 @@ class CGObjCObjFW : public CGObjCGCC {
}
public:
- CGObjCObjFW(CodeGenModule &Mod): CGObjCGCC(Mod) {}
+ CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
+ // IMP objc_msg_lookup(id, SEL);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+ // IMP objc_msg_lookup_super(struct objc_super*, SEL);
+ MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
+ PtrToObjCSuperTy, SelectorTy, NULL);
+ }
};
} // end anonymous namespace
@@ -909,29 +968,30 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
- if (!CGM.getLangOpts().CPlusPlus) {
- if (T->isObjCIdType()
- || T->isObjCQualifiedIdType()) {
- // With the old ABI, there was only one kind of catchall, which broke
- // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
- // a pointer indicating object catchalls, and NULL to indicate real
- // catchalls
- if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
- return MakeConstantString("@id");
- } else {
- return 0;
- }
- }
-
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *OPT =
- T->getAs<ObjCObjectPointerType>();
- assert(OPT && "Invalid @catch type.");
- const ObjCInterfaceDecl *IDecl =
- OPT->getObjectType()->getInterface();
- assert(IDecl && "Invalid @catch type.");
- return MakeConstantString(IDecl->getIdentifier()->getName());
+ if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
+ // With the old ABI, there was only one kind of catchall, which broke
+ // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
+ // a pointer indicating object catchalls, and NULL to indicate real
+ // catchalls
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
+ return MakeConstantString("@id");
+ } else {
+ return 0;
+ }
}
+
+ // All other types should be Objective-C interface pointer types.
+ const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>();
+ assert(OPT && "Invalid @catch type.");
+ const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface();
+ assert(IDecl && "Invalid @catch type.");
+ return MakeConstantString(IDecl->getIdentifier()->getName());
+}
+
+llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
+ if (!CGM.getLangOpts().CPlusPlus)
+ return CGObjCGNU::GetEHType(T);
+
// For Objective-C++, we want to provide the ability to catch both C++ and
// Objective-C objects in the same function.
@@ -1436,7 +1496,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(Zero);
Elements.push_back(llvm::ConstantInt::get(LongTy, info));
if (isMeta) {
- llvm::TargetData td(&TheModule);
+ llvm::DataLayout td(&TheModule);
Elements.push_back(
llvm::ConstantInt::get(LongTy,
td.getTypeSizeInBits(ClassTy) /
@@ -1595,13 +1655,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
- InstanceMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
- InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
- } else {
OptionalInstanceMethodNames.push_back(
MakeConstantString((*iter)->getSelector().getAsString()));
OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ InstanceMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
// Collect information about class methods:
@@ -1615,13 +1675,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
- ClassMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
- ClassMethodTypes.push_back(MakeConstantString(TypeStr));
- } else {
OptionalClassMethodNames.push_back(
MakeConstantString((*iter)->getSelector().getAsString()));
OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
+ } else {
+ ClassMethodNames.push_back(
+ MakeConstantString((*iter)->getSelector().getAsString()));
+ ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
@@ -1656,7 +1716,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Fields;
ObjCPropertyDecl *property = *iter;
- Fields.push_back(MakeConstantString(property->getNameAsString()));
+
+ Fields.push_back(MakePropertyEncodingString(property, PD));
+
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
property->getPropertyAttributes()));
Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
@@ -1909,7 +1971,7 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
- Fields.push_back(MakeConstantString(property->getNameAsString()));
+ Fields.push_back(MakePropertyEncodingString(property, OID));
Fields.push_back(llvm::ConstantInt::get(Int8Ty,
property->getPropertyAttributes()));
Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized));
@@ -2011,7 +2073,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
// For non-fragile ivars, set the instance size to 0 - {the size of just this
// class}. The runtime will then set this to the correct value on load.
- if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) {
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
@@ -2026,7 +2088,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Get the offset
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
uint64_t Offset = BaseOffset;
- if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) {
+ if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
Offset = BaseOffset - superInstanceSize;
}
llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
@@ -2334,7 +2396,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
// sizeof(ModuleTy)
- llvm::TargetData td(&TheModule);
+ llvm::DataLayout td(&TheModule);
Elements.push_back(
llvm::ConstantInt::get(LongTy,
td.getTypeSizeInBits(ModuleTy) /
@@ -2488,7 +2550,7 @@ void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
// Unlike the Apple non-fragile runtimes, which also uses
// unwind-based zero cost exceptions, the GNU Objective C runtime's
// EH support isn't a veneer over C++ EH. Instead, exception
- // objects are created by __objc_exception_throw and destroyed by
+ // objects are created by objc_exception_throw and destroyed by
// the personality function; this avoids the need for bracketing
// catch handlers with calls to __blah_begin_catch/__blah_end_catch
// (or even _Unwind_DeleteException), but probably doesn't
@@ -2513,7 +2575,9 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
- CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ llvm::CallSite Throw =
+ CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
CGF.Builder.ClearInsertionPoint();
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index ef802a3ed0ca..2203f0182800 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -36,7 +36,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdio>
using namespace clang;
@@ -66,7 +66,8 @@ private:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend",
- llvm::Attribute::NonLazyBind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -433,19 +434,19 @@ public:
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
- // void objc_sync_enter (id)
+ // int objc_sync_enter (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
- // void objc_sync_exit (id)
+ // int objc_sync_exit (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
@@ -583,7 +584,8 @@ public:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
"_setjmp",
- llvm::Attribute::ReturnsTwice);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
public:
@@ -753,6 +755,74 @@ public:
: skip(_skip), scan(_scan) {}
};
+ /// opcode for captured block variables layout 'instructions'.
+ /// In the following descriptions, 'I' is the value of the immediate field.
+ /// (field following the opcode).
+ ///
+ enum BLOCK_LAYOUT_OPCODE {
+ /// An operator which affects how the following layout should be
+ /// interpreted.
+ /// I == 0: Halt interpretation and treat everything else as
+ /// a non-pointer. Note that this instruction is equal
+ /// to '\0'.
+ /// I != 0: Currently unused.
+ BLOCK_LAYOUT_OPERATOR = 0,
+
+ /// The next I+1 bytes do not contain a value of object pointer type.
+ /// Note that this can leave the stream unaligned, meaning that
+ /// subsequent word-size instructions do not begin at a multiple of
+ /// the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
+
+ /// The next I+1 words do not contain a value of object pointer type.
+ /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
+ /// when the required skip quantity is a multiple of the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
+
+ /// The next I+1 words are __strong pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_STRONG = 3,
+
+ /// The next I+1 words are pointers to __block variables.
+ BLOCK_LAYOUT_BYREF = 4,
+
+ /// The next I+1 words are __weak pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_WEAK = 5,
+
+ /// The next I+1 words are __unsafe_unretained pointers to
+ /// Objective-C objects or blocks.
+ BLOCK_LAYOUT_UNRETAINED = 6
+
+ /// The next I+1 words are block or object pointers with some
+ /// as-yet-unspecified ownership semantics. If we add more
+ /// flavors of ownership semantics, values will be taken from
+ /// this range.
+ ///
+ /// This is included so that older tools can at least continue
+ /// processing the layout past such things.
+ //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
+
+ /// All other opcodes are reserved. Halt interpretation and
+ /// treat everything else as opaque.
+ };
+
+ class RUN_SKIP {
+ public:
+ enum BLOCK_LAYOUT_OPCODE opcode;
+ CharUnits block_var_bytepos;
+ CharUnits block_var_size;
+ RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
+ CharUnits BytePos = CharUnits::Zero(),
+ CharUnits Size = CharUnits::Zero())
+ : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
+
+ // Allow sorting based on byte pos.
+ bool operator<(const RUN_SKIP &b) const {
+ return block_var_bytepos < b.block_var_bytepos;
+ }
+ };
+
protected:
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
@@ -761,6 +831,9 @@ protected:
// gc ivar layout bitmap calculation helper caches.
SmallVector<GC_IVAR, 16> SkipIvars;
SmallVector<GC_IVAR, 16> IvarsInfo;
+
+ // arc/mrr layout of captured block literal variables.
+ SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
/// LazySymbols - Symbols to generate a lazy reference for. See
/// DefinedSymbols and FinishModule().
@@ -869,6 +942,24 @@ protected:
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
+
+ Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT);
+
+ void UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize);
+
+ void BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos, bool &HasUnion);
+
+ void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion);
+
+ uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -959,6 +1050,8 @@ public:
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo);
};
@@ -1787,8 +1880,8 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
+
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
!CGM.getLangOpts().ObjCAutoRefCount)
return nullPtr;
@@ -1807,7 +1900,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
// Calculate the basic layout of the block structure.
const llvm::StructLayout *layout =
- CGM.getTargetData().getStructLayout(blockInfo.StructureType);
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
// Ignore the optional 'this' capture: C++ objects are not assumed
// to be GC'ed.
@@ -1860,7 +1953,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n block variable layout for block: ");
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -1872,6 +1965,476 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
return C;
}
+/// getBlockCaptureLifetime - This routine returns life time of the captured
+/// block variable for the purpose of block layout meta-data generation. FQT is
+/// the type of the variable captured in the block.
+Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT) {
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ return FQT.getObjCLifetime();
+
+ // MRR.
+ if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
+ return Qualifiers::OCL_ExplicitNone;
+
+ return Qualifiers::OCL_None;
+}
+
+void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize) {
+ // __block variables are passed by their descriptor address.
+ if (IsByref)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Strong)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Weak)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_ExplicitNone)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
+ FieldSize));
+ else
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
+ FieldOffset,
+ FieldSize));
+}
+
+void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion) {
+ bool IsUnion = (RD && RD->isUnion());
+ CharUnits MaxUnionSize = CharUnits::Zero();
+ const FieldDecl *MaxField = 0;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ CharUnits MaxFieldOffset = CharUnits::Zero();
+ CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
+
+ if (RecFields.empty())
+ return;
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ const FieldDecl *Field = RecFields[i];
+ // Note that 'i' here is actually the field index inside RD of Field,
+ // although this dependency is hidden.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ CharUnits FieldOffset =
+ CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
+
+ // Skip over unnamed or bitfields
+ if (!Field->getIdentifier() || Field->isBitField()) {
+ LastFieldBitfieldOrUnnamed = Field;
+ LastBitfieldOrUnnamedOffset = FieldOffset;
+ continue;
+ }
+
+ LastFieldBitfieldOrUnnamed = 0;
+ QualType FQT = Field->getType();
+ if (FQT->isRecordType() || FQT->isUnionType()) {
+ if (FQT->isUnionType())
+ HasUnion = true;
+
+ BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
+ BytePos + FieldOffset, HasUnion);
+ continue;
+ }
+
+ if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ uint64_t ElCount = CArray->getSize().getZExtValue();
+ assert(CArray && "only array with known element size is supported");
+ FQT = CArray->getElementType();
+ while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ ElCount *= CArray->getSize().getZExtValue();
+ FQT = CArray->getElementType();
+ }
+
+ assert(!FQT->isUnionType() &&
+ "layout for array of unions not supported");
+ if (FQT->isRecordType() && ElCount) {
+ int OldIndex = RunSkipBlockVars.size() - 1;
+ const RecordType *RT = FQT->getAs<RecordType>();
+ BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset,
+ HasUnion);
+
+ // Replicate layout information for each array element. Note that
+ // one element is already done.
+ uint64_t ElIx = 1;
+ for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
+ CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
+ for (int i = OldIndex+1; i <= FirstIndex; ++i)
+ RunSkipBlockVars.push_back(
+ RUN_SKIP(RunSkipBlockVars[i].opcode,
+ RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
+ RunSkipBlockVars[i].block_var_size));
+ }
+ continue;
+ }
+ }
+ CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
+ if (IsUnion) {
+ CharUnits UnionIvarSize = FieldSize;
+ if (UnionIvarSize > MaxUnionSize) {
+ MaxUnionSize = UnionIvarSize;
+ MaxField = Field;
+ MaxFieldOffset = FieldOffset;
+ }
+ } else {
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(FQT),
+ BytePos + FieldOffset,
+ FieldSize);
+ }
+ }
+
+ if (LastFieldBitfieldOrUnnamed) {
+ if (LastFieldBitfieldOrUnnamed->isBitField()) {
+ // Last field was a bitfield. Must update the info.
+ uint64_t BitFieldSize
+ = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
+ unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
+ ((BitFieldSize % ByteSizeInBits) != 0);
+ CharUnits Size = CharUnits::fromQuantity(UnsSize);
+ Size += LastBitfieldOrUnnamedOffset;
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ Size);
+ } else {
+ assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
+ // Last field was unnamed. Must update skip info.
+ CharUnits FieldSize
+ = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ FieldSize);
+ }
+ }
+
+ if (MaxField)
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(MaxField->getType()),
+ BytePos + MaxFieldOffset,
+ MaxUnionSize);
+}
+
+void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos,
+ bool &HasUnion) {
+ const RecordDecl *RD = RT->getDecl();
+ SmallVector<const FieldDecl*, 16> Fields;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i)
+ Fields.push_back(*i);
+ llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
+ const llvm::StructLayout *RecLayout =
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
+
+ BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
+}
+
+/// InlineLayoutInstruction - This routine produce an inline instruction for the
+/// block variable layout if it can. If not, it returns 0. Rules are as follow:
+/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
+/// an inline layout of value 0x0000000000000xyz is interpreted as follows:
+/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
+/// y captured object of BLOCK_LAYOUT_BYREF. Followed by
+/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
+/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
+/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
+uint64_t CGObjCCommonMac::InlineLayoutInstruction(
+ SmallVectorImpl<unsigned char> &Layout) {
+ uint64_t Result = 0;
+ if (Layout.size() <= 3) {
+ unsigned size = Layout.size();
+ unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
+ unsigned char inst;
+ enum BLOCK_LAYOUT_OPCODE opcode ;
+ switch (size) {
+ case 3:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[2];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ case 2:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG) {
+ strong_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else if (opcode == BLOCK_LAYOUT_BYREF) {
+ byref_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ break;
+
+ case 1:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ // Cannot inline when any of the word counts is 15. Because this is one less
+ // than the actual work count (so 15 means 16 actual word counts),
+ // and we can only display 0 thru 15 word counts.
+ if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
+ return 0;
+
+ unsigned count =
+ (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
+
+ if (size == count) {
+ if (strong_word_count)
+ Result = strong_word_count;
+ Result <<= 4;
+ if (byref_word_count)
+ Result += byref_word_count;
+ Result <<= 4;
+ if (weak_word_count)
+ Result += weak_word_count;
+ }
+ }
+ return Result;
+}
+
+llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+
+ RunSkipBlockVars.clear();
+ bool hasUnion = false;
+
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
+
+ const BlockDecl *blockDecl = blockInfo.getBlockDecl();
+
+ // Calculate the basic layout of the block structure.
+ const llvm::StructLayout *layout =
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
+
+ // Ignore the optional 'this' capture: C++ objects are not assumed
+ // to be GC'ed.
+
+ // Walk the captured variables.
+ for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
+ ce = blockDecl->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ QualType type = variable->getType();
+
+ const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
+
+ // Ignore constant captures.
+ if (capture.isConstant()) continue;
+
+ CharUnits fieldOffset =
+ CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
+
+ assert(!type->isArrayType() && "array variable should not be caught");
+ if (const RecordType *record = type->getAs<RecordType>()) {
+ BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
+ continue;
+ }
+ CharUnits fieldSize;
+ if (ci->isByRef())
+ fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
+ else
+ fieldSize = CGM.getContext().getTypeSizeInChars(type);
+ UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type),
+ fieldOffset, fieldSize);
+ }
+
+ if (RunSkipBlockVars.empty())
+ return nullPtr;
+
+ // Sort on byte position; captures might not be allocated in order,
+ // and unions can do funny things.
+ llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
+ SmallVector<unsigned char, 16> Layout;
+
+ unsigned size = RunSkipBlockVars.size();
+ for (unsigned i = 0; i < size; i++) {
+ enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
+ CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
+ CharUnits end_byte_pos = start_byte_pos;
+ unsigned j = i+1;
+ while (j < size) {
+ if (opcode == RunSkipBlockVars[j].opcode) {
+ end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
+ i++;
+ }
+ else
+ break;
+ }
+ CharUnits size_in_bytes =
+ end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
+ if (j < size) {
+ CharUnits gap =
+ RunSkipBlockVars[j].block_var_bytepos -
+ RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
+ size_in_bytes += gap;
+ }
+ CharUnits residue_in_bytes = CharUnits::Zero();
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
+ residue_in_bytes = size_in_bytes % WordSizeInBytes;
+ size_in_bytes -= residue_in_bytes;
+ opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
+ }
+
+ unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
+ while (size_in_words >= 16) {
+ // Note that value in imm. is one less that the actual
+ // value. So, 0xf means 16 words follow!
+ unsigned char inst = (opcode << 4) | 0xf;
+ Layout.push_back(inst);
+ size_in_words -= 16;
+ }
+ if (size_in_words > 0) {
+ // Note that value in imm. is one less that the actual
+ // value. So, we subtract 1 away!
+ unsigned char inst = (opcode << 4) | (size_in_words-1);
+ Layout.push_back(inst);
+ }
+ if (residue_in_bytes > CharUnits::Zero()) {
+ unsigned char inst =
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
+ Layout.push_back(inst);
+ }
+ }
+
+ int e = Layout.size()-1;
+ while (e >= 0) {
+ unsigned char inst = Layout[e--];
+ enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
+ Layout.pop_back();
+ else
+ break;
+ }
+
+ uint64_t Result = InlineLayoutInstruction(Layout);
+ if (Result != 0) {
+ // Block variable layout instruction has been inlined.
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n Inline instruction for block variable layout: ");
+ printf("0x0%llx\n", (unsigned long long)Result);
+ }
+ if (WordSizeInBytes == 8) {
+ const llvm::APInt Instruction(64, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction);
+ }
+ else {
+ const llvm::APInt Instruction(32, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction);
+ }
+ }
+
+ unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
+ Layout.push_back(inst);
+ std::string BitMap;
+ for (unsigned i = 0, e = Layout.size(); i != e; i++)
+ BitMap += Layout[i];
+
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n block variable layout: ");
+ for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
+ unsigned char inst = BitMap[i];
+ enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ unsigned delta = 1;
+ switch (opcode) {
+ case BLOCK_LAYOUT_OPERATOR:
+ printf("BL_OPERATOR:");
+ delta = 0;
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_BYTES:
+ printf("BL_NON_OBJECT_BYTES:");
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_WORDS:
+ printf("BL_NON_OBJECT_WORD:");
+ break;
+ case BLOCK_LAYOUT_STRONG:
+ printf("BL_STRONG:");
+ break;
+ case BLOCK_LAYOUT_BYREF:
+ printf("BL_BYREF:");
+ break;
+ case BLOCK_LAYOUT_WEAK:
+ printf("BL_WEAK:");
+ break;
+ case BLOCK_LAYOUT_UNRETAINED:
+ printf("BL_UNRETAINED:");
+ break;
+ }
+ // Actual value of word count is one more that what is in the imm.
+ // field of the instruction
+ printf("%d", (inst & 0xf) + delta);
+ if (i < e-1)
+ printf(", ");
+ else
+ printf("\n");
+ }
+ }
+
+ llvm::GlobalVariable * Entry =
+ CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, BitMap,false),
+ "__TEXT,__objc_classname,cstring_literals", 1, true);
+ return getConstantGEP(VMContext, Entry, 0, 0);
+}
+
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
@@ -2040,7 +2603,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
ArrayRef<llvm::Constant*> OptClassMethods,
ArrayRef<llvm::Constant*> MethodTypesExt) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
@@ -2180,7 +2743,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
unsigned PropertySize =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
@@ -2269,7 +2832,7 @@ CGObjCMac::EmitMethodDescList(Twine Name, const char *Section,
};
*/
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
// FIXME: This is poor design, the OCD should have a pointer to the category
// decl. Additionally, note that Category can be null for the @implementation
@@ -2338,15 +2901,37 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
MethodDefinitions.clear();
}
-// FIXME: Get from somewhere?
-enum ClassFlags {
- eClassFlags_Factory = 0x00001,
- eClassFlags_Meta = 0x00002,
- // <rdr://5142207>
- eClassFlags_HasCXXStructors = 0x02000,
- eClassFlags_Hidden = 0x20000,
- eClassFlags_ABI2_Hidden = 0x00010,
- eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634>
+enum FragileClassFlags {
+ FragileABI_Class_Factory = 0x00001,
+ FragileABI_Class_Meta = 0x00002,
+ FragileABI_Class_HasCXXStructors = 0x02000,
+ FragileABI_Class_Hidden = 0x20000
+};
+
+enum NonFragileClassFlags {
+ /// Is a meta-class.
+ NonFragileABI_Class_Meta = 0x00001,
+
+ /// Is a root class.
+ NonFragileABI_Class_Root = 0x00002,
+
+ /// Has a C++ constructor and destructor.
+ NonFragileABI_Class_HasCXXStructors = 0x00004,
+
+ /// Has hidden visibility.
+ NonFragileABI_Class_Hidden = 0x00010,
+
+ /// Has the exception attribute.
+ NonFragileABI_Class_Exception = 0x00020,
+
+ /// (Obsolete) ARC-specific: this class has a .release_ivars method
+ NonFragileABI_Class_HasIvarReleaser = 0x00040,
+
+ /// Class implementation was compiled under ARC.
+ NonFragileABI_Class_CompiledByARC = 0x00080,
+
+ /// Class has non-trivial destructors, but zero-initialization is okay.
+ NonFragileABI_Class_HasCXXDestructorOnly = 0x00100
};
/*
@@ -2379,15 +2964,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
- unsigned Flags = eClassFlags_Factory;
- if (ID->hasCXXStructors())
- Flags |= eClassFlags_HasCXXStructors;
+ unsigned Flags = FragileABI_Class_Factory;
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors())
+ Flags |= FragileABI_Class_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
// FIXME: Set CXX-structors flag.
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
@@ -2470,11 +3055,11 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
ArrayRef<llvm::Constant*> Methods) {
- unsigned Flags = eClassFlags_Meta;
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
+ unsigned Flags = FragileABI_Class_Meta;
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::Constant *Values[12];
// The isa for the metaclass is the root of the hierarchy.
@@ -2588,7 +3173,7 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
@@ -3481,7 +4066,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3502,7 +4087,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3528,7 +4113,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3548,7 +4133,7 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3679,7 +4264,7 @@ void CGObjCCommonMac::EmitImageInfo() {
static const int ModuleVersion = 7;
void CGObjCMac::EmitModuleInfo() {
- uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
+ uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
@@ -3824,7 +4409,7 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
Fields.push_back(*i);
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
- CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
ForStrongLayout, HasUnion);
@@ -3951,7 +4536,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (IsUnion) {
// FIXME: Why the asymmetry? We divide by word size in bits on other
// side.
- uint64_t UnionIvarSize = FieldSize;
+ uint64_t UnionIvarSize = FieldSize / ByteSizeInBits;
if (UnionIvarSize > MaxSkippedUnionIvarSize) {
MaxSkippedUnionIvarSize = UnionIvarSize;
MaxSkippedField = Field;
@@ -4005,7 +4590,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
// Build the string of skip/scan nibbles
SmallVector<SKIP_SCAN, 32> SkipScanIvars;
unsigned int WordSize =
- CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
+ CGM.getTypes().getDataLayout().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
WordsToSkip = 0;
WordsToScan = IvarsInfo[0].ivar_size;
@@ -4187,7 +4772,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().data());
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -4835,7 +5420,7 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
@@ -4941,19 +5526,6 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
return VTableDispatchMethods.count(Sel);
}
-// Metadata flags
-enum MetaDataDlags {
- CLS = 0x0,
- CLS_META = 0x1,
- CLS_ROOT = 0x2,
- OBJC2_CLS_HIDDEN = 0x10,
- CLS_EXCEPTION = 0x20,
-
- /// (Obsolete) ARC-specific: this class has a .release_ivars method
- CLS_HAS_IVAR_RELEASER = 0x40,
- /// class was compiled with -fobjc-arr
- CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
-};
/// BuildClassRoTInitializer - generate meta-data for:
/// struct _class_ro_t {
/// uint32_t const flags;
@@ -4978,19 +5550,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
llvm::Constant *Values[10]; // 11 for 64bit targets!
if (CGM.getLangOpts().ObjCAutoRefCount)
- flags |= CLS_COMPILED_BY_ARC;
+ flags |= NonFragileABI_Class_CompiledByARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
// FIXME. For 64bit targets add 0 here.
- Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
+ Values[ 3] = (flags & NonFragileABI_Class_Meta)
+ ? GetIvarLayoutName(0, ObjCTypes)
: BuildIvarLayout(ID, true);
Values[ 4] = GetClassName(ID->getIdentifier());
// const struct _method_list_t * const baseMethods;
std::vector<llvm::Constant*> Methods;
std::string MethodListName("\01l_OBJC_$_");
- if (flags & CLS_META) {
+ if (flags & NonFragileABI_Class_Meta) {
MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
@@ -5030,28 +5603,27 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
- if (flags & CLS_META)
+ if (flags & NonFragileABI_Class_Meta) {
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- else
- Values[ 7] = EmitIvarList(ID);
- Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
- : BuildIvarLayout(ID, false);
- if (flags & CLS_META)
+ Values[ 8] = GetIvarLayoutName(0, ObjCTypes);
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
- else
+ } else {
+ Values[ 7] = EmitIvarList(ID);
+ Values[ 8] = BuildIvarLayout(ID, false);
Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
+ }
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
llvm::GlobalVariable *CLASS_RO_GV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
llvm::GlobalValue::InternalLinkage,
Init,
- (flags & CLS_META) ?
+ (flags & NonFragileABI_Class_Meta) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
@@ -5088,7 +5660,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
@@ -5138,23 +5710,31 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
// FIXME: Is this correct (that meta class size is never computed)?
uint32_t InstanceStart =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
uint32_t InstanceSize = InstanceStart;
- uint32_t flags = CLS_META;
+ uint32_t flags = NonFragileABI_Class_Meta;
std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
std::string ObjCClassName(getClassSymbolPrefix());
llvm::GlobalVariable *SuperClassGV, *IsAGV;
+ // Build the flags for the metaclass.
bool classIsHidden =
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ // FIXME: why is this flag set on the metaclass?
+ // ObjC metaclasses have no fields and don't really get constructed.
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
+
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
} else {
@@ -5183,17 +5763,28 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
- flags = CLS;
+ flags = 0;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+
+ // Set a flag to enable a runtime optimization when a class has
+ // fields that require destruction but which don't require
+ // anything except zero-initialization during construction. This
+ // is most notably true of __strong and __weak types, but you can
+ // also imagine there being C++ types with non-trivial default
+ // constructors that merely set all fields to null.
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
- flags |= CLS_EXCEPTION;
+ flags |= NonFragileABI_Class_Exception;
if (!ID->getClassInterface()->getSuperClass()) {
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = 0;
} else {
// Has a root. Current class is not a root.
@@ -5220,7 +5811,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedNonLazyClasses.push_back(ClassMD);
// Force the definition of the EHType if necessary.
- if (flags & CLS_EXCEPTION)
+ if (flags & NonFragileABI_Class_Exception)
GetInterfaceEHType(ID->getClassInterface(), true);
// Make sure method definition entries are all clear for next implementation.
MethodDefinitions.clear();
@@ -5344,7 +5935,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Init,
ExtCatName);
GCATV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
@@ -5391,7 +5982,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::Constant *Values[3];
// sizeof(struct _objc_method)
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
// method_count
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
@@ -5403,7 +5994,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage, Init, Name);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
@@ -5437,7 +6028,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.LongTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -5490,7 +6081,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Ivar[2] = GetMethodVarType(IVD);
llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(IVD->getType());
- unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
IVD->getType().getTypePtr()) >> 3;
Align = llvm::Log2_32(Align);
@@ -5508,7 +6099,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
llvm::Constant *Values[3];
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
@@ -5522,7 +6113,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Init,
Prefix + OID->getName());
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
@@ -5644,7 +6235,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(),
0, PD, ObjCTypes);
uint32_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
@@ -5663,7 +6254,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
Protocols[PD->getIdentifier()] = Entry;
@@ -5678,7 +6269,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
@@ -5732,7 +6323,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
Init, Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
@@ -5970,7 +6561,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6004,7 +6595,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6030,7 +6621,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
@@ -6079,16 +6670,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
- if (IsClassMessage) {
- if (isCategoryImpl) {
- // Message sent to "super' in a class method defined in
- // a category implementation.
- Target = EmitClassRef(CGF.Builder, Class);
- Target = CGF.Builder.CreateStructGEP(Target, 0);
- Target = CGF.Builder.CreateLoad(Target);
- } else
+ if (IsClassMessage)
Target = EmitMetaClassRef(CGF.Builder, Class);
- } else
+ else
Target = EmitSuperClassRef(CGF.Builder, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
@@ -6143,7 +6727,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *ivarOffset) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6164,7 +6748,7 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6211,7 +6795,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6232,7 +6816,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6364,7 +6948,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
+ Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
if (ForDefinition) {
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 9aa68376bcd0..6932dd709d16 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -78,6 +78,13 @@ uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
CGM.getContext().getCharWidth();
}
+unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
+ CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar);
+}
+
LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID,
llvm::Value *BaseValue,
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 219a3e4df0d4..3e77875e6baf 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -261,6 +261,8 @@ public:
llvm::Value *Size) = 0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
struct MessageSendInfo {
@@ -275,6 +277,12 @@ public:
MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs);
+
+ // FIXME: This probably shouldn't be here, but the code to compute
+ // it is here.
+ unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *Ivar);
};
/// Creates an instance of an Objective-C runtime class.
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index d1b370a1f728..7c83d39f8bce 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -105,7 +105,6 @@ public:
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
///
/// \param Force - true to force the creation of this RTTI value
- /// \param ForEH - true if this is for exception handling
llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -779,28 +778,24 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (Base->isVirtual()) {
- if (Bases.VirtualBases.count(BaseDecl)) {
+ // Mark the virtual base as seen.
+ if (!Bases.VirtualBases.insert(BaseDecl)) {
// If this virtual base has been seen before, then the class is diamond
// shaped.
Flags |= RTTIBuilder::VMI_DiamondShaped;
} else {
if (Bases.NonVirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
-
- // Mark the virtual base as seen.
- Bases.VirtualBases.insert(BaseDecl);
}
} else {
- if (Bases.NonVirtualBases.count(BaseDecl)) {
+ // Mark the non-virtual base as seen.
+ if (!Bases.NonVirtualBases.insert(BaseDecl)) {
// If this non-virtual base has been seen before, then the class has non-
// diamond shaped repeated inheritance.
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
} else {
if (Bases.VirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
-
- // Mark the non-virtual base as seen.
- Bases.NonVirtualBases.insert(BaseDecl);
}
}
@@ -891,7 +886,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
Offset = Layout.getBaseClassOffset(BaseDecl);
};
- OffsetFlags = Offset.getQuantity() << 8;
+ OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
// The low-order byte of __offset_flags contains flags, as given by the
// masks from the enumeration __offset_flags_masks.
@@ -982,7 +977,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
// Return a bogus pointer if RTTI is disabled, unless it's for EH.
// FIXME: should we even be calling this method if RTTI is disabled
// and it's not for EH?
- if (!ForEH && !getContext().getLangOpts().RTTI)
+ if (!ForEH && !getLangOpts().RTTI)
return llvm::Constant::getNullValue(Int8PtrTy);
if (ForEH && Ty->isObjCObjectPointerType() &&
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 94c822f49f17..3db5e0483bab 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -166,8 +166,8 @@ public:
class CGRecordLayout {
friend class CodeGenTypes;
- CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT
- void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
+ CGRecordLayout(const CGRecordLayout &) LLVM_DELETED_FUNCTION;
+ void operator=(const CGRecordLayout &) LLVM_DELETED_FUNCTION;
private:
/// The LLVM type corresponding to this record layout; used when
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d642ef8533c5..26ef3efe73e6 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -25,7 +25,7 @@
#include "llvm/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -206,7 +206,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Alignment = Types.getContext().getASTRecordLayout(D).getAlignment();
Packed = D->hasAttr<PackedAttr>();
- IsMsStruct = D->hasAttr<MsStructAttr>();
+ IsMsStruct = D->isMsStruct(Types.getContext());
if (D->isUnion()) {
LayoutUnion(D);
@@ -239,7 +239,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
CharUnits TypeSizeInBytes =
- CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
+ CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
@@ -259,7 +259,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
// in big-endian machines the first fields are in higher bit positions,
// so revert the offset. The byte offsets are reversed(back) later.
- if (Types.getTargetData().isBigEndian()) {
+ if (Types.getDataLayout().isBigEndian()) {
FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize);
}
@@ -334,7 +334,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
// on big-endian machines we reverted the bit offset because first fields are
// in higher bits. But this also reverts the bytes, so fix this here by reverting
// the byte offset on big-endian machines.
- if (Types.getTargetData().isBigEndian()) {
+ if (Types.getDataLayout().isBigEndian()) {
AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(
ContainingTypeSizeInBits - AccessStart - AccessWidth);
} else {
@@ -553,9 +553,9 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
hasOnlyZeroSizedBitFields = false;
CharUnits fieldAlign = CharUnits::fromQuantity(
- Types.getTargetData().getABITypeAlignment(fieldType));
+ Types.getDataLayout().getABITypeAlignment(fieldType));
CharUnits fieldSize = CharUnits::fromQuantity(
- Types.getTargetData().getTypeAllocSize(fieldType));
+ Types.getDataLayout().getTypeAllocSize(fieldType));
if (fieldAlign < unionAlign)
continue;
@@ -884,7 +884,7 @@ void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) {
void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
llvm::Type *fieldType) {
CharUnits fieldSize =
- CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(fieldType));
+ CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(fieldType));
FieldTypes.push_back(fieldType);
@@ -957,7 +957,7 @@ CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const {
if (Packed)
return CharUnits::One();
- return CharUnits::fromQuantity(Types.getTargetData().getABITypeAlignment(Ty));
+ return CharUnits::fromQuantity(Types.getDataLayout().getABITypeAlignment(Ty));
}
CharUnits CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const {
@@ -1036,7 +1036,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D);
uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize());
- assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) &&
+ assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) &&
"Type size mismatch!");
if (BaseTy) {
@@ -1049,19 +1049,19 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
getContext().toBits(AlignedNonVirtualTypeSize);
assert(AlignedNonVirtualTypeSizeInBits ==
- getTargetData().getTypeAllocSizeInBits(BaseTy) &&
+ getDataLayout().getTypeAllocSizeInBits(BaseTy) &&
"Type size mismatch!");
}
// Verify that the LLVM and AST field offsets agree.
llvm::StructType *ST =
dyn_cast<llvm::StructType>(RL->getLLVMType());
- const llvm::StructLayout *SL = getTargetData().getStructLayout(ST);
+ const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST);
const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
RecordDecl::field_iterator it = D->field_begin();
const FieldDecl *LastFD = 0;
- bool IsMsStruct = D->hasAttr<MsStructAttr>();
+ bool IsMsStruct = D->isMsStruct(getContext());
for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
const FieldDecl *FD = *it;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index d78908dee876..3548dbac6fc1 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -21,7 +21,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/InlineAsm.h"
#include "llvm/Intrinsics.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -132,8 +132,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
- case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
- case Stmt::MSAsmStmtClass: EmitMSAsmStmt(cast<MSAsmStmt>(*S)); break;
+ case Stmt::GCCAsmStmtClass: // Intentional fall-through.
+ case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
@@ -237,6 +237,10 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
if (!BI || !BI->isUnconditional())
return;
+ // Can only simplify empty blocks.
+ if (BI != BB->begin())
+ return;
+
BB->replaceAllUsesWith(BI->getSuccessor(0));
BI->eraseFromParent();
BB->eraseFromParent();
@@ -743,6 +747,17 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// Emit the result value, even if unused, to evalute the side effects.
const Expr *RV = S.getRetValue();
+ // Treat block literals in a return expression as if they appeared
+ // in their own scope. This permits a small, easily-implemented
+ // exception to our over-conservative rules about not jumping to
+ // statements following block literals with non-trivial cleanups.
+ RunCleanupsScope cleanupScope(*this);
+ if (const ExprWithCleanups *cleanups =
+ dyn_cast_or_null<ExprWithCleanups>(RV)) {
+ enterFullExpression(cleanups);
+ RV = cleanups->getSubExpr();
+ }
+
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
@@ -779,6 +794,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
AggValueSlot::IsNotAliased));
}
+ cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
}
@@ -899,7 +915,8 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
// If the body of the case is just a 'break', and if there was no fallthrough,
// try to not emit an empty block.
- if ((CGM.getCodeGenOpts().OptimizationLevel > 0) && isa<BreakStmt>(S.getSubStmt())) {
+ if ((CGM.getCodeGenOpts().OptimizationLevel > 0) &&
+ isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
// Only do this optimization if there are no cleanups that need emitting.
@@ -1263,6 +1280,10 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
case '=': // Will see this and the following in mult-alt constraints.
case '+':
break;
+ case '#': // Ignore the rest of the constraint alternative.
+ while (Constraint[1] && Constraint[1] != ',')
+ Constraint++;
+ break;
case ',':
Result += "|";
break;
@@ -1323,8 +1344,7 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
}
llvm::Value*
-CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
std::string &ConstraintStr) {
llvm::Value *Arg;
@@ -1333,7 +1353,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
- uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
+ uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
Ty = llvm::PointerType::getUnqual(Ty);
@@ -1353,7 +1373,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S,
return Arg;
}
-llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
+llvm::Value* CodeGenFunction::EmitAsmInput(
const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr,
std::string &ConstraintStr) {
@@ -1363,7 +1383,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
- return EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), ConstraintStr);
+ return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr);
}
/// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline
@@ -1396,23 +1416,8 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
}
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
- // 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<AsmStmt::AsmStringPiece, 4> Pieces;
- unsigned DiagOffs;
- S.AnalyzeAsmString(Pieces, getContext(), DiagOffs);
-
- // Assemble the pieces into the final asm string.
- std::string AsmString;
- for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
- if (Pieces[i].isString())
- AsmString += Pieces[i].getString();
- else if (Pieces[i].getModifier() == '\0')
- AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo());
- else
- AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' +
- Pieces[i].getModifier() + '}';
- }
+ // Assemble the final asm string.
+ std::string AsmString = S.generateAsmString(getContext());
// Get all the output and input constraints together.
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
@@ -1511,7 +1516,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
- llvm::Value *Arg = EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(),
+ llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(),
InOutConstraints);
if (llvm::Type* AdjTy =
@@ -1549,7 +1554,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
*InputExpr->IgnoreParenNoopCasts(getContext()),
Target, CGM, S);
- llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, Constraints);
+ llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints);
// If this input argument is tied to a larger output result, extend the
// input to be the same size as the output. The LLVM backend wants to see
@@ -1596,7 +1601,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- StringRef Clobber = S.getClobber(i)->getString();
+ StringRef Clobber = S.getClobber(i);
if (Clobber != "memory" && Clobber != "cc")
Clobber = Target.getNormalizedGCCRegisterName(Clobber);
@@ -1628,15 +1633,22 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
+ bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
+ llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
+ llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT;
llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, AsmString, Constraints,
- S.isVolatile() || S.getNumOutputs() == 0);
+ llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
+ /* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+ Result->addAttribute(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(getLLVMContext(),
+ llvm::Attributes::NoUnwind));
// Slap the source location of the inline asm into a !srcloc metadata on the
- // call.
- Result->setMetadata("srcloc", getAsmSrcLocInfo(S.getAsmString(), *this));
+ // call. FIXME: Handle metadata for MS-style inline asms.
+ if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
+ Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
+ *this));
// Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
@@ -1662,12 +1674,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
if (TruncTy->isFloatingPointTy())
Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
- uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
Tmp = Builder.CreateTrunc(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
} else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
- uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType());
+ uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
Tmp = Builder.CreatePtrToInt(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
Tmp = Builder.CreateTrunc(Tmp, TruncTy);
@@ -1681,47 +1693,3 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
}
}
-
-void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) {
- // MS-style inline assembly is not fully supported, so sema emits a warning.
- if (!CGM.getCodeGenOpts().EmitMicrosoftInlineAsm)
- return;
-
- assert (S.isSimple() && "CodeGen can only handle simple MSAsmStmts.");
-
- std::vector<llvm::Value*> Args;
- std::vector<llvm::Type *> ArgTypes;
- std::string Constraints;
-
- // Clobbers
- for (unsigned i = 0, e = S.getNumClobbers(); i != e; ++i) {
- StringRef Clobber = S.getClobber(i);
-
- if (Clobber != "memory" && Clobber != "cc")
- Clobber = Target.getNormalizedGCCRegisterName(Clobber);
-
- if (i != 0)
- Constraints += ',';
-
- Constraints += "~{";
- Constraints += Clobber;
- Constraints += '}';
- }
-
- // Add machine specific clobbers
- std::string MachineClobbers = Target.getClobbers();
- if (!MachineClobbers.empty()) {
- if (!Constraints.empty())
- Constraints += ',';
- Constraints += MachineClobbers;
- }
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, ArgTypes, false);
-
- llvm::InlineAsm *IA =
- llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true);
- llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(~0, llvm::Attribute::NoUnwind);
- Result->addAttribute(~0, llvm::Attribute::IANSDialect);
-}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index cdaa26a2bad6..5b37fe4b9634 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -79,15 +79,16 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
llvm::Value *Ptr,
int64_t NonVirtualAdjustment,
- int64_t VirtualAdjustment) {
+ 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) {
- // Do the non-virtual adjustment.
+ if (NonVirtualAdjustment && !IsReturnAdjustment) {
+ // Perform the non-virtual adjustment for a base-to-derived cast.
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
}
@@ -95,7 +96,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
- // Do the virtual adjustment.
+ // Perform the virtual adjustment.
llvm::Value *VTablePtrPtr =
CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
@@ -113,6 +114,11 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
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());
}
@@ -150,8 +156,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- if (!CGM.getCodeGenOpts().HiddenWeakTemplateVTables)
- return;
+ return;
break;
}
@@ -199,7 +204,8 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
+ Thunk.Return.VBaseOffsetOffset,
+ /*IsReturnAdjustment*/true);
if (NullCheckValue) {
CGF.Builder.CreateBr(AdjustEnd);
@@ -248,7 +254,9 @@ void CodeGenFunction::GenerateVarArgsThunk(
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
// Clone to thunk.
- llvm::Function *NewFn = llvm::CloneFunction(BaseFn);
+ llvm::ValueToValueMapTy VMap;
+ llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap,
+ /*ModuleLevelChanges=*/false);
CGM.getModule().getFunctionList().push_back(NewFn);
Fn->replaceAllUsesWith(NewFn);
NewFn->takeName(Fn);
@@ -281,7 +289,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
llvm::Value *AdjustedThisPtr =
PerformTypeAdjustment(*this, ThisPtr,
Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset);
+ Thunk.This.VCallOffsetOffset,
+ /*IsReturnAdjustment*/false);
ThisStore->setOperand(0, AdjustedThisPtr);
if (!Thunk.Return.isEmpty()) {
@@ -324,7 +333,10 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
FunctionArgs.push_back(Param);
}
-
+
+ // Initialize debug info if needed.
+ maybeInitializeDebugInfo();
+
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
SourceLocation());
@@ -335,7 +347,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
llvm::Value *AdjustedThisPtr =
PerformTypeAdjustment(*this, LoadCXXThis(),
Thunk.This.NonVirtual,
- Thunk.This.VCallOffsetOffset);
+ Thunk.This.VCallOffsetOffset,
+ /*IsReturnAdjustment*/false);
CallArgList CallArgs;
@@ -455,6 +468,8 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
return;
}
+ CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn);
+
if (ThunkFn->isVarArg()) {
// Varargs thunks are special; we can't just generate a call because
// we can't copy the varargs. Our implementation is rather
@@ -524,7 +539,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
unsigned NextVTableThunkIndex = 0;
- llvm::Constant* PureVirtualFn = 0;
+ llvm::Constant *PureVirtualFn = 0, *DeletedVirtualFn = 0;
for (unsigned I = 0; I != NumComponents; ++I) {
VTableComponent Component = Components[I];
@@ -573,14 +588,25 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
// We have a pure virtual member function.
if (!PureVirtualFn) {
- llvm::FunctionType *Ty =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
- PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
- PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
+ llvm::FunctionType *Ty =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
+ PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
+ PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
CGM.Int8PtrTy);
}
Init = PureVirtualFn;
+ } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) {
+ if (!DeletedVirtualFn) {
+ llvm::FunctionType *Ty =
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+ StringRef DeletedCallName =
+ CGM.getCXXABI().GetDeletedVirtualCallName();
+ DeletedVirtualFn = CGM.CreateRuntimeFunction(Ty, DeletedCallName);
+ DeletedVirtualFn = llvm::ConstantExpr::getBitCast(DeletedVirtualFn,
+ CGM.Int8PtrTy);
+ }
+ Init = DeletedVirtualFn;
} else {
// Check if we should use a thunk.
if (NextVTableThunkIndex < NumVTableThunks &&
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index dd32167b8477..9d6d183d97d9 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -65,9 +65,11 @@ namespace clang {
TargetOpts(targetopts),
LangOpts(langopts),
AsmOutStream(OS),
+ Context(),
LLVMIRGeneration("LLVM IR Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
- LinkModule(LinkModule) {
+ LinkModule(LinkModule)
+ {
llvm::TimePassesIsEnabled = TimePasses;
}
@@ -379,7 +381,7 @@ void CodeGenAction::ExecuteAction() {
// FIXME: This is stupid, IRReader shouldn't take ownership.
llvm::MemoryBuffer *MainFileCopy =
llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(),
- getCurrentFile().c_str());
+ getCurrentFile());
llvm::SMDiagnostic Err;
TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext));
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 1d02861ed786..18f1623d242e 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -24,7 +24,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
#include "llvm/MDBuilder.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -32,6 +32,10 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm),
Target(CGM.getContext().getTargetInfo()),
Builder(cgm.getModule().getContext()),
+ SanitizePerformTypeCheck(CGM.getLangOpts().SanitizeNull |
+ CGM.getLangOpts().SanitizeAlignment |
+ CGM.getLangOpts().SanitizeObjectSize |
+ CGM.getLangOpts().SanitizeVptr),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
@@ -40,8 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
TerminateHandler(0), TrapBB(0) {
-
- CatchUndefined = getContext().getLangOpts().CatchUndefined;
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
}
@@ -348,11 +350,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
RE = FD->redecls_end(); RI != RE; ++RI)
if (RI->isInlineSpecified()) {
- Fn->addFnAttr(llvm::Attribute::InlineHint);
+ Fn->addFnAttr(llvm::Attributes::InlineHint);
break;
}
- if (getContext().getLangOpts().OpenCL) {
+ if (getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
EmitOpenCLKernelMetadata(FD, Fn);
@@ -485,7 +487,7 @@ static void TryMarkNoThrow(llvm::Function *F) {
} else if (isa<llvm::ResumeInst>(&*BI)) {
return;
}
- F->setDoesNotThrow(true);
+ F->setDoesNotThrow();
}
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
@@ -493,8 +495,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
- if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getModuleDebugInfo();
+ if (!FD->hasAttr<NoDebugAttr>())
+ maybeInitializeDebugInfo();
FunctionArgList Args;
QualType ResTy = FD->getResultType();
@@ -517,7 +519,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
EmitConstructorBody(Args);
- else if (getContext().getLangOpts().CUDA &&
+ else if (getLangOpts().CUDA &&
!CGM.getCodeGenOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
@@ -535,6 +537,24 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
else
EmitFunctionBody(Args);
+ // C++11 [stmt.return]p2:
+ // Flowing off the end of a function [...] results in undefined behavior in
+ // a value-returning function.
+ // C11 6.9.1p12:
+ // If the '}' that terminates a function is reached, and the value of the
+ // function call is used by the caller, the behavior is undefined.
+ if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
+ !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
+ if (getLangOpts().SanitizeReturn)
+ EmitCheck(Builder.getFalse(), "missing_return",
+ EmitCheckSourceLocation(FD->getLocation()),
+ llvm::ArrayRef<llvm::Value*>());
+ else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ }
+
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
@@ -806,7 +826,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
void
CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Ignore empty classes in C++.
- if (getContext().getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
return;
@@ -983,8 +1003,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
arrayType = getContext().getAsArrayType(eltType);
}
- unsigned AddressSpace =
- cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+ unsigned AddressSpace = addr->getType()->getPointerAddressSpace();
llvm::Type *BaseType = ConvertType(eltType)->getPointerTo(AddressSpace);
addr = Builder.CreateBitCast(addr, BaseType, "array.begin");
} else {
@@ -1027,6 +1046,7 @@ CodeGenFunction::getVLASize(const VariableArrayType *type) {
numElements = vlaSize;
} else {
// It's undefined behavior if this wraps around, so mark it that way.
+ // FIXME: Teach -fcatch-undefined-behavior to trap this.
numElements = Builder.CreateNUWMul(numElements, vlaSize);
}
} while ((type = getContext().getAsVariableArrayType(elementType)));
@@ -1104,10 +1124,26 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// e.g. with a typedef and a pointer to it.
llvm::Value *&entry = VLASizeMap[size];
if (!entry) {
+ llvm::Value *Size = EmitScalarExpr(size);
+
+ // C11 6.7.6.2p5:
+ // If the size is an expression that is not an integer constant
+ // expression [...] each time it is evaluated it shall have a value
+ // greater than zero.
+ if (getLangOpts().SanitizeVLABound &&
+ size->getType()->isSignedIntegerType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
+ llvm::Constant *StaticArgs[] = {
+ EmitCheckSourceLocation(size->getLocStart()),
+ EmitCheckTypeDescriptor(size->getType())
+ };
+ EmitCheck(Builder.CreateICmpSGT(Size, Zero),
+ "vla_bound_not_positive", StaticArgs, Size);
+ }
+
// Always zexting here would be wrong if it weren't
// undefined behavior to have a negative bound.
- entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy,
- /*signed*/ false);
+ entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false);
}
}
type = vat->getElementType();
@@ -1156,7 +1192,7 @@ void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
llvm::Constant *Init) {
assert (Init && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
- if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo)
+ if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
Dbg->EmitGlobalVariable(E->getDecl(), Init);
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index ed3e43beb0f8..f2ab226ab530 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -222,8 +222,7 @@ public:
/// immediately-enclosing context of the cleanup scope. For
/// EH cleanups, this is run in a terminate context.
///
- // \param IsForEHCleanup true if this is for an EH cleanup, false
- /// if for a normal cleanup.
+ // \param flags cleanup kind.
virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
};
@@ -533,8 +532,8 @@ public:
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache {
- CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT
- void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT
+ CodeGenFunction(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
+ void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION;
friend class CGCXXABI;
public:
@@ -595,8 +594,9 @@ public:
/// potentially higher performance penalties.
unsigned char BoundsChecking;
- /// CatchUndefined - Emit run-time checks to catch undefined behaviors.
- bool CatchUndefined;
+ /// \brief Whether any type-checking sanitizers are enabled. If \c false,
+ /// calls to EmitTypeCheck can be skipped.
+ bool SanitizePerformTypeCheck;
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
@@ -795,8 +795,8 @@ public:
bool OldDidCallStackSave;
bool PerformCleanup;
- RunCleanupsScope(const RunCleanupsScope &); // DO NOT IMPLEMENT
- RunCleanupsScope &operator=(const RunCleanupsScope &); // DO NOT IMPLEMENT
+ RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
protected:
CodeGenFunction& CGF;
@@ -839,8 +839,8 @@ public:
SourceRange Range;
bool PopDebugStack;
- LexicalScope(const LexicalScope &); // DO NOT IMPLEMENT THESE
- LexicalScope &operator=(const LexicalScope &);
+ LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION;
+ void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION;
public:
/// \brief Enter a new cleanup scope.
@@ -908,7 +908,7 @@ public:
/// themselves).
void popCatchScope();
- llvm::BasicBlock *getEHResumeBlock();
+ llvm::BasicBlock *getEHResumeBlock(bool isCleanup);
llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope);
/// An object to manage conditionally-evaluated expressions.
@@ -1213,6 +1213,14 @@ 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;
@@ -1504,7 +1512,7 @@ public:
static bool hasAggregateLLVMType(QualType T);
/// createBasicBlock - Create an LLVM basic block.
- llvm::BasicBlock *createBasicBlock(StringRef name = "",
+ llvm::BasicBlock *createBasicBlock(const Twine &name = "",
llvm::Function *parent = 0,
llvm::BasicBlock *before = 0) {
#ifdef NDEBUG
@@ -1631,7 +1639,7 @@ public:
/// aggregate expression, the aggloc/agglocvolatile arguments indicate where
/// the result should be returned.
///
- /// \param IgnoreResult - True if the resulting value isn't used.
+ /// \param ignoreResult True if the resulting value isn't used.
RValue EmitAnyExpr(const Expr *E,
AggValueSlot aggSlot = AggValueSlot::ignored(),
bool ignoreResult = false);
@@ -1654,13 +1662,26 @@ public:
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit);
+ /// EmitAggregateCopy - Emit an aggrate assignment.
+ ///
+ /// The difference to EmitAggregateCopy is that tail padding is not copied.
+ /// This is required for correctness when assigning non-POD structures in C++.
+ void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr,
+ QualType EltTy, bool isVolatile=false,
+ CharUnits Alignment = CharUnits::Zero()) {
+ EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true);
+ }
+
/// EmitAggregateCopy - Emit an aggrate copy.
///
/// \param isVolatile - True iff either the source or the destination is
/// volatile.
+ /// \param isAssignment - If false, allow padding to be copied. This often
+ /// yields more efficient.
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
QualType EltTy, bool isVolatile=false,
- CharUnits Alignment = CharUnits::Zero());
+ CharUnits Alignment = CharUnits::Zero(),
+ bool isAssignment = false);
/// StartBlock - Start new block named N. If insert block is a dummy block
/// then reuse it.
@@ -1829,12 +1850,37 @@ public:
llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
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);
- void EmitCheck(llvm::Value *, unsigned Size);
+ /// \brief Situations in which we might emit a check for the suitability of a
+ /// pointer or glvalue.
+ enum TypeCheckKind {
+ /// Checking the operand of a load. Must be suitably sized and aligned.
+ TCK_Load,
+ /// Checking the destination of a store. Must be suitably sized and aligned.
+ TCK_Store,
+ /// Checking the bound value in a reference binding. Must be suitably sized
+ /// and aligned, but is not required to refer to an object (until the
+ /// reference is used), per core issue 453.
+ TCK_ReferenceBinding,
+ /// Checking the object expression in a non-static data member access. Must
+ /// be an object within its lifetime.
+ TCK_MemberAccess,
+ /// Checking the 'this' pointer for a call to a non-static member function.
+ /// Must be an object within its lifetime.
+ TCK_MemberCall,
+ /// Checking the 'this' pointer for a constructor call.
+ TCK_ConstructorCall
+ };
+
+ /// \brief Emit a check that \p V is the address of storage of the
+ /// appropriate size and alignment for an object of type \p Type.
+ void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
+ QualType Type, CharUnits Alignment = CharUnits::Zero());
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
@@ -1981,7 +2027,6 @@ public:
void EmitCaseStmt(const CaseStmt &S);
void EmitCaseStmtRange(const CaseStmt &S);
void EmitAsmStmt(const AsmStmt &S);
- void EmitMSAsmStmt(const MSAsmStmt &S);
void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
@@ -2033,11 +2078,10 @@ public:
///
LValue EmitLValue(const Expr *E);
- /// EmitCheckedLValue - Same as EmitLValue but additionally we generate
- /// checking code to guard against undefined behavior. This is only
- /// suitable when we know that the address will be used to access the
- /// object.
- LValue EmitCheckedLValue(const Expr *E);
+ /// \brief Same as EmitLValue but additionally we generate checking code to
+ /// guard against undefined behavior. This is only suitable when we know
+ /// that the address will be used to access the object.
+ LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
@@ -2178,6 +2222,7 @@ public:
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitLambdaLValue(const LambdaExpr *E);
LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
+ LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
@@ -2230,6 +2275,7 @@ public:
const CXXRecordDecl *RD);
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
+ SourceLocation CallLoc,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
@@ -2310,6 +2356,7 @@ public:
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
+ void EmitARCDestroyStrong(llvm::Value *addr, bool precise);
void EmitARCRelease(llvm::Value *value, bool precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
@@ -2516,9 +2563,29 @@ public:
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock);
- /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll
- /// generate a branch around the created basic block as necessary.
- llvm::BasicBlock *getTrapBB();
+ /// \brief Emit a description of a type in a format suitable for passing to
+ /// a runtime sanitizer handler.
+ llvm::Constant *EmitCheckTypeDescriptor(QualType T);
+
+ /// \brief Convert a value into a format suitable for passing to a runtime
+ /// sanitizer handler.
+ llvm::Value *EmitCheckValue(llvm::Value *V);
+
+ /// \brief Emit a description of a source location in a format suitable for
+ /// passing to a runtime sanitizer handler.
+ llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+
+ /// \brief Create a basic block that will call a handler function in a
+ /// sanitizer runtime with the provided arguments, and create a conditional
+ /// branch to it.
+ void EmitCheck(llvm::Value *Checked, StringRef CheckName,
+ llvm::ArrayRef<llvm::Constant *> StaticArgs,
+ llvm::ArrayRef<llvm::Value *> DynamicArgs,
+ bool Recoverable = false);
+
+ /// \brief Create a basic block that will call the trap intrinsic, and emit a
+ /// conditional branch to it, for the -ftrapv checks.
+ void EmitTrapvCheck(llvm::Value *Checked);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
@@ -2553,12 +2620,10 @@ private:
SmallVector<llvm::Value*, 16> &Args,
llvm::FunctionType *IRFuncTy);
- llvm::Value* EmitAsmInput(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+ llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr, std::string &ConstraintStr);
- llvm::Value* EmitAsmInputLValue(const AsmStmt &S,
- const TargetInfo::ConstraintInfo &Info,
+ llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
LValue InputValue, QualType InputType,
std::string &ConstraintStr);
@@ -2624,15 +2689,9 @@ private:
void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
- /// GetPointeeAlignment - Given an expression with a pointer type, find the
- /// alignment of the type referenced by the pointer. Skip over implicit
- /// casts.
- unsigned GetPointeeAlignment(const Expr *Addr);
-
- /// GetPointeeAlignmentValue - Given an expression with a pointer type, find
- /// the alignment of the type referenced by the pointer. Skip over implicit
- /// casts. Return the alignment as an llvm::Value.
- llvm::Value *GetPointeeAlignmentValue(const Expr *Addr);
+ /// GetPointeeAlignment - Given an expression with a pointer type, emit the
+ /// value and compute our best estimate of the alignment of the pointee.
+ std::pair<llvm::Value*, unsigned> EmitPointerWithAlignment(const Expr *Addr);
};
/// Helper class with most of the code for saving a value for a
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 3ae3c521300b..17972e29b65a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -42,7 +42,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Target/Mangler.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -62,10 +62,10 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
- llvm::Module &M, const llvm::TargetData &TD,
+ llvm::Module &M, const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
: Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
- TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(*this),
TBAA(0),
@@ -103,14 +103,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.ThreadSanitizer ||
+ if (LangOpts.SanitizeThread ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
ABI.getMangleContext());
// If debug info or coverage generation is enabled, create the CGDebugInfo
// object.
- if (CodeGenOpts.DebugInfo != CodeGenOptions::NoDebugInfo ||
+ if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo ||
CodeGenOpts.EmitGcovArcs ||
CodeGenOpts.EmitGcovNotes)
DebugInfo = new CGDebugInfo(*this);
@@ -202,6 +202,12 @@ llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() {
return TBAA->getTBAAInfoForVTablePtr();
}
+llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructInfo(QTy);
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
@@ -287,7 +293,7 @@ void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!");
llvm::GlobalVariable::ThreadLocalMode TLM;
- TLM = GetLLVMTLSModel(CodeGenOpts.DefaultTLSModel);
+ TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
// Override the TLS model if it is explicitly specified.
if (D.hasAttr<TLSModelAttr>()) {
@@ -347,9 +353,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
// to deal with mixed-visibility symbols.
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- if (!CodeGenOpts.HiddenWeakTemplateVTables)
- return;
- break;
+ return;
}
// If there's a key function, there may be translation units
@@ -529,7 +533,7 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
unsigned CallingConv;
AttributeListType AttributeList;
ConstructAttributeList(Info, D, AttributeList, CallingConv);
- F->setAttributes(llvm::AttrListPtr::get(AttributeList));
+ F->setAttributes(llvm::AttrListPtr::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -559,39 +563,46 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setHasUWTable();
if (!hasUnwindExceptions(LangOpts))
- F->addFnAttr(llvm::Attribute::NoUnwind);
+ F->addFnAttr(llvm::Attributes::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);
+ F->addFnAttr(llvm::Attributes::Naked);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
if (D->hasAttr<NoInlineAttr>())
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
// (noinline wins over always_inline, and we can't specify both in IR)
if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) &&
- !F->hasFnAttr(llvm::Attribute::NoInline))
- F->addFnAttr(llvm::Attribute::AlwaysInline);
+ !F->getFnAttributes().hasAttribute(llvm::Attributes::NoInline))
+ F->addFnAttr(llvm::Attributes::AlwaysInline);
// FIXME: Communicate hot and cold attributes to LLVM more directly.
if (D->hasAttr<ColdAttr>())
- F->addFnAttr(llvm::Attribute::OptimizeForSize);
+ F->addFnAttr(llvm::Attributes::OptimizeForSize);
+
+ if (D->hasAttr<MinSizeAttr>())
+ F->addFnAttr(llvm::Attributes::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);
+
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- F->addFnAttr(llvm::Attribute::StackProtect);
+ F->addFnAttr(llvm::Attributes::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- F->addFnAttr(llvm::Attribute::StackProtectReq);
+ F->addFnAttr(llvm::Attributes::StackProtectReq);
- if (LangOpts.AddressSanitizer) {
+ if (LangOpts.SanitizeAddress) {
// When AddressSanitizer is enabled, set AddressSafety attribute
// unless __attribute__((no_address_safety_analysis)) is used.
if (!D->hasAttr<NoAddressSafetyAnalysisAttr>())
- F->addFnAttr(llvm::Attribute::AddressSafety);
+ F->addFnAttr(llvm::Attributes::AddressSafety);
}
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
@@ -636,7 +647,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (unsigned IID = F->getIntrinsicID()) {
// If this is an intrinsic function, set the function's attributes
// to the intrinsic's attributes.
- F->setAttributes(llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)IID));
+ F->setAttributes(llvm::Intrinsic::getAttributes(getLLVMContext(),
+ (llvm::Intrinsic::ID)IID));
return;
}
@@ -822,6 +834,49 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
return !getContext().DeclMustBeEmitted(Global);
}
+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();
+
+ // Look for an existing global.
+ if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name))
+ return GV;
+
+ 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);
+ return GV;
+}
+
llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
const AliasAttr *AA = VD->getAttr<AliasAttr>();
assert(AA && "No alias?");
@@ -830,19 +885,23 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
// See if there is already something with the target's name in the module.
llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
+ if (Entry) {
+ unsigned AS = getContext().getTargetAddressSpace(VD->getType());
+ return llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS));
+ }
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(),
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy,
+ GlobalDecl(cast<FunctionDecl>(VD)),
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy), 0);
- if (!Entry) {
- llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- WeakRefReferences.insert(F);
- }
+
+ llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
+ F->setLinkage(llvm::Function::ExternalWeakLinkage);
+ WeakRefReferences.insert(F);
return Aliasee;
}
@@ -1051,12 +1110,10 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- if (WeakRefReferences.count(Entry)) {
+ if (WeakRefReferences.erase(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
if (FD && !FD->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
-
- WeakRefReferences.erase(Entry);
}
if (Entry->getType()->getElementType() == Ty)
@@ -1085,8 +1142,8 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
- if (ExtraAttrs != llvm::Attribute::None)
- F->addFnAttr(ExtraAttrs);
+ if (ExtraAttrs.hasAttributes())
+ F->addAttribute(llvm::AttrListPtr::FunctionIndex, ExtraAttrs);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -1197,11 +1254,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- if (WeakRefReferences.count(Entry)) {
+ if (WeakRefReferences.erase(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
-
- WeakRefReferences.erase(Entry);
}
if (UnnamedAddr)
@@ -1279,7 +1334,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
// Because C++ name mangling, the only way we can end up with an already
// existing global with the same name is if it has been declared extern "C".
- assert(GV->isDeclaration() && "Declaration has wrong type!");
+ assert(GV->isDeclaration() && "Declaration has wrong type!");
OldGV = GV;
}
@@ -1424,7 +1479,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
- TheTargetData.getTypeStoreSizeInBits(Ty));
+ TheDataLayout.getTypeStoreSizeInBits(Ty));
}
llvm::Constant *
@@ -1473,10 +1528,10 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
// 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.
- Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(),
- const_cast<InitListExpr*>(init)->getInits(),
- init->getNumInits(),
- init->getRBraceLoc());
+ 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())
@@ -1682,9 +1737,21 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
+ // If we are compiling with ASan, add metadata indicating dynamically
+ // initialized globals.
+ if (LangOpts.SanitizeAddress && NeedsGlobalCtor) {
+ llvm::Module &M = getModule();
+
+ llvm::NamedMDNode *DynamicInitializers =
+ M.getOrInsertNamedMetadata("llvm.asan.dynamically_initialized_globals");
+ llvm::Value *GlobalToAdd[] = { GV };
+ llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalToAdd);
+ DynamicInitializers->addOperand(ThisGlobal);
+ }
+
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo)
+ if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
DI->EmitGlobalVariable(GV, D);
}
@@ -1758,8 +1825,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Attributes RAttrs = AttrList.getRetAttributes();
// Add the return attributes.
- if (RAttrs)
- AttrVec.push_back(llvm::AttributeWithIndex::get(0, RAttrs));
+ if (RAttrs.hasAttributes())
+ AttrVec.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
+ RAttrs));
// If the function was passed too few arguments, don't transform. If extra
// arguments were passed, we silently drop them. If any of the types
@@ -1775,14 +1844,18 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
}
// Add any parameter attributes.
- if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1))
+ llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1);
+ if (PAttrs.hasAttributes())
AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs));
}
if (DontTransform)
continue;
- if (llvm::Attributes FnAttrs = AttrList.getFnAttributes())
- AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs));
+ llvm::Attributes FnAttrs = AttrList.getFnAttributes();
+ if (FnAttrs.hasAttributes())
+ AttrVec.push_back(llvm::
+ AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
+ FnAttrs));
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
@@ -1791,7 +1864,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
ArgList.clear();
if (!NewCall->getType()->isVoidTy())
NewCall->takeName(CI);
- NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec));
+ NewCall->setAttributes(llvm::AttrListPtr::get(OldFn->getContext(), AttrVec));
NewCall->setCallingConv(CI->getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
@@ -1911,7 +1984,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// if a deferred decl.
llvm::Constant *Aliasee;
if (isa<llvm::FunctionType>(DeclTy))
- Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(),
+ Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD,
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
@@ -1987,7 +2060,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
IsUTF16 = true;
SmallVector<UTF16, 128> ToBuf(NumBytes + 1); // +1 for ending nulls.
- const UTF8 *FromPtr = (UTF8 *)String.data();
+ const UTF8 *FromPtr = (const UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
(void)ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
@@ -2019,7 +2092,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
bool isUTF16 = false;
llvm::StringMapEntry<llvm::Constant*> &Entry =
GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getTargetData().isLittleEndian(),
+ getDataLayout().isLittleEndian(),
isUTF16, StringLength);
if (llvm::Constant *C = Entry.getValue())
@@ -2429,7 +2502,7 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
ObjCPropertyDecl *PD = PID->getPropertyDecl();
// Determine which methods need to be implemented, some may have
- // been overridden. Note that ::isSynthesized is not the method
+ // been overridden. Note that ::isPropertyAccessor is not the method
// we want, that just indicates if the decl came from a
// property. What we want to know is if the method is defined in
// this implementation.
@@ -2465,11 +2538,11 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
cxxSelector, getContext().VoidTy, 0, D,
/*isInstance=*/true, /*isVariadic=*/false,
- /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true,
+ /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
- D->setHasCXXStructors(true);
+ D->setHasDestructors(true);
}
// If the implementation doesn't have any ivar initializers, we don't need
@@ -2487,13 +2560,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
getContext().getObjCIdType(), 0,
D, /*isInstance=*/true,
/*isVariadic=*/false,
- /*isSynthesized=*/true,
+ /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
- D->setHasCXXStructors(true);
+ D->setHasNonZeroConstructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.
@@ -2512,8 +2585,17 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
}
for (RecordDecl::decl_iterator I = LSD->decls_begin(), E = LSD->decls_end();
- I != E; ++I)
+ I != E; ++I) {
+ // Meta-data for ObjC class includes references to implemented methods.
+ // Generate class's method definitions first.
+ if (ObjCImplDecl *OID = dyn_cast<ObjCImplDecl>(*I)) {
+ for (ObjCContainerDecl::method_iterator M = OID->meth_begin(),
+ MEnd = OID->meth_end();
+ M != MEnd; ++M)
+ EmitTopLevelDecl(*M);
+ }
EmitTopLevelDecl(*I);
+ }
}
/// EmitTopLevelDecl - Emit code for a single top level declaration.
@@ -2737,3 +2819,32 @@ void CodeGenModule::EmitCoverageFile() {
}
}
}
+
+llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
+ QualType GuidType) {
+ // 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(isxdigit(Uuidstr[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);
+}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index d6ff50d5ad79..1167c87ce13b 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -35,7 +35,7 @@ namespace llvm {
class ConstantInt;
class Function;
class GlobalValue;
- class TargetData;
+ class DataLayout;
class FunctionType;
class LLVMContext;
}
@@ -210,8 +210,8 @@ struct ARCEntrypoints {
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public CodeGenTypeCache {
- CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT
- void operator=(const CodeGenModule&); // DO NOT IMPLEMENT
+ CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION;
+ void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION;
typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
@@ -219,7 +219,7 @@ class CodeGenModule : public CodeGenTypeCache {
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
- const llvm::TargetData &TheTargetData;
+ const llvm::DataLayout &TheDataLayout;
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
DiagnosticsEngine &Diags;
CGCXXABI &ABI;
@@ -296,11 +296,18 @@ class CodeGenModule : public CodeGenTypeCache {
/// order.
llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
+ typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData;
+
+ struct GlobalInitPriorityCmp {
+ bool operator()(const GlobalInitData &LHS,
+ const GlobalInitData &RHS) const {
+ return LHS.first.priority < RHS.first.priority;
+ }
+ };
+
/// - Global variables with initializers whose order of initialization
/// is set by init_priority attribute.
-
- SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8>
- PrioritizedCXXGlobalInits;
+ SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// CXXGlobalDtors - Global destructor functions and arguments that need to
/// run on termination.
@@ -357,7 +364,7 @@ class CodeGenModule : public CodeGenTypeCache {
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
- llvm::Module &M, const llvm::TargetData &TD,
+ llvm::Module &M, const llvm::DataLayout &TD,
DiagnosticsEngine &Diags);
~CodeGenModule();
@@ -451,7 +458,7 @@ public:
CodeGenVTables &getVTables() { return VTables; }
VTableContext &getVTableContext() { return VTables.getVTableContext(); }
DiagnosticsEngine &getDiags() const { return Diags; }
- const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Context.getTargetInfo(); }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
const TargetCodeGenInfo &getTargetCodeGenInfo();
@@ -461,6 +468,7 @@ public:
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
+ llvm::MDNode *getTBAAStructInfo(QualType QTy);
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
@@ -548,6 +556,9 @@ public:
/// for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
+ /// GetAddrOfUuidDescriptor - Get the address of a uuid descriptor .
+ llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
+
/// GetAddrOfThunk - Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
@@ -701,7 +712,7 @@ public:
llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
StringRef Name,
llvm::Attributes ExtraAttrs =
- llvm::Attribute::None);
+ llvm::Attributes());
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
@@ -880,7 +891,7 @@ private:
GlobalDecl D,
bool ForVTable,
llvm::Attributes ExtraAttrs =
- llvm::Attribute::None);
+ llvm::Attributes());
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
const VarDecl *D,
@@ -984,6 +995,9 @@ private:
/// to emit the .gcno and .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
+ /// Emits the initializer for a uuidof string.
+ llvm::Constant *EmitUuidofInitializer(StringRef uuidstr, QualType IIDType);
+
/// MayDeferGeneration - Determine if the given decl can be emitted
/// lazily; this is only relevant for definitions. The given decl
/// must be either a function or var decl.
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index bab60afbb7f2..d9004a02ae25 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -17,6 +17,7 @@
#include "CodeGenTBAA.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/LLVMContext.h"
@@ -167,3 +168,59 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
return MDHelper.createTBAANode("vtable pointer", getRoot());
}
+
+bool
+CodeGenTBAA::CollectFields(uint64_t BaseOffset,
+ QualType QTy,
+ SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &
+ Fields,
+ bool MayAlias) {
+ /* Things not handled yet include: C++ base classes, bitfields, */
+
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // TODO: Handle C++ base classes.
+ if (const CXXRecordDecl *Decl = dyn_cast<CXXRecordDecl>(RD))
+ if (Decl->bases_begin() != Decl->bases_end())
+ return false;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i, ++idx) {
+ uint64_t Offset = BaseOffset +
+ Layout.getFieldOffset(idx) / Context.getCharWidth();
+ QualType FieldQTy = i->getType();
+ if (!CollectFields(Offset, FieldQTy, Fields,
+ MayAlias || TypeHasMayAlias(FieldQTy)))
+ return false;
+ }
+ return true;
+ }
+
+ /* Otherwise, treat whatever it is as a field. */
+ uint64_t Offset = BaseOffset;
+ uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
+ llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy);
+ Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo));
+ return true;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
+ const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+
+ if (llvm::MDNode *N = StructMetadataCache[Ty])
+ return N;
+
+ SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
+ if (CollectFields(0, QTy, Fields, TypeHasMayAlias(QTy)))
+ return MDHelper.createTBAAStructNode(Fields);
+
+ // For now, handle any other kind of type conservatively.
+ return StructMetadataCache[Ty] = NULL;
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index c17a5cf03c60..eedb996f3eef 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -49,6 +49,10 @@ class CodeGenTBAA {
/// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
+ /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
+ /// them for struct assignments.
+ llvm::DenseMap<const Type *, llvm::MDNode *> StructMetadataCache;
+
llvm::MDNode *Root;
llvm::MDNode *Char;
@@ -60,6 +64,13 @@ class CodeGenTBAA {
/// considered to be equivalent to it.
llvm::MDNode *getChar();
+ /// CollectFields - Collect information about the fields of a type for
+ /// !tbaa.struct metadata formation. Return false for an unsupported type.
+ bool CollectFields(uint64_t BaseOffset,
+ QualType Ty,
+ SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields,
+ bool MayAlias);
+
public:
CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext,
const CodeGenOptions &CGO,
@@ -74,6 +85,10 @@ public:
/// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a
/// dereference of a vtable pointer.
llvm::MDNode *getTBAAInfoForVTablePtr();
+
+ /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
+ /// the given type.
+ llvm::MDNode *getTBAAStructInfo(QualType QTy);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 9a78daefc71c..3c6c5c9a2e2f 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -23,13 +23,13 @@
#include "clang/AST/RecordLayout.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
CodeGenTypes::CodeGenTypes(CodeGenModule &CGM)
: Context(CGM.getContext()), Target(Context.getTargetInfo()),
- TheModule(CGM.getModule()), TheTargetData(CGM.getTargetData()),
+ TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()),
TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()),
TheCXXABI(CGM.getCXXABI()),
CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) {
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 3c29d2d74626..0519911a07ef 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -23,7 +23,7 @@
namespace llvm {
class FunctionType;
class Module;
- class TargetData;
+ class DataLayout;
class Type;
class LLVMContext;
class StructType;
@@ -62,7 +62,7 @@ class CodeGenTypes {
ASTContext &Context;
const TargetInfo &Target;
llvm::Module &TheModule;
- const llvm::TargetData &TheTargetData;
+ const llvm::DataLayout &TheDataLayout;
const ABIInfo &TheABIInfo;
CGCXXABI &TheCXXABI;
const CodeGenOptions &CodeGenOpts;
@@ -108,7 +108,7 @@ public:
CodeGenTypes(CodeGenModule &CGM);
~CodeGenTypes();
- const llvm::TargetData &getTargetData() const { return TheTargetData; }
+ const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0b7ce36d5b94..245150c88d0a 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -23,11 +23,11 @@
#include "CGVTables.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include <clang/AST/Mangle.h>
-#include <clang/AST/Type.h>
-#include <llvm/Intrinsics.h>
-#include <llvm/Target/TargetData.h>
-#include <llvm/Value.h>
+#include "clang/AST/Mangle.h"
+#include "clang/AST/Type.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/DataLayout.h"
+#include "llvm/Value.h"
using namespace clang;
using namespace CodeGen;
@@ -92,6 +92,10 @@ public:
llvm::Value *Addr,
const MemberPointerType *MPT);
+ llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type);
+
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType T,
CanQualType &ResTy,
@@ -109,6 +113,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
+ StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
CharUnits getArrayCookieSizeImpl(QualType elementType);
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
@@ -299,7 +304,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
CGBuilderTy &Builder = CGF.Builder;
- unsigned AS = cast<llvm::PointerType>(Base->getType())->getAddressSpace();
+ unsigned AS = Base->getType()->getPointerAddressSpace();
// Cast to char*.
Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
@@ -677,6 +682,25 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
return MPT->getPointeeType()->isFunctionType();
}
+/// The Itanium ABI always places an offset to the complete object
+/// at entry -2 in the vtable.
+llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) {
+ // Grab the vtable pointer as an intptr_t*.
+ llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo());
+
+ // Track back to entry -2 and pull out the offset there.
+ llvm::Value *offsetPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr");
+ llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr);
+ offset->setAlignment(CGF.PointerAlignInBytes);
+
+ // Apply the offset.
+ ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
+ return CGF.Builder.CreateInBoundsGEP(ptr, offset);
+}
+
/// The generic ABI passes 'this', plus a VTT if it's initializing a
/// base subobject.
void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
@@ -810,7 +834,7 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
QualType ElementType) {
assert(requiresArrayCookie(expr));
- unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+ unsigned AS = NewPtr->getType()->getPointerAddressSpace();
ASTContext &Ctx = getContext();
QualType SizeTy = Ctx.getSizeType();
@@ -852,7 +876,7 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
CGF.Builder.CreateConstInBoundsGEP1_64(numElementsPtr,
numElementsOffset.getQuantity());
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -878,7 +902,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
// NewPtr is a char*.
- unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+ unsigned AS = NewPtr->getType()->getPointerAddressSpace();
ASTContext &Ctx = getContext();
CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
@@ -913,7 +937,7 @@ llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *numElementsPtr
= CGF.Builder.CreateConstInBoundsGEP1_64(allocPtr, CGF.SizeSizeInBytes);
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -927,9 +951,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
@@ -937,9 +961,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
// void __cxa_guard_release(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
@@ -947,9 +971,9 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
// void __cxa_guard_abort(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
-
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
- llvm::Attribute::NoUnwind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NoUnwind));
}
namespace {
@@ -1149,7 +1173,7 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
// In Apple kexts, we want to add a global destructor entry.
// FIXME: shouldn't this be guarded by some variable?
- if (CGM.getContext().getLangOpts().AppleKext) {
+ if (CGM.getLangOpts().AppleKext) {
// Generate a global destructor entry.
return CGM.AddCXXDtorEntry(dtor, addr);
}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 6a2925bbd953..8d205c3d0f5d 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -29,14 +29,18 @@ public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
StringRef GetPureVirtualCallName() { return "_purecall"; }
+ // No known support for deleted functions in MSVC yet, so this choice is
+ // arbitrary.
+ StringRef GetDeletedVirtualCallName() { return "_purecall"; }
+
+ llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type);
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
- // TODO: 'for base' flag
- }
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
CXXDtorType Type,
@@ -48,15 +52,9 @@ public:
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
- FunctionArgList &Params) {
- BuildThisParam(CGF, Params);
- // TODO: 'for base' flag
- }
+ FunctionArgList &Params);
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- EmitThisParam(CGF);
- // TODO: 'for base' flag
- }
+ void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
@@ -99,10 +97,49 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize);
+ static bool needThisReturn(GlobalDecl GD);
};
}
+llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
+ llvm::Value *ptr,
+ QualType type) {
+ // FIXME: implement
+ return ptr;
+}
+
+bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
+ const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
+ return isa<CXXConstructorDecl>(MD);
+}
+
+void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type,
+ CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
+ // 'this' is already in place
+ // TODO: 'for base' flag
+ // Ctor returns this ptr
+ ResTy = ArgTys[0];
+}
+
+void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
+ QualType &ResTy,
+ FunctionArgList &Params) {
+ BuildThisParam(CGF, Params);
+ if (needThisReturn(CGF.CurGD)) {
+ ResTy = Params[0]->getType();
+ }
+}
+
+void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
+ EmitThisParam(CGF);
+ if (needThisReturn(CGF.CurGD)) {
+ CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
+ }
+}
+
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
QualType elementType) {
// Microsoft seems to completely ignore the possibility of a
@@ -127,7 +164,7 @@ CharUnits MicrosoftCXXABI::getArrayCookieSizeImpl(QualType type) {
llvm::Value *MicrosoftCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize) {
- unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+ unsigned AS = allocPtr->getType()->getPointerAddressSpace();
llvm::Value *numElementsPtr =
CGF.Builder.CreateBitCast(allocPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
@@ -147,7 +184,7 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *cookiePtr = newPtr;
// Write the number of elements into the appropriate slot.
- unsigned AS = cast<llvm::PointerType>(newPtr->getType())->getAddressSpace();
+ unsigned AS = newPtr->getType()->getPointerAddressSpace();
llvm::Value *numElementsPtr
= CGF.Builder.CreateBitCast(cookiePtr, CGF.SizeTy->getPointerTo(AS));
CGF.Builder.CreateStore(numElements, numElementsPtr);
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index ea2389e66b5a..012555962f82 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -21,14 +21,14 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/ADT/OwningPtr.h"
using namespace clang;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
- OwningPtr<const llvm::TargetData> TD;
+ OwningPtr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
@@ -54,7 +54,7 @@ namespace {
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
- TD.reset(new llvm::TargetData(Ctx->getTargetInfo().getTargetDescription()));
+ TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
*M, *TD, Diags));
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 9c23ed9871da..ffff0d0a1bc4 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Type.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -51,8 +51,8 @@ llvm::LLVMContext &ABIInfo::getVMContext() const {
return CGT.getLLVMContext();
}
-const llvm::TargetData &ABIInfo::getTargetData() const {
- return CGT.getTargetData();
+const llvm::DataLayout &ABIInfo::getDataLayout() const {
+ return CGT.getDataLayout();
}
@@ -389,6 +389,90 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
+//===----------------------------------------------------------------------===//
+// le32/PNaCl bitcode ABI Implementation
+//===----------------------------------------------------------------------===//
+
+class PNaClABIInfo : public ABIInfo {
+ public:
+ PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {}
+};
+
+void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+
+ unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0;
+
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, FreeRegs);
+ }
+
+llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &FreeRegs) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ FreeRegs = 0;
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Regparm regs hold 32 bits.
+ unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ if (SizeInRegs == 0) return BaseInfo;
+ if (SizeInRegs > FreeRegs) {
+ FreeRegs = 0;
+ return BaseInfo;
+ }
+ FreeRegs -= SizeInRegs;
+ return BaseInfo.isDirect() ?
+ ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) :
+ ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType());
+}
+
+ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy))
+ return ABIArgInfo::getIndirect(0);
+
+ // 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());
+}
+
/// UseX86_MMXType - Return true if this is an MMX type that should use the
/// special x86_mmx type.
bool UseX86_MMXType(llvm::Type *IRType) {
@@ -435,7 +519,8 @@ class X86_32ABIInfo : public ABIInfo {
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty, bool ByVal = true) const;
+ ABIArgInfo getIndirectResult(QualType Ty, bool ByVal,
+ unsigned &FreeRegs) const;
/// \brief Return the alignment to use for the given type on the stack.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
@@ -443,9 +528,10 @@ class X86_32ABIInfo : public ABIInfo {
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy,
unsigned callingConvention) const;
- ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy,
- unsigned &FreeRegs) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs,
+ bool IsFastCall) const;
+ bool shouldUseInReg(QualType Ty, unsigned &FreeRegs,
+ bool IsFastCall, bool &NeedsPadding) const;
public:
@@ -682,9 +768,15 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
return MinABIStackAlignInBytes;
}
-ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
- if (!ByVal)
+ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
+ unsigned &FreeRegs) const {
+ if (!ByVal) {
+ if (FreeRegs) {
+ --FreeRegs; // Non byval indirects just use one pointer.
+ return ABIArgInfo::getIndirectInReg(0, false);
+ }
return ABIArgInfo::getIndirect(0, false);
+ }
// Compute the byval alignment.
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
@@ -714,45 +806,51 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
return Integer;
}
-ABIArgInfo
-X86_32ABIInfo::classifyArgumentTypeWithReg(QualType Ty,
- unsigned &FreeRegs) const {
- // Common case first.
- if (FreeRegs == 0)
- return classifyArgumentType(Ty);
-
+bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
+ bool IsFastCall, bool &NeedsPadding) const {
+ NeedsPadding = false;
Class C = classify(Ty);
if (C == Float)
- return classifyArgumentType(Ty);
+ return false;
+
+ unsigned Size = getContext().getTypeSize(Ty);
+ unsigned SizeInRegs = (Size + 31) / 32;
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
if (SizeInRegs == 0)
- return classifyArgumentType(Ty);
+ return false;
if (SizeInRegs > FreeRegs) {
FreeRegs = 0;
- return classifyArgumentType(Ty);
+ return false;
}
- assert(SizeInRegs >= 1 && SizeInRegs <= 3);
+
FreeRegs -= SizeInRegs;
- // If it is a simple scalar, keep the type so that we produce a cleaner IR.
- ABIArgInfo Foo = classifyArgumentType(Ty);
- if (Foo.isDirect() && !Foo.getDirectOffset() && !Foo.getPaddingType())
- return ABIArgInfo::getDirectInReg(Foo.getCoerceToType());
- if (Foo.isExtend())
- return ABIArgInfo::getExtendInReg(Foo.getCoerceToType());
+ if (IsFastCall) {
+ if (Size > 32)
+ return false;
+
+ if (Ty->isIntegralOrEnumerationType())
+ return true;
+
+ if (Ty->isPointerType())
+ return true;
+
+ if (Ty->isReferenceType())
+ return true;
+
+ if (FreeRegs)
+ NeedsPadding = true;
- llvm::LLVMContext &LLVMContext = getVMContext();
- llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext);
- SmallVector<llvm::Type*, 3> Elements;
- for (unsigned I = 0; I < SizeInRegs; ++I)
- Elements.push_back(Int32);
- llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
- return ABIArgInfo::getDirectInReg(Result);
+ return false;
+ }
+
+ return true;
}
-ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &FreeRegs,
+ bool IsFastCall) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
// Structures with flexible arrays are always indirect.
@@ -760,25 +858,38 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
- return getIndirectResult(Ty, /*ByVal=*/false);
+ return getIndirectResult(Ty, false, FreeRegs);
if (RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectResult(Ty);
+ return getIndirectResult(Ty, true, FreeRegs);
}
// Ignore empty structs/unions.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
+ llvm::LLVMContext &LLVMContext = getVMContext();
+ llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
+ 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);
+ llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
+ return ABIArgInfo::getDirectInReg(Result);
+ }
+ llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : 0;
+
// Expand small (<= 128-bit) record types when we know that the stack layout
// of those arguments will match the struct. This is important because the
// LLVM backend isn't smart enough to remove byval, which inhibits many
// optimizations.
if (getContext().getTypeSize(Ty) <= 4*32 &&
canExpandIndirectArgument(Ty, getContext()))
- return ABIArgInfo::getExpand();
+ return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType);
- return getIndirectResult(Ty);
+ return getIndirectResult(Ty, true, FreeRegs);
}
if (const VectorType *VT = Ty->getAs<VectorType>()) {
@@ -809,16 +920,32 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ bool NeedsPadding;
+ bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding);
+
+ if (Ty->isPromotableIntegerType()) {
+ if (InReg)
+ return ABIArgInfo::getExtendInReg();
+ return ABIArgInfo::getExtend();
+ }
+ if (InReg)
+ return ABIArgInfo::getDirectInReg();
+ return ABIArgInfo::getDirect();
}
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
FI.getCallingConvention());
- unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() :
- DefaultNumRegisterParameters;
+ unsigned CC = FI.getCallingConvention();
+ bool IsFastCall = CC == llvm::CallingConv::X86_FastCall;
+ unsigned FreeRegs;
+ if (IsFastCall)
+ FreeRegs = 2;
+ else if (FI.getHasRegParm())
+ FreeRegs = FI.getRegParm();
+ else
+ FreeRegs = DefaultNumRegisterParameters;
// If the return value is indirect, then the hidden argument is consuming one
// integer register.
@@ -832,7 +959,7 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentTypeWithReg(it->type, FreeRegs);
+ it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall);
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -884,7 +1011,10 @@ void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::Function *Fn = cast<llvm::Function>(GV);
// Now add the 'alignstack' attribute with a value of 16.
- Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16));
+ llvm::AttrBuilder B;
+ B.addStackAlignmentAttr(16);
+ Fn->addAttribute(llvm::AttrListPtr::FunctionIndex,
+ llvm::Attributes::get(CGM.getLLVMContext(), B));
}
}
}
@@ -1030,10 +1160,15 @@ class X86_64ABIInfo : public ABIInfo {
}
bool HasAVX;
+ // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
+ // 64-bit hardware.
+ bool Has64BitPointers;
public:
X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) :
- ABIInfo(CGT), HasAVX(hasavx) {}
+ ABIInfo(CGT), HasAVX(hasavx),
+ Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) {
+ }
bool isPassedUsingAVXType(QualType type) const {
unsigned neededInt, neededSSE;
@@ -1070,7 +1205,7 @@ public:
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
- : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
+ : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
const X86_64ABIInfo &getABIInfo() const {
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -1243,7 +1378,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Hi = Integer;
} else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
Current = Integer;
- } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
+ } else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
+ (k == BuiltinType::LongDouble &&
+ getContext().getTargetInfo().getTriple().getOS() ==
+ llvm::Triple::NativeClient)) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1266,7 +1404,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
}
if (Ty->isMemberPointerType()) {
- if (Ty->isMemberFunctionPointerType())
+ if (Ty->isMemberFunctionPointerType() && Has64BitPointers)
Lo = Hi = Integer;
else
Current = Integer;
@@ -1329,7 +1467,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Lo = Hi = Integer;
} else if (ET == getContext().FloatTy)
Current = SSE;
- else if (ET == getContext().DoubleTy)
+ else if (ET == getContext().DoubleTy ||
+ (ET == getContext().LongDoubleTy &&
+ getContext().getTargetInfo().getTriple().getOS() ==
+ llvm::Triple::NativeClient))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -1708,7 +1849,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
/// float at offset 4. It is conservatively correct for this routine to return
/// false.
static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset,
- const llvm::TargetData &TD) {
+ const llvm::DataLayout &TD) {
// Base case if we find a float.
if (IROffset == 0 && IRType->isFloatTy())
return true;
@@ -1748,8 +1889,8 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// We want to pass as <2 x float> if the LLVM IR type contains a float at
// offset+0 and offset+4. Walk the LLVM IR type to find out if this is the
// case.
- if (ContainsFloatAtOffset(IRType, IROffset, getTargetData()) &&
- ContainsFloatAtOffset(IRType, IROffset+4, getTargetData()))
+ if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) &&
+ ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout()))
return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2);
return llvm::Type::getDoubleTy(getVMContext());
@@ -1777,7 +1918,8 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// returning an 8-byte unit starting with it. See if we can safely use it.
if (IROffset == 0) {
// Pointers and int64's always fill the 8-byte unit.
- if (isa<llvm::PointerType>(IRType) || IRType->isIntegerTy(64))
+ if ((isa<llvm::PointerType>(IRType) && Has64BitPointers) ||
+ IRType->isIntegerTy(64))
return IRType;
// If we have a 1/2/4-byte integer, we can use it only if the rest of the
@@ -1787,8 +1929,10 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
// have to do this analysis on the source type because we can't depend on
// unions being lowered a specific way etc.
if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) ||
- IRType->isIntegerTy(32)) {
- unsigned BitWidth = cast<llvm::IntegerType>(IRType)->getBitWidth();
+ IRType->isIntegerTy(32) ||
+ (isa<llvm::PointerType>(IRType) && !Has64BitPointers)) {
+ unsigned BitWidth = isa<llvm::PointerType>(IRType) ? 32 :
+ cast<llvm::IntegerType>(IRType)->getBitWidth();
if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth,
SourceOffset*8+64, getContext()))
@@ -1798,7 +1942,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) {
// If this is a struct, recurse into the field at the specified offset.
- const llvm::StructLayout *SL = getTargetData().getStructLayout(STy);
+ const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy);
if (IROffset < SL->getSizeInBytes()) {
unsigned FieldIdx = SL->getElementContainingOffset(IROffset);
IROffset -= SL->getElementOffset(FieldIdx);
@@ -1810,7 +1954,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) {
llvm::Type *EltTy = ATy->getElementType();
- unsigned EltSize = getTargetData().getTypeAllocSize(EltTy);
+ unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy);
unsigned EltOffset = IROffset/EltSize*EltSize;
return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy,
SourceOffset);
@@ -1837,14 +1981,14 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
/// return {i32*, float}.
static llvm::Type *
GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
- const llvm::TargetData &TD) {
+ const llvm::DataLayout &TD) {
// In order to correctly satisfy the ABI, we need to the high part to start
// at offset 8. If the high and low parts we inferred are both 4-byte types
// (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
// the second element at offset 8. Check for this:
unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
unsigned HiAlign = TD.getABITypeAlignment(Hi);
- unsigned HiStart = llvm::TargetData::RoundUpAlignment(LoSize, HiAlign);
+ unsigned HiStart = llvm::DataLayout::RoundUpAlignment(LoSize, HiAlign);
assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
// To handle this, we have to increase the size of the low part so that the
@@ -1996,7 +2140,7 @@ classifyReturnType(QualType RetTy) const {
// known to pass in the high eightbyte of the result. We do this by forming a
// first class struct aggregate with the high and low part: {low, high}
if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData());
+ ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
return ABIArgInfo::getDirect(ResType);
}
@@ -2122,7 +2266,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
// known to pass in the high eightbyte of the result. We do this by forming a
// first class struct aggregate with the high and low part: {low, high}
if (HighPart)
- ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData());
+ ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout());
return ABIArgInfo::getDirect(ResType);
}
@@ -2435,6 +2579,43 @@ llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+namespace {
+
+class NaClX86_64ABIInfo : public ABIInfo {
+ public:
+ NaClX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, HasAVX) {}
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+ private:
+ PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
+ X86_64ABIInfo NInfo; // Used for everything else.
+};
+
+class NaClX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)) {}
+};
+
+}
+
+void NaClX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (FI.getASTCallingConvention() == CC_PnaclCall)
+ PInfo.computeInfo(FI);
+ else
+ NInfo.computeInfo(FI);
+}
+
+llvm::Value *NaClX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // Always use the native convention; calling pnacl-style varargs functions
+ // is unuspported.
+ return NInfo.EmitVAArg(VAListAddr, Ty, CGF);
+}
+
+
// PowerPC-32
namespace {
@@ -2497,6 +2678,62 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// PowerPC-64
namespace {
+/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information.
+class PPC64_SVR4_ABIInfo : public DefaultABIInfo {
+
+public:
+ PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+
+ bool isPromotableTypeForABI(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType Ty) const;
+
+ // TODO: We can add more logic to computeInfo to improve performance.
+ // Example: For aggregate arguments that fit in a register, we could
+ // use getDirectInReg (as is done below for structs containing a single
+ // floating-point value) to avoid pushing them to memory on function
+ // entry. This would require changing the logic in PPCISelLowering
+ // when lowering the parameters in the caller and args in the callee.
+ 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) {
+ // 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.
+ const Type *T = isSingleElementStruct(it->type, getContext());
+ if (T) {
+ const BuiltinType *BT = T->getAs<BuiltinType>();
+ if (BT && BT->isFloatingPoint()) {
+ QualType QT(T, 0);
+ it->info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
+ continue;
+ }
+ }
+ it->info = classifyArgumentType(it->type);
+ }
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT)) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ // This is recovered from gcc output.
+ return 1; // r1 is the dedicated stack pointer
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const;
+};
+
class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
public:
PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
@@ -2512,9 +2749,94 @@ public:
}
+// Return true if the ABI requires Ty to be passed sign- or zero-
+// extended to 64 bits.
bool
-PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
+PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ // Promotable integer types are required to be promoted by the ABI.
+ if (Ty->isPromotableIntegerType())
+ return true;
+
+ // In addition to the usual promotable integer types, we also need to
+ // extend all 32-bit types, since the ABI requires promotion to 64 bits.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+ABIArgInfo
+PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ return (isPromotableTypeForABI(Ty) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo
+PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy))
+ return ABIArgInfo::getIndirect(0);
+
+ return (isPromotableTypeForABI(RetTy) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+// Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine.
+llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) const {
+ llvm::Type *BP = CGF.Int8PtrTy;
+ 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");
+
+ // Update the va_list pointer.
+ unsigned SizeInBytes = CGF.getContext().getTypeSize(Ty) / 8;
+ unsigned Offset = llvm::RoundUpToAlignment(SizeInBytes, 8);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int64Ty, Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ // If the argument is smaller than 8 bytes, it is right-adjusted in
+ // its doubleword slot. Adjust the pointer to pick it up from the
+ // correct offset.
+ if (SizeInBytes < 8) {
+ llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
+ AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(8 - SizeInBytes));
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
+ }
+
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ return Builder.CreateBitCast(Addr, PTy);
+}
+
+static bool
+PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) {
// This is calculated from the LLVM and GCC tables and verified
// against gcc output. AFAIK all ABIs use the same encoding.
@@ -2553,6 +2875,21 @@ PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
return false;
}
+bool
+PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable(
+ CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+
+ return PPC64_initDwarfEHRegSizeTable(CGF, Address);
+}
+
+bool
+PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+
+ return PPC64_initDwarfEHRegSizeTable(CGF, Address);
+}
+
//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
@@ -2576,14 +2913,18 @@ public:
bool isEABI() const {
StringRef Env =
getContext().getTargetInfo().getTriple().getEnvironmentName();
- return (Env == "gnueabi" || Env == "eabi" || Env == "androideabi");
+ return (Env == "gnueabi" || Env == "eabi" ||
+ Env == "android" || Env == "androideabi");
}
private:
ABIKind getABIKind() const { return Kind; }
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
+ unsigned &AllocatedVFP,
+ bool &IsHA) const;
+ bool isIllegalVectorType(QualType Ty) const;
virtual void computeInfo(CGFunctionInfo &FI) const;
@@ -2626,10 +2967,33 @@ public:
}
void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ // To correctly handle Homogeneous Aggregate, we need to keep track of the
+ // VFP registers allocated so far.
+ // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive
+ // VFP registers of the appropriate type unallocated then the argument is
+ // allocated to the lowest-numbered sequence of such registers.
+ // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are
+ // unallocated are marked as unavailable.
+ unsigned AllocatedVFP = 0;
+ int VFPRegs[16] = { 0 };
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);
+ it != ie; ++it) {
+ unsigned PreAllocation = AllocatedVFP;
+ bool IsHA = false;
+ // 6.1.2.3 There is one VFP co-processor register class using registers
+ // s0-s15 (d0-d7) for passing arguments.
+ const unsigned NumVFPs = 16;
+ it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA);
+ // If we do not have enough VFP registers for the HA, any VFP registers
+ // that are unallocated are marked as unavailable. To achieve this, we add
+ // padding of (NumVFPs - PreAllocation) floats.
+ if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
+ llvm::Type *PaddingTy = llvm::ArrayType::get(
+ llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
+ it->info = ABIArgInfo::getExpandWithPadding(false, PaddingTy);
+ }
+ }
// Always honor user-specified calling convention.
if (FI.getCallingConvention() != llvm::CallingConv::C)
@@ -2637,7 +3001,9 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- if (isEABI())
+ if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
+ DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP;
+ else if (isEABI())
DefaultCC = llvm::CallingConv::ARM_AAPCS;
else
DefaultCC = llvm::CallingConv::ARM_APCS;
@@ -2729,7 +3095,88 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
return (Members > 0 && Members <= 4);
}
-ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
+/// markAllocatedVFPs - update VFPRegs according to the alignment and
+/// number of VFP registers (unit is S register) requested.
+static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
+ unsigned Alignment,
+ unsigned NumRequired) {
+ // Early Exit.
+ if (AllocatedVFP >= 16)
+ return;
+ // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive
+ // VFP registers of the appropriate type unallocated then the argument is
+ // allocated to the lowest-numbered sequence of such registers.
+ for (unsigned I = 0; I < 16; I += Alignment) {
+ bool FoundSlot = true;
+ for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++)
+ if (J >= 16 || VFPRegs[J]) {
+ FoundSlot = false;
+ break;
+ }
+ if (FoundSlot) {
+ for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++)
+ VFPRegs[J] = 1;
+ AllocatedVFP += NumRequired;
+ return;
+ }
+ }
+ // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are
+ // unallocated are marked as unavailable.
+ for (unsigned I = 0; I < 16; I++)
+ VFPRegs[I] = 1;
+ AllocatedVFP = 17; // We do not have enough VFP registers.
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
+ unsigned &AllocatedVFP,
+ bool &IsHA) const {
+ // We update number of allocated VFPs according to
+ // 6.1.2.1 The following argument types are VFP CPRCs:
+ // A single-precision floating-point type (including promoted
+ // half-precision types); A double-precision floating-point type;
+ // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate
+ // with a Base Type of a single- or double-precision floating-point type,
+ // 64-bit containerized vectors or 128-bit containerized vectors with one
+ // to four Elements.
+
+ // Handle illegal vector types here.
+ if (isIllegalVectorType(Ty)) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 32) {
+ llvm::Type *ResType =
+ llvm::Type::getInt32Ty(getVMContext());
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 64) {
+ llvm::Type *ResType = llvm::VectorType::get(
+ llvm::Type::getInt32Ty(getVMContext()), 2);
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 128) {
+ llvm::Type *ResType = llvm::VectorType::get(
+ llvm::Type::getInt32Ty(getVMContext()), 4);
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 4, 4);
+ return ABIArgInfo::getDirect(ResType);
+ }
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+ // Update VFPRegs for legal vector types.
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ uint64_t Size = getContext().getTypeSize(VT);
+ // Size of a legal vector should be power of 2 and above 64.
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, Size >= 128 ? 4 : 2, Size / 32);
+ }
+ // Update VFPRegs for floating point types.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Half ||
+ BT->getKind() == BuiltinType::Float)
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, 1);
+ if (BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble)
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ }
+
if (!isAggregateTypeForABI(Ty)) {
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
@@ -2749,18 +3196,42 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
- // Homogeneous Aggregates need to be expanded.
+ // Homogeneous Aggregates need to be expanded when we can fit the aggregate
+ // into VFP registers.
const Type *Base = 0;
- if (isHomogeneousAggregate(Ty, Base, getContext())) {
+ uint64_t Members = 0;
+ if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
assert(Base && "Base class should be set for homogeneous aggregate");
+ // Base can be a floating-point or a vector.
+ if (Base->isVectorType()) {
+ // ElementSize is in number of floats.
+ unsigned ElementSize = getContext().getTypeSize(Base) == 64 ? 2 : 4;
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, ElementSize,
+ Members * ElementSize);
+ } else if (Base->isSpecificBuiltinType(BuiltinType::Float))
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, Members);
+ else {
+ assert(Base->isSpecificBuiltinType(BuiltinType::Double) ||
+ Base->isSpecificBuiltinType(BuiltinType::LongDouble));
+ markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, Members * 2);
+ }
+ IsHA = true;
return ABIArgInfo::getExpand();
}
}
// Support byval for ARM.
- if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64) ||
- getContext().getTypeAlign(Ty) > 64) {
- return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
+ // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at
+ // most 8-byte. We realign the indirect argument if type alignment is bigger
+ // than ABI alignment.
+ uint64_t ABIAlign = 4;
+ uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8;
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
+ getABIKind() == ARMABIInfo::AAPCS)
+ ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+ if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/true,
+ /*Realign=*/TyAlign > ABIAlign);
}
// Otherwise, pass by coercing to a structure of the appropriate size.
@@ -2946,6 +3417,21 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIndirect(0);
}
+/// isIllegalVector - check whether Ty is an illegal vector type.
+bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ // Check whether VT is legal.
+ unsigned NumElements = VT->getNumElements();
+ uint64_t Size = getContext().getTypeSize(VT);
+ // NumElements should be power of 2.
+ if ((NumElements & (NumElements - 1)) != 0)
+ return true;
+ // Size should be greater than 32 bits.
+ return Size <= 32;
+ }
+ return false;
+}
+
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
llvm::Type *BP = CGF.Int8PtrTy;
@@ -2954,30 +3440,104 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- // Handle address alignment for type alignment > 32 bits
+
+ uint64_t Size = CGF.getContext().getTypeSize(Ty) / 8;
uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
+ bool IsIndirect = false;
+
+ // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for
+ // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte.
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
+ getABIKind() == ARMABIInfo::AAPCS)
+ TyAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+ else
+ TyAlign = 4;
+ // Use indirect if size of the illegal vector is bigger than 16 bytes.
+ if (isIllegalVectorType(Ty) && Size > 16) {
+ IsIndirect = true;
+ Size = 4;
+ TyAlign = 4;
+ }
+
+ // Handle address alignment for ABI alignment > 4 bytes.
if (TyAlign > 4) {
assert((TyAlign & (TyAlign - 1)) == 0 &&
"Alignment is not power of 2!");
llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1));
AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1)));
- Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP, "ap.align");
}
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
- llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::RoundUpToAlignment(Size, 4);
llvm::Value *NextAddr =
Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+ if (IsIndirect)
+ Addr = Builder.CreateLoad(Builder.CreateBitCast(Addr, BPP));
+ else if (TyAlign < CGF.getContext().getTypeAlign(Ty) / 8) {
+ // We can't directly cast ap.cur to pointer to a vector type, since ap.cur
+ // may not be correctly aligned for the vector type. We create an aligned
+ // temporary space and copy the content over from ap.cur to the temporary
+ // space. This is necessary if the natural alignment of the type is greater
+ // than the ABI alignment.
+ llvm::Type *I8PtrTy = Builder.getInt8PtrTy();
+ CharUnits CharSize = getContext().getTypeSizeInChars(Ty);
+ llvm::Value *AlignedTemp = CGF.CreateTempAlloca(CGF.ConvertType(Ty),
+ "var.align");
+ llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy);
+ llvm::Value *Src = Builder.CreateBitCast(Addr, I8PtrTy);
+ Builder.CreateMemCpy(Dst, Src,
+ llvm::ConstantInt::get(CGF.IntPtrTy, CharSize.getQuantity()),
+ TyAlign, false);
+ Addr = AlignedTemp; //The content is in aligned location.
+ }
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
return AddrTyped;
}
+namespace {
+
+class NaClARMABIInfo : public ABIInfo {
+ public:
+ NaClARMABIInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+ : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, Kind) {}
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+ private:
+ PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
+ ARMABIInfo NInfo; // Used for everything else.
+};
+
+class NaClARMTargetCodeGenInfo : public TargetCodeGenInfo {
+ public:
+ NaClARMTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
+ : TargetCodeGenInfo(new NaClARMABIInfo(CGT, Kind)) {}
+};
+
+}
+
+void NaClARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (FI.getASTCallingConvention() == CC_PnaclCall)
+ PInfo.computeInfo(FI);
+ else
+ static_cast<const ABIInfo&>(NInfo).computeInfo(FI);
+}
+
+llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // Always use the native convention; calling pnacl-style varargs functions
+ // is unsupported.
+ return static_cast<const ABIInfo&>(NInfo).EmitVAArg(VAListAddr, Ty, CGF);
+}
+
//===----------------------------------------------------------------------===//
// NVPTX ABI Implementation
//===----------------------------------------------------------------------===//
@@ -3072,7 +3632,7 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// OpenCL __kernel functions get a kernel calling convention
F->setCallingConv(llvm::CallingConv::PTX_Kernel);
// And kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
}
@@ -3188,7 +3748,7 @@ void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(CC);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
}
// Step 3: Emit _interrupt_handler alias.
@@ -3226,7 +3786,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
// Step 3: Emit ISR vector alias.
unsigned Num = attr->getNumber() + 0xffe0;
@@ -3583,7 +4143,7 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
if (M.getLangOpts().OpenCL) {
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL C Kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attribute::NoInline);
+ F->addFnAttr(llvm::Attributes::NoInline);
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
@@ -3767,6 +4327,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
+ case llvm::Triple::le32:
+ return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types));
case llvm::Triple::mips:
case llvm::Triple::mipsel:
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true));
@@ -3779,19 +4341,29 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::thumb:
{
ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
-
if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0)
Kind = ARMABIInfo::APCS;
- else if (CodeGenOpts.FloatABI == "hard")
+ else if (CodeGenOpts.FloatABI == "hard" ||
+ (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF))
Kind = ARMABIInfo::AAPCS_VFP;
- return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind));
+ switch (Triple.getOS()) {
+ case llvm::Triple::NativeClient:
+ return *(TheTargetCodeGenInfo =
+ new NaClARMTargetCodeGenInfo(Types, Kind));
+ default:
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(Types, Kind));
+ }
}
case llvm::Triple::ppc:
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
case llvm::Triple::ppc64:
- return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
+ if (Triple.isOSBinFormatELF())
+ return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
+ else
+ return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
@@ -3848,6 +4420,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::MinGW32:
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
+ case llvm::Triple::NativeClient:
+ return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
default:
return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
HasAVX));
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index c0a2a506a6ba..93d70a9fefed 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#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"
@@ -15,22 +16,23 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
+using clang::StringRef;
-Arg::Arg(const Option *_Opt, unsigned _Index, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+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, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
}
-Arg::Arg(const Option *_Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const char *Value1, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
Values.push_back(Value1);
@@ -47,7 +49,7 @@ void Arg::dump() const {
llvm::errs() << "<";
llvm::errs() << " Opt:";
- Opt->dump();
+ Opt.dump();
llvm::errs() << " Index:" << Index;
@@ -83,39 +85,39 @@ void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const {
}
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, 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(Args, i));
+ Output.push_back(getValue(i));
break;
case Option::RenderCommaJoinedStyle: {
SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
- OS << getOption().getName();
+ OS << getSpelling();
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
if (i) OS << ',';
- OS << getValue(Args, i);
+ OS << getValue(i);
}
Output.push_back(Args.MakeArgString(OS.str()));
break;
}
-
+
case Option::RenderJoinedStyle:
Output.push_back(Args.GetOrMakeJoinedArgString(
- getIndex(), getOption().getName(), getValue(Args, 0)));
+ getIndex(), getSpelling(), getValue(0)));
for (unsigned i = 1, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
break;
case Option::RenderSeparateStyle:
- Output.push_back(getOption().getName().data());
+ Output.push_back(Args.MakeArgString(getSpelling()));
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
- Output.push_back(getValue(Args, i));
+ Output.push_back(getValue(i));
break;
}
}
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 7fd439e63082..b3a43df98041 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -211,7 +211,7 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
StringRef ArgList::getLastArgValue(OptSpecifier Id,
StringRef Default) const {
if (Arg *A = getLastArg(Id))
- return A->getValue(*this);
+ return A->getValue();
return Default;
}
@@ -220,10 +220,10 @@ int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
int Res = Default;
if (Arg *A = getLastArg(Id)) {
- if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) {
+ if (StringRef(A->getValue()).getAsInteger(10, Res)) {
if (Diags)
Diags->Report(diag::err_drv_invalid_int_value)
- << A->getAsString(*this) << A->getValue(*this);
+ << A->getAsString(*this) << A->getValue();
}
}
@@ -258,7 +258,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
ie = filtered_end(); it != ie; ++it) {
(*it)->claim();
for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
- Output.push_back((*it)->getValue(*this, i));
+ Output.push_back((*it)->getValue(i));
}
}
@@ -271,10 +271,10 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
if (Joined) {
Output.push_back(MakeArgString(StringRef(Translation) +
- (*it)->getValue(*this, 0)));
+ (*it)->getValue(0)));
} else {
Output.push_back(Translation);
- Output.push_back((*it)->getValue(*this, 0));
+ Output.push_back((*it)->getValue(0));
}
}
}
@@ -362,33 +362,40 @@ 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, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
+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,
+Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg);
+ 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,
+Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
- unsigned Index = BaseArgs.MakeIndex(Opt->getName(), Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg);
+ 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,
+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, Index,
- BaseArgs.getArgString(Index) + Opt->getName().size(),
+ 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 ea80f5a20eae..4f89b73a46d3 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -15,11 +15,19 @@ using namespace clang::driver;
using namespace clang::driver::options;
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)
+#include "clang/Driver/CC1AsOptions.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info CC1AsInfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/CC1AsOptions.inc"
};
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index c962fca0bf9a..124e50c32ea4 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -17,6 +17,7 @@
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Program.h"
#include <sys/stat.h>
@@ -101,6 +102,105 @@ void Compilation::PrintJob(raw_ostream &OS, const Job &J,
}
}
+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", "-fmodule-cache-path", "-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 << '"';
+ }
+
+ 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);
+ }
+}
+
bool Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 87d533dd2953..68471ec04c6a 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -52,25 +52,13 @@ Driver::Driver(StringRef ClangExecutable,
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
DefaultImageName(DefaultImageName),
- DriverTitle("clang \"gcc-compatible\" driver"),
+ DriverTitle("clang LLVM compiler"),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
CCLogDiagnosticsFilename(0), CCCIsCXX(false),
CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
- CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true),
- ForcedClangUse(false), CCCUsePCH(true), SuppressMissingInputWarning(false) {
- if (IsProduction) {
- // In a "production" build, only use clang on architectures we expect to
- // work.
- //
- // During development its more convenient to always have the driver use
- // clang, but we don't want users to be confused when things don't work, or
- // to file bugs for things we don't support.
- CCCClangArchs.insert(llvm::Triple::x86);
- CCCClangArchs.insert(llvm::Triple::x86_64);
- CCCClangArchs.insert(llvm::Triple::arm);
- }
+ CCCUsePCH(true), SuppressMissingInputWarning(false) {
Name = llvm::sys::path::stem(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
@@ -109,7 +97,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().isUnsupported()) {
+ if (A->getOption().hasFlag(options::Unsupported)) {
Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args);
continue;
}
@@ -186,9 +174,9 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Add the remaining values as Xlinker arguments.
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (StringRef(A->getValue(Args, i)) != "--no-demangle")
+ if (StringRef(A->getValue(i)) != "--no-demangle")
DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker),
- A->getValue(Args, i));
+ A->getValue(i));
continue;
}
@@ -197,22 +185,22 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// some build systems. We don't try to be complete here because we don't
// care to encourage this usage model.
if (A->getOption().matches(options::OPT_Wp_COMMA) &&
- A->getNumValues() == 2 &&
- (A->getValue(Args, 0) == StringRef("-MD") ||
- A->getValue(Args, 0) == StringRef("-MMD"))) {
+ (A->getValue(0) == StringRef("-MD") ||
+ A->getValue(0) == StringRef("-MMD"))) {
// Rewrite to -MD/-MMD along with -MF.
- if (A->getValue(Args, 0) == StringRef("-MD"))
+ if (A->getValue(0) == StringRef("-MD"))
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD));
else
DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD));
- DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF),
- A->getValue(Args, 1));
+ if (A->getNumValues() == 2)
+ DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF),
+ A->getValue(1));
continue;
}
// Rewrite reserved library names.
if (A->getOption().matches(options::OPT_l)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
// Rewrite unless -nostdlib is present.
if (!HasNostdlib && Value == "stdc++") {
@@ -285,48 +273,23 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
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(*Args);
- CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx,
- options::OPT_ccc_no_clang_cxx,
- CCCUseClangCXX);
+ CCCGenericGCCName = A->getValue();
CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch,
options::OPT_ccc_pch_is_pth);
- CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang);
- CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp);
- if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) {
- StringRef Cur = A->getValue(*Args);
-
- CCCClangArchs.clear();
- while (!Cur.empty()) {
- std::pair<StringRef, StringRef> Split = Cur.split(',');
-
- if (!Split.first.empty()) {
- llvm::Triple::ArchType Arch =
- llvm::Triple(Split.first, "", "").getArch();
-
- if (Arch == llvm::Triple::UnknownArch)
- Diag(clang::diag::err_drv_invalid_arch_name) << Split.first;
-
- CCCClangArchs.insert(Arch);
- }
-
- Cur = Split.second;
- }
- }
// FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
if (const Arg *A = Args->getLastArg(options::OPT_target))
- DefaultTargetTriple = A->getValue(*Args);
+ DefaultTargetTriple = A->getValue();
if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
- Dir = InstalledDir = A->getValue(*Args);
+ Dir = InstalledDir = A->getValue();
for (arg_iterator it = Args->filtered_begin(options::OPT_B),
ie = Args->filtered_end(); it != ie; ++it) {
const Arg *A = *it;
A->claim();
- PrefixDirs.push_back(A->getValue(*Args, 0));
+ PrefixDirs.push_back(A->getValue(0));
}
if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ))
- SysRoot = A->getValue(*Args);
+ SysRoot = A->getValue();
if (Args->hasArg(options::OPT_nostdlib))
UseStdLib = false;
@@ -399,11 +362,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
std::string Cmd;
llvm::raw_string_ostream OS(Cmd);
if (FailingCommand)
- C.PrintJob(OS, *FailingCommand, "\n", false);
+ C.PrintDiagnosticJob(OS, *FailingCommand);
else
// Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an
// associated FailingCommand, so just pass all jobs.
- C.PrintJob(OS, C.getJobs(), "\n", false);
+ C.PrintDiagnosticJob(OS, C.getJobs());
OS.flush();
// Clear stale state and suppress tool output.
@@ -418,7 +381,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
bool IgnoreInput = false;
// Ignore input from stdin or any inputs that cannot be preprocessed.
- if (!strcmp(it->second->getValue(C.getArgs()), "-")) {
+ if (!strcmp(it->second->getValue(), "-")) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s) - ignoring input from stdin"
".";
@@ -442,7 +405,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
it != ie; ++it) {
Arg *A = *it;
if (A->getOption().matches(options::OPT_arch)) {
- StringRef ArchName = A->getValue(C.getArgs());
+ StringRef ArchName = A->getValue();
ArchNames.insert(ArchName);
}
}
@@ -501,57 +464,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + Err;
} else {
- // Strip away options not necessary to reproduce the crash.
- // FIXME: This doesn't work with quotes (e.g., -D "foo bar").
- SmallVector<std::string, 16> Flag;
- Flag.push_back("-D ");
- Flag.push_back("-F");
- Flag.push_back("-I ");
- Flag.push_back("-M ");
- Flag.push_back("-MD ");
- Flag.push_back("-MF ");
- Flag.push_back("-MG ");
- Flag.push_back("-MM ");
- Flag.push_back("-MMD ");
- Flag.push_back("-MP ");
- Flag.push_back("-MQ ");
- Flag.push_back("-MT ");
- Flag.push_back("-o ");
- Flag.push_back("-coverage-file ");
- Flag.push_back("-dependency-file ");
- Flag.push_back("-fdebug-compilation-dir ");
- Flag.push_back("-fmodule-cache-path ");
- Flag.push_back("-idirafter ");
- Flag.push_back("-include ");
- Flag.push_back("-include-pch ");
- Flag.push_back("-internal-isystem ");
- Flag.push_back("-internal-externc-isystem ");
- Flag.push_back("-iprefix ");
- Flag.push_back("-iwithprefix ");
- Flag.push_back("-iwithprefixbefore ");
- Flag.push_back("-isysroot ");
- Flag.push_back("-isystem ");
- Flag.push_back("-iquote ");
- Flag.push_back("-resource-dir ");
- Flag.push_back("-serialize-diagnostic-file ");
- for (unsigned i = 0, e = Flag.size(); i < e; ++i) {
- size_t I = 0, E = 0;
- do {
- I = Cmd.find(Flag[i], I);
- if (I == std::string::npos) break;
-
- E = Cmd.find(" ", I + Flag[i].length());
- if (E == std::string::npos) break;
- // The -D option is not removed. Instead, the argument is quoted.
- if (Flag[i] != "-D ") {
- Cmd.erase(I, E - I + 1);
- } else {
- Cmd.insert(I+3, "\"");
- Cmd.insert(++E, "\"");
- I = E;
- }
- } while(1);
- }
// Append the new filename with correct preprocessed suffix.
size_t I, E;
I = Cmd.find("-main-file-name ");
@@ -639,12 +551,12 @@ void Driver::PrintOptions(const ArgList &Args) const {
it != ie; ++it, ++i) {
Arg *A = *it;
llvm::errs() << "Option " << i << " - "
- << "Name: \"" << A->getOption().getName() << "\", "
+ << "Name: \"" << A->getOption().getPrefixedName() << "\", "
<< "Values: {";
for (unsigned j = 0; j < A->getNumValues(); ++j) {
if (j)
llvm::errs() << ", ";
- llvm::errs() << '"' << A->getValue(Args, j) << '"';
+ llvm::errs() << '"' << A->getValue(j) << '"';
}
llvm::errs() << "}\n";
}
@@ -652,7 +564,9 @@ void Driver::PrintOptions(const ArgList &Args) const {
void Driver::PrintHelp(bool ShowHidden) const {
getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
- ShowHidden);
+ /*Include*/0,
+ /*Exclude*/options::NoDriverOption |
+ (ShowHidden ? 0 : options::HelpHidden));
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -750,12 +664,12 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
// FIXME: The following handlers should use a callback mechanism, we don't
// know what the client would like to do.
if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) {
- llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n";
+ llvm::outs() << GetFilePath(A->getValue(), TC) << "\n";
return false;
}
if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) {
- llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n";
+ llvm::outs() << GetProgramPath(A->getValue(), TC) << "\n";
return false;
}
@@ -818,7 +732,7 @@ static unsigned PrintActions1(const Compilation &C, Action *A,
os << Action::getClassName(A->getKind()) << ", ";
if (InputAction *IA = dyn_cast<InputAction>(A)) {
- os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\"";
+ os << "\"" << IA->getInputArg().getValue() << "\"";
} else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) {
os << '"' << BIA->getArchName() << '"'
<< ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}";
@@ -878,7 +792,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Validate the option here; we don't save the type here because its
// particular spelling may participate in other driver choices.
llvm::Triple::ArchType Arch =
- llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ tools::darwin::getArchTypeForDarwinArchName(A->getValue());
if (Arch == llvm::Triple::UnknownArch) {
Diag(clang::diag::err_drv_invalid_arch_name)
<< A->getAsString(Args);
@@ -886,15 +800,15 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
A->claim();
- if (ArchNames.insert(A->getValue(Args)))
- Archs.push_back(A->getValue(Args));
+ if (ArchNames.insert(A->getValue()))
+ Archs.push_back(A->getValue());
}
}
// When there is no explicit arch for this platform, make sure we still bind
// the architecture (to the default) so that -Xarch_ is handled correctly.
if (!Archs.size())
- Archs.push_back(Args.MakeArgString(TC.getArchName()));
+ Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName()));
// FIXME: We killed off some others but these aren't yet detected in a
// functional manner. If we added information to jobs about which "auxiliary"
@@ -981,8 +895,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
it != ie; ++it) {
Arg *A = *it;
- if (isa<InputOption>(A->getOption())) {
- const char *Value = A->getValue(Args);
+ if (A->getOption().getKind() == Option::InputClass) {
+ const char *Value = A->getValue();
types::ID Ty = types::TY_INVALID;
// Infer the input type if necessary.
@@ -1049,8 +963,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
if (CheckInputsExist && memcmp(Value, "-", 2) != 0) {
SmallString<64> Path(Value);
if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
- SmallString<64> Directory(WorkDir->getValue(Args));
- if (llvm::sys::path::is_absolute(Directory.str())) {
+ if (!llvm::sys::path::is_absolute(Path.str())) {
+ SmallString<64> Directory(WorkDir->getValue());
llvm::sys::path::append(Directory, Value);
Path.assign(Directory);
}
@@ -1064,21 +978,21 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
} else
Inputs.push_back(std::make_pair(Ty, A));
- } else if (A->getOption().isLinkerInput()) {
+ } else if (A->getOption().hasFlag(options::LinkerInput)) {
// Just treat as object type, we could make a special type for this if
// necessary.
Inputs.push_back(std::make_pair(types::TY_Object, A));
} else if (A->getOption().matches(options::OPT_x)) {
InputTypeArg = A;
- InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args));
+ InputType = types::lookupTypeForTypeSpecifier(A->getValue());
A->claim();
// Follow gcc behavior and treat as linker input for invalid -x
// options. Its not clear why we shouldn't just revert to unknown; but
// this isn't very important, we might as well be bug compatible.
if (!InputType) {
- Diag(clang::diag::err_drv_unknown_language) << A->getValue(Args);
+ Diag(clang::diag::err_drv_unknown_language) << A->getValue();
InputType = types::TY_Object;
}
}
@@ -1301,7 +1215,7 @@ void Driver::BuildJobs(Compilation &C) const {
const char *LinkingOutput = 0;
if (isa<LipoJobAction>(A)) {
if (FinalOutput)
- LinkingOutput = FinalOutput->getValue(C.getArgs());
+ LinkingOutput = FinalOutput->getValue();
else
LinkingOutput = DefaultImageName.c_str();
}
@@ -1331,13 +1245,13 @@ void Driver::BuildJobs(Compilation &C) const {
// DiagnosticsEngine, so that extra values, position, and so on could be
// printed.
if (!A->isClaimed()) {
- if (A->getOption().hasNoArgumentUnused())
+ if (A->getOption().hasFlag(options::NoArgumentUnused))
continue;
// Suppress the warning automatically if this is just a flag, and it is an
// instance of an argument we already claimed.
const Option &Opt = A->getOption();
- if (isa<FlagOption>(Opt)) {
+ if (Opt.getKind() == Option::FlagClass) {
bool DuplicateClaimed = false;
for (arg_iterator it = C.getArgs().filtered_begin(&Opt),
@@ -1392,6 +1306,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
!C.getArgs().hasArg(options::OPT_traditional_cpp) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
+ !C.getArgs().hasArg(options::OPT_rewrite_objc) &&
ToolForJob->hasIntegratedCPP())
Inputs = &(*Inputs)[0]->getInputs();
@@ -1413,7 +1328,7 @@ void Driver::BuildJobsForAction(Compilation &C,
const Arg &Input = IA->getInputArg();
Input.claim();
if (Input.getOption().matches(options::OPT_INPUT)) {
- const char *Name = Input.getValue(C.getArgs());
+ const char *Name = Input.getValue();
Result = InputInfo(Name, A->getType(), Name);
} else
Result = InputInfo(&Input, A->getType(), "");
@@ -1502,7 +1417,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
if (AtTopLevel && !isa<DsymutilJobAction>(JA) &&
!isa<VerifyJobAction>(JA)) {
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- return C.addResultFile(FinalOutput->getValue(C.getArgs()));
+ return C.addResultFile(FinalOutput->getValue());
}
// Default to writing to stdout?
@@ -1580,7 +1495,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
// Respect a limited subset of the '-Bprefix' functionality in GCC by
- // attempting to use this prefix when lokup up program paths.
+ // attempting to use this prefix when looking for file paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
std::string Dir(*it);
@@ -1619,26 +1534,26 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
return Name;
}
-static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) {
- bool Exists;
- return (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists
- : P.canExecute());
-}
-
-std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
- bool WantFile) const {
+std::string Driver::GetProgramPath(const char *Name,
+ const ToolChain &TC) const {
// FIXME: Needs a better variable than DefaultTargetTriple
std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name);
// Respect a limited subset of the '-Bprefix' functionality in GCC by
- // attempting to use this prefix when lokup up program paths.
+ // 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) {
- llvm::sys::Path P(*it);
- P.appendComponent(TargetSpecificExecutable);
- if (isPathExecutable(P, WantFile)) return P.str();
- P.eraseComponent();
- P.appendComponent(Name);
- if (isPathExecutable(P, WantFile)) return P.str();
+ 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();
+ } else {
+ llvm::sys::Path P(*it + Name);
+ if (P.canExecute()) return P.str();
+ }
}
const ToolChain::path_list &List = TC.getProgramPaths();
@@ -1646,10 +1561,10 @@ std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
it = List.begin(), ie = List.end(); it != ie; ++it) {
llvm::sys::Path P(*it);
P.appendComponent(TargetSpecificExecutable);
- if (isPathExecutable(P, WantFile)) return P.str();
+ if (P.canExecute()) return P.str();
P.eraseComponent();
P.appendComponent(Name);
- if (isPathExecutable(P, WantFile)) return P.str();
+ if (P.canExecute()) return P.str();
}
// If all else failed, search the path.
@@ -1701,7 +1616,7 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
StringRef DarwinArchName) {
// FIXME: Already done in Compilation *Driver::BuildCompilation
if (const Arg *A = Args.getLastArg(options::OPT_target))
- DefaultTargetTriple = A->getValue(Args);
+ DefaultTargetTriple = A->getValue();
llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple));
@@ -1710,14 +1625,14 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
// If an explict Darwin arch name is given, that trumps all.
if (!DarwinArchName.empty()) {
Target.setArch(
- llvm::Triple::getArchTypeForDarwinArchName(DarwinArchName));
+ tools::darwin::getArchTypeForDarwinArchName(DarwinArchName));
return Target;
}
// Handle the Darwin '-arch' flag.
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
llvm::Triple::ArchType DarwinArch
- = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ = tools::darwin::getArchTypeForDarwinArchName(A->getValue());
if (DarwinArch != llvm::Triple::UnknownArch)
Target.setArch(DarwinArch);
}
@@ -1820,37 +1735,14 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
const llvm::Triple &Triple) const {
// Check if user requested no clang, or clang doesn't understand this type (we
// only handle single inputs for now).
- if (!CCCUseClang || JA.size() != 1 ||
+ if (JA.size() != 1 ||
!types::isAcceptedByClang((*JA.begin())->getType()))
return false;
// Otherwise make sure this is an action clang understands.
- if (isa<PreprocessJobAction>(JA)) {
- if (!CCCUseClangCPP) {
- Diag(clang::diag::warn_drv_not_using_clang_cpp);
- return false;
- }
- } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA))
- return false;
-
- // Use clang for C++?
- if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) {
- Diag(clang::diag::warn_drv_not_using_clang_cxx);
+ if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
+ !isa<CompileJobAction>(JA))
return false;
- }
-
- // Always use clang for precompiling, AST generation, and rewriting,
- // regardless of archs.
- if (isa<PrecompileJobAction>(JA) ||
- types::isOnlyAcceptedByClang(JA.getType()))
- return true;
-
- // Finally, don't use clang if this isn't one of the user specified archs to
- // build.
- if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) {
- Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName();
- return false;
- }
return true;
}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 715819d04b26..3925b8aa35c5 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -14,11 +14,19 @@
using namespace clang::driver;
using namespace clang::driver::options;
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR)
+#include "clang/Driver/Options.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info InfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/Options.inc"
};
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index a3e38b26f20f..6e7b6951fb83 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -11,6 +11,7 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
+#include "clang/Driver/Options.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
@@ -54,6 +55,13 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
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)) &&
@@ -78,23 +86,24 @@ OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
//
OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
- : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos),
- Options(new Option*[NumOptionInfos]),
- TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0)
+ : 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.
- memset(Options, 0, sizeof(*Options) * NumOptionInfos);
// 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(!TheInputOption && "Cannot have multiple input options!");
- TheInputOption = getOption(i + 1);
+ assert(!TheInputOptionID && "Cannot have multiple input options!");
+ TheInputOptionID = getInfo(i + 1).ID;
} else if (Kind == Option::UnknownClass) {
- assert(!TheUnknownOption && "Cannot have multiple input options!");
- TheUnknownOption = getOption(i + 1);
+ assert(!TheUnknownOptionID && "Cannot have multiple unknown options!");
+ TheUnknownOptionID = getInfo(i + 1).ID;
} else if (Kind != Option::GroupClass) {
FirstSearchableIndex = i;
break;
@@ -115,91 +124,80 @@ OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
// 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();
+ 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() {
- for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
- delete Options[i];
- delete[] Options;
}
-Option *OptTable::CreateOption(unsigned id) const {
- const Info &info = getInfo(id);
- const OptionGroup *Group =
- cast_or_null<OptionGroup>(getOption(info.GroupID));
- const Option *Alias = getOption(info.AliasID);
-
- Option *Opt = 0;
- switch (info.Kind) {
- case Option::InputClass:
- Opt = new InputOption(id); break;
- case Option::UnknownClass:
- Opt = new UnknownOption(id); break;
- case Option::GroupClass:
- Opt = new OptionGroup(id, info.Name, Group); break;
- case Option::FlagClass:
- Opt = new FlagOption(id, info.Name, Group, Alias); break;
- case Option::JoinedClass:
- Opt = new JoinedOption(id, info.Name, Group, Alias); break;
- case Option::SeparateClass:
- Opt = new SeparateOption(id, info.Name, Group, Alias); break;
- case Option::CommaJoinedClass:
- Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
- case Option::MultiArgClass:
- Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
- case Option::JoinedOrSeparateClass:
- Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
- case Option::JoinedAndSeparateClass:
- Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
- }
+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);
+}
- if (info.Flags & DriverOption)
- Opt->setDriverOption(true);
- if (info.Flags & LinkerInput)
- Opt->setLinkerInput(true);
- if (info.Flags & NoArgumentUnused)
- Opt->setNoArgumentUnused(true);
- if (info.Flags & NoForward)
- Opt->setNoForward(true);
- if (info.Flags & RenderAsInput)
- Opt->setNoOptAsInput(true);
- if (info.Flags & RenderJoined) {
- assert((info.Kind == Option::JoinedOrSeparateClass ||
- info.Kind == Option::SeparateClass) && "Invalid option.");
- Opt->setRenderStyle(Option::RenderJoinedStyle);
- }
- if (info.Flags & RenderSeparate) {
- assert((info.Kind == Option::JoinedOrSeparateClass ||
- info.Kind == Option::JoinedClass) && "Invalid option.");
- Opt->setRenderStyle(Option::RenderSeparateStyle);
- }
- if (info.Flags & Unsupported)
- Opt->setUnsupported(true);
- if (info.Flags & CC1Option)
- Opt->setIsCC1Option(true);
+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;
+}
- return Opt;
+/// \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 '-' is an input, as is '-' itself.
- if (Str[0] != '-' || Str[1] == '\0')
- return new Arg(TheInputOption, Index++, Str);
+ // 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, Str);
+ 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
@@ -210,15 +208,16 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
// 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 (memcmp(Str, Start->Name, strlen(Start->Name)) == 0)
+ if ((ArgSize = matchOption(Start, Str)))
break;
if (Start == End)
break;
// See if this option matches.
- if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index))
+ if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
return A;
// Otherwise, see if this argument was missing values.
@@ -226,7 +225,7 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
return 0;
}
- return new Arg(TheUnknownOption, Index++, Str);
+ return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
}
InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
@@ -266,10 +265,11 @@ InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
}
static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
- std::string Name = Opts.getOptionName(Id);
+ const Option O = Opts.getOption(Id);
+ std::string Name = O.getPrefixedName();
// Add metavar, if used.
- switch (Opts.getOptionKind(Id)) {
+ switch (O.getKind()) {
case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
llvm_unreachable("Invalid option with help text.");
@@ -346,7 +346,8 @@ static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
}
void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
- const char *Title, bool ShowHidden) const {
+ const char *Title, unsigned short FlagsToInclude,
+ unsigned short FlagsToExclude) const {
OS << "OVERVIEW: " << Title << "\n";
OS << '\n';
OS << "USAGE: " << Name << " [options] <inputs>\n";
@@ -365,7 +366,8 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
if (getOptionKind(Id) == Option::GroupClass)
continue;
- if (!ShowHidden && isOptionHelpHidden(Id))
+ if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) ||
+ getInfo(Id).Flags & FlagsToExclude)
continue;
if (const char *Text = getOptionHelpText(Id)) {
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index 03360ea2d89a..9a34df59036a 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -13,46 +13,20 @@
#include "clang/Driver/ArgList.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/Twine.h"
#include <cassert>
#include <algorithm>
using namespace clang::driver;
-Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name,
- const OptionGroup *_Group, const Option *_Alias)
- : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias),
- Unsupported(false), LinkerInput(false), NoOptAsInput(false),
- DriverOption(false), NoArgumentUnused(false), NoForward(false) {
+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((!Alias || (!Alias->Alias && !Group)) &&
+ assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
+ !getGroup().isValid())) &&
"Multi-level aliases and aliases with groups are unsupported.");
-
- // Initialize rendering options based on the class.
- switch (Kind) {
- case GroupClass:
- case InputClass:
- case UnknownClass:
- RenderStyle = RenderValuesStyle;
- break;
-
- case JoinedClass:
- case JoinedAndSeparateClass:
- RenderStyle = RenderJoinedStyle;
- break;
-
- case CommaJoinedClass:
- RenderStyle = RenderCommaJoinedStyle;
- break;
-
- case FlagClass:
- case SeparateClass:
- case MultiArgClass:
- case JoinedOrSeparateClass:
- RenderStyle = RenderSeparateStyle;
- break;
- }
}
Option::~Option() {
@@ -60,7 +34,7 @@ Option::~Option() {
void Option::dump() const {
llvm::errs() << "<";
- switch (Kind) {
+ switch (getKind()) {
#define P(N) case N: llvm::errs() << #N; break
P(GroupClass);
P(InputClass);
@@ -75,206 +49,153 @@ void Option::dump() const {
#undef P
}
- llvm::errs() << " Name:\"" << Name << '"';
+ llvm::errs() << " Prefixes:[";
+ for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
+ llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
+ }
+ llvm::errs() << ']';
- if (Group) {
+ llvm::errs() << " Name:\"" << getName() << '"';
+
+ const Option Group = getGroup();
+ if (Group.isValid()) {
llvm::errs() << " Group:";
- Group->dump();
+ Group.dump();
}
- if (Alias) {
+ const Option Alias = getAlias();
+ if (Alias.isValid()) {
llvm::errs() << " Alias:";
- Alias->dump();
+ Alias.dump();
}
- if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this))
- llvm::errs() << " NumArgs:" << MOA->getNumArgs();
+ 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.
- if (Alias)
- return Alias->matches(Opt);
+ const Option Alias = getAlias();
+ if (Alias.isValid())
+ return Alias.matches(Opt);
// Check exact match.
- if (ID == Opt)
+ if (getID() == Opt.getID())
return true;
- if (Group)
- return Group->matches(Opt);
+ const Option Group = getGroup();
+ if (Group.isValid())
+ return Group.matches(Opt);
return false;
}
-OptionGroup::OptionGroup(OptSpecifier ID, const char *Name,
- const OptionGroup *Group)
- : Option(Option::GroupClass, ID, Name, Group, 0) {
-}
-
-Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an OptionGroup");
-}
-
-InputOption::InputOption(OptSpecifier ID)
- : Option(Option::InputClass, ID, "<input>", 0, 0) {
-}
-
-Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an InputOption");
-}
-
-UnknownOption::UnknownOption(OptSpecifier ID)
- : Option(Option::UnknownClass, ID, "<unknown>", 0, 0) {
-}
-
-Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const {
- llvm_unreachable("accept() should never be called on an UnknownOption");
-}
-
-FlagOption::FlagOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::FlagClass, ID, Name, Group, Alias) {
-}
-
-Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- return new Arg(getUnaliasedOption(), Index++);
-}
-
-JoinedOption::JoinedOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::JoinedClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const {
- // Always matches.
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(getUnaliasedOption(), Index++, Value);
-}
-
-CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) {
-}
-
-Arg *CommaJoinedOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // Always matches.
- const char *Str = Args.getArgString(Index) + getName().size();
- Arg *A = new Arg(getUnaliasedOption(), Index++);
+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()));
+ }
- // Parse out the comma separated values.
- const char *Prev = Str;
- for (;; ++Str) {
- char c = *Str;
+ switch (getKind()) {
+ case FlagClass:
+ if (ArgSize != strlen(Args.getArgString(Index)))
+ return 0;
- 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);
+ 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;
}
-
- if (!c)
- break;
-
- Prev = Str + 1;
}
- }
- A->setOwnsValues(true);
-
- return A;
-}
-
-SeparateOption::SeparateOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias)
- : Option(Option::SeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
-
- return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
-}
-
-MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name,
- const OptionGroup *Group, const Option *Alias,
- unsigned _NumArgs)
- : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) {
- assert(NumArgs > 1 && "Invalid MultiArgOption!");
-}
-
-Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const {
- // Matches iff this is an exact match.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
- return 0;
-
- Index += 1 + NumArgs;
- if (Index > Args.getNumInputArgStrings())
- return 0;
+ A->setOwnsValues(true);
- Arg *A = new Arg(getUnaliasedOption(), Index - 1 - NumArgs,
- Args.getArgString(Index - NumArgs));
- for (unsigned i = 1; i != NumArgs; ++i)
- A->getValues().push_back(Args.getArgString(Index - NumArgs + i));
- return A;
-}
-
-JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID,
- const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedOrSeparateOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // If this is not an exact match, it is a joined arg.
- // FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index))) {
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(this, Index++, Value);
+ 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(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1));
-}
-
-JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID,
- const char *Name,
- const OptionGroup *Group,
- const Option *Alias)
- : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) {
-}
-
-Arg *JoinedAndSeparateOption::accept(const ArgList &Args,
- unsigned &Index) const {
- // Always matches.
-
- Index += 2;
- if (Index > Args.getNumInputArgStrings())
- return 0;
+ // Otherwise it must be separate.
+ Index += 2;
+ if (Index > Args.getNumInputArgStrings())
+ return 0;
- return new Arg(getUnaliasedOption(), Index - 2,
- Args.getArgString(Index-2)+getName().size(),
- Args.getArgString(Index-1));
+ 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.h b/lib/Driver/SanitizerArgs.h
new file mode 100644
index 000000000000..ecb396ea06cf
--- /dev/null
+++ b/lib/Driver/SanitizerArgs.h
@@ -0,0 +1,106 @@
+//===--- 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/ArgList.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,
+ NeedsUbsanRt = Undefined
+ };
+ unsigned Kind;
+
+ public:
+ SanitizerArgs() : Kind(0) {}
+ /// Parses the sanitizer arguments from an argument list.
+ SanitizerArgs(const Driver &D, const ArgList &Args);
+
+ bool needsAsanRt() const { return Kind & NeedsAsanRt; }
+ bool needsTsanRt() const { return Kind & NeedsTsanRt; }
+ bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
+
+ bool sanitizesVptr() const { return Kind & Vptr; }
+
+ void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+ if (!Kind)
+ return;
+ llvm::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));
+ }
+
+ private:
+ /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
+ /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value
+ /// is not known.
+ static unsigned parse(const char *Value) {
+ return 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());
+ }
+
+ /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+ /// invalid components.
+ static unsigned parse(const Driver &D, const Arg *A) {
+ unsigned Kind = 0;
+ for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
+ if (unsigned K = parse(A->getValue(I)))
+ Kind |= K;
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue(I);
+ }
+ return 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 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");
+ }
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 48ed044c8f5c..de8ed1d1c5e7 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -14,6 +14,7 @@
#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 "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -32,13 +33,32 @@ const Driver &ToolChain::getDriver() const {
return D;
}
+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
+ // an inverse of the darwin::getArchTypeForDarwinArchName() function, but the
+ // only interesting special case is powerpc.
+ switch (Triple.getArch()) {
+ case llvm::Triple::ppc:
+ return "ppc";
+ case llvm::Triple::ppc64:
+ return "ppc64";
+ default:
+ return Triple.getArchName();
+ }
+}
+
+bool ToolChain::IsUnwindTablesDefault() const {
+ return false;
+}
+
std::string ToolChain::GetFilePath(const char *Name) const {
return D.GetFilePath(Name, *this);
}
-std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const {
- return D.GetProgramPath(Name, *this, WantFile);
+std::string ToolChain::GetProgramPath(const char *Name) const {
+ return D.GetProgramPath(Name, *this);
}
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
@@ -66,13 +86,13 @@ static const char *getARMTargetCPU(const ArgList &Args,
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue(Args);
+ return A->getValue();
}
StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue(Args);
+ MArch = A->getValue();
} else {
// Otherwise, use the Arch from the triple.
MArch = Triple.getArchName();
@@ -91,6 +111,8 @@ static const char *getARMTargetCPU(const ArgList &Args,
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7f", "armv7-f", "cortex-a9-mp")
+ .Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
.Case("ep9312", "ep9312")
@@ -119,10 +141,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "v7")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7m")
.Case("cortex-m0", "v6m")
+ .Case("cortex-a9-mp", "v7f")
+ .Case("swift", "v7s")
.Default("");
}
@@ -142,7 +166,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault = (Suffix == "v7" && getTriple().isOSDarwin());
+ bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin());
std::string ArchName = "arm";
// Assembly files should start in ARM mode.
@@ -180,7 +204,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
const ArgList &Args) const
{
if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
if (Value == "compiler-rt")
return ToolChain::RLT_CompilerRT;
if (Value == "libgcc")
@@ -194,7 +218,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
- StringRef Value = A->getValue(Args);
+ StringRef Value = A->getValue();
if (Value == "libc++")
return ToolChain::CST_Libcxx;
if (Value == "libstdc++")
@@ -273,3 +297,24 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-lcc_kext");
}
+
+bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Check if -ffast-math or -funsafe-math is enabled.
+ Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations);
+
+ if (!A || A->getOption().getID() == options::OPT_fno_fast_math ||
+ A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations)
+ return false;
+
+ // If crtfastmath.o exists add it to the arguments.
+ std::string Path = GetFilePath("crtfastmath.o");
+ if (Path == "crtfastmath.o") // Not found.
+ return false;
+
+ CmdArgs.push_back(Args.MakeArgString(Path));
+ return true;
+}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 01c66239a121..a2ccb35ed264 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -31,6 +31,8 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
+#include "SanitizerArgs.h"
+
#include <cstdlib> // ::getenv
#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
@@ -80,17 +82,11 @@ bool Darwin::HasNativeLLVMSupport() const {
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
- if (isTargetIPhoneOS()) {
+ if (isTargetIPhoneOS())
return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
- } else if (TargetSimulatorVersionFromDefines != VersionTuple()) {
- return ObjCRuntime(ObjCRuntime::iOS, TargetSimulatorVersionFromDefines);
- } else {
- if (isNonFragile) {
- return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
- } else {
- return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
- }
- }
+ if (isNonFragile)
+ return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
+ return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
}
/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
@@ -111,6 +107,9 @@ static const char *GetArmArchForMArch(StringRef Value) {
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
.Cases("armv7m", "armv7-m", "armv7")
+ .Cases("armv7f", "armv7-f", "armv7f")
+ .Cases("armv7k", "armv7-k", "armv7k")
+ .Cases("armv7s", "armv7-s", "armv7s")
.Default(0);
}
@@ -122,7 +121,10 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Case("xscale", "xscale")
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s",
"arm1176jzf-s", "cortex-m0", "armv6")
- .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7")
+ .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15",
+ "armv7")
+ .Case("cortex-a9-mp", "armv7f")
+ .Case("swift", "armv7s")
.Default(0);
}
@@ -134,11 +136,11 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
case llvm::Triple::thumb:
case llvm::Triple::arm: {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- if (const char *Arch = GetArmArchForMArch(A->getValue(Args)))
+ if (const char *Arch = GetArmArchForMArch(A->getValue()))
return Arch;
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- if (const char *Arch = GetArmArchForMCpu(A->getValue(Args)))
+ if (const char *Arch = GetArmArchForMCpu(A->getValue()))
return Arch;
return "arm";
@@ -175,24 +177,11 @@ void Generic_ELF::anchor() {}
Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key = JA.getKind();
- bool useClang = false;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) {
- useClang = true;
- // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI.
- if (!getDriver().shouldForceClangUse() &&
- Inputs.size() == 1 &&
- types::isCXX(Inputs[0]->getType()) &&
- getTriple().isOSDarwin() &&
- getTriple().getArch() == llvm::Triple::x86 &&
- (C.getArgs().getLastArg(options::OPT_fapple_kext) ||
- C.getArgs().getLastArg(options::OPT_mkernel)))
- useClang = false;
- }
-
- // FIXME: This seems like a hacky way to choose clang frontend.
- if (useClang)
+ // FIXME: This seems like a hacky way to choose clang frontend.
Key = Action::AnalyzeJobClass;
+ }
bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
@@ -245,30 +234,6 @@ DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple)
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
-
- // For fallback, we need to know how to find the GCC cc1 executables, so we
- // also add the GCC libexec paths. This is legacy code that can be removed
- // once fallback is no longer useful.
- AddGCCLibexecPath(DarwinVersion[0]);
- AddGCCLibexecPath(DarwinVersion[0] - 2);
- AddGCCLibexecPath(DarwinVersion[0] - 1);
- AddGCCLibexecPath(DarwinVersion[0] + 1);
- AddGCCLibexecPath(DarwinVersion[0] + 2);
-}
-
-void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) {
- std::string ToolChainDir = "i686-apple-darwin";
- ToolChainDir += llvm::utostr(darwinVersion);
- ToolChainDir += "/4.2.1";
-
- std::string Path = getDriver().Dir;
- Path += "/../llvm-gcc-4.2/libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
-
- Path = "/usr/llvm-gcc-4.2/libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
}
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
@@ -287,9 +252,6 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
s += "iphonesimulator";
else if (isTargetIPhoneOS())
s += "iphoneos";
- // FIXME: Remove this once we depend fully on -mios-simulator-version-min.
- else if (TargetSimulatorVersionFromDefines != VersionTuple())
- s += "iphonesimulator";
else
s += "macosx";
s += ".a";
@@ -320,13 +282,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
break;
default:
getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Args.getLastArg(options::OPT_rtlib_EQ)->getValue(Args) << "darwin";
+ << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "darwin";
return;
}
// Darwin doesn't support real static executables, don't link any runtime
// libraries with -static.
- if (Args.hasArg(options::OPT_static))
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext) ||
+ Args.hasArg(options::OPT_mkernel))
return;
// Reject -static-libgcc for now, we can deal with this when and if someone
@@ -351,15 +315,16 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
+ SanitizerArgs Sanitize(getDriver(), Args);
+
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false)) {
+ if (Sanitize.needsAsanRt()) {
if (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) return;
if (isTargetIPhoneOS()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
- << "-faddress-sanitizer";
+ << "-fsanitize=address";
} else {
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a");
@@ -410,67 +375,28 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
-static inline StringRef SimulatorVersionDefineName() {
- return "__IPHONE_OS_VERSION_MIN_REQUIRED";
-}
-
-/// \brief Parse the simulator version define:
-/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
-// and return the grouped values as integers, e.g:
-// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
-// will return Major=4, Minor=2, Micro=1.
-static bool GetVersionFromSimulatorDefine(StringRef define,
- unsigned &Major, unsigned &Minor,
- unsigned &Micro) {
- assert(define.startswith(SimulatorVersionDefineName()));
- StringRef name, version;
- llvm::tie(name, version) = define.split('=');
- if (version.empty())
- return false;
- std::string verstr = version.str();
- char *end;
- unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
- if (*end != '\0')
- return false;
- Major = num / 10000;
- num = num % 10000;
- Minor = num / 100;
- Micro = num % 100;
- return true;
-}
-
void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const OptTable &Opts = getDriver().getOpts();
+ // Support allowing the SDKROOT environment variable used by xcrun and other
+ // Xcode tools to define the default sysroot, by making it the default for
+ // isysroot.
+ if (!Args.hasArg(options::OPT_isysroot)) {
+ if (char *env = ::getenv("SDKROOT")) {
+ // We only use this value as the default if it is an absolute path and
+ // exists.
+ if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env)) {
+ Args.append(Args.MakeSeparateArg(
+ 0, Opts.getOption(options::OPT_isysroot), env));
+ }
+ }
+ }
+
Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
Arg *iOSSimVersion = Args.getLastArg(
options::OPT_mios_simulator_version_min_EQ);
- // FIXME: HACK! When compiling for the simulator we don't get a
- // '-miphoneos-version-min' to help us know whether there is an ARC runtime
- // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
- // define passed in command-line.
- if (!iOSVersion && !iOSSimVersion) {
- for (arg_iterator it = Args.filtered_begin(options::OPT_D),
- ie = Args.filtered_end(); it != ie; ++it) {
- StringRef define = (*it)->getValue(Args);
- if (define.startswith(SimulatorVersionDefineName())) {
- unsigned Major = 0, Minor = 0, Micro = 0;
- if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
- Major < 10 && Minor < 100 && Micro < 100) {
- TargetSimulatorVersionFromDefines = VersionTuple(Major, Minor, Micro);
- }
- // When using the define to indicate the simulator, we force
- // 10.6 macosx target.
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- OSXVersion = Args.MakeJoinedArg(0, O, "10.6");
- Args.append(OSXVersion);
- break;
- }
- }
- }
-
if (OSXVersion && (iOSVersion || iOSSimVersion)) {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
@@ -500,7 +426,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (iOSTarget.empty()) {
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef first, second;
- StringRef isysroot = A->getValue(Args);
+ StringRef isysroot = A->getValue();
llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS"));
if (second != "")
iOSTarget = second.substr(0,3);
@@ -510,7 +436,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// If no OSX or iOS target has been specified and we're compiling for armv7,
// go ahead as assume we're targeting iOS.
if (OSXTarget.empty() && iOSTarget.empty() &&
- getDarwinArchName(Args) == "armv7")
+ (getDarwinArchName(Args) == "armv7" ||
+ getDarwinArchName(Args) == "armv7s"))
iOSTarget = iOSVersionMin;
// Handle conflicting deployment targets
@@ -536,21 +463,21 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
if (!OSXTarget.empty()) {
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget);
Args.append(OSXVersion);
} else if (!iOSTarget.empty()) {
- const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget);
Args.append(iOSVersion);
} else if (!iOSSimTarget.empty()) {
- const Option *O = Opts.getOption(
+ const Option O = Opts.getOption(
options::OPT_mios_simulator_version_min_EQ);
iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget);
Args.append(iOSSimVersion);
} else {
// Otherwise, assume we are targeting OS X.
- const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin);
Args.append(OSXVersion);
}
@@ -568,7 +495,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
bool HadExtra;
if (OSXVersion) {
assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
+ if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major != 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
@@ -576,7 +503,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
} else {
const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
assert(Version && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
+ if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major >= 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
@@ -614,7 +541,7 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
// Check in the sysroot first.
bool Exists;
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- llvm::sys::Path P(A->getValue(Args));
+ llvm::sys::Path P(A->getValue());
P.appendComponent("usr");
P.appendComponent("lib");
P.appendComponent("libstdc++.dylib");
@@ -655,7 +582,14 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
llvm::sys::Path P(getDriver().ResourceDir);
P.appendComponent("lib");
P.appendComponent("darwin");
- P.appendComponent("libclang_rt.cc_kext.a");
+
+ // Use the newer cc_kext for iOS ARM after 6.0.
+ if (!isTargetIPhoneOS() || isTargetIOSSimulator() ||
+ !isIPhoneOSVersionLT(6, 0)) {
+ P.appendComponent("libclang_rt.cc_kext.a");
+ } else {
+ P.appendComponent("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.
@@ -683,15 +617,15 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches either the toolchain
// triple arch, or the arch being bound.
- //
- // FIXME: Canonicalize name.
- StringRef XarchArch = A->getValue(Args, 0);
- if (!(XarchArch == getArchName() ||
- (BoundArch && XarchArch == BoundArch)))
+ llvm::Triple::ArchType XarchArch =
+ tools::darwin::getArchTypeForDarwinArchName(A->getValue(0));
+ if (!(XarchArch == getArch() ||
+ (BoundArch && XarchArch ==
+ tools::darwin::getArchTypeForDarwinArchName(BoundArch))))
continue;
Arg *OriginalArg = A;
- unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1));
+ unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
unsigned Prev = Index;
Arg *XarchArg = Opts.ParseOneArg(Args, Index);
@@ -707,7 +641,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
<< A->getAsString(Args);
continue;
- } else if (XarchArg->getOption().isDriverOption()) {
+ } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
<< A->getAsString(Args);
continue;
@@ -721,12 +655,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// Linker input arguments require custom handling. The problem is that we
// have already constructed the phase actions, so we can not treat them as
// "input arguments".
- if (A->getOption().isLinkerInput()) {
+ if (A->getOption().hasFlag(options::LinkerInput)) {
// Convert the argument into individual Zlinker_input_args.
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
DAL->AddSeparateArg(OriginalArg,
Opts.getOption(options::OPT_Zlinker_input),
- A->getValue(Args, i));
+ A->getValue(i));
}
continue;
@@ -749,7 +683,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
case options::OPT_dependency_file:
DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF),
- A->getValue(Args));
+ A->getValue());
break;
case options::OPT_gfull:
@@ -805,8 +739,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// how the driver driver works.
if (BoundArch) {
StringRef Name = BoundArch;
- const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ);
- const Option *MArch = Opts.getOption(options::OPT_march_EQ);
+ const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
+ const Option MArch = Opts.getOption(options::OPT_march_EQ);
// This code must be kept in sync with LLVM's getArchTypeForDarwinArch,
// which defines the list of which architectures we accept.
@@ -864,6 +798,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddJoinedArg(0, MArch, "armv6k");
else if (Name == "armv7")
DAL->AddJoinedArg(0, MArch, "armv7a");
+ else if (Name == "armv7f")
+ DAL->AddJoinedArg(0, MArch, "armv7f");
+ else if (Name == "armv7k")
+ DAL->AddJoinedArg(0, MArch, "armv7k");
+ else if (Name == "armv7s")
+ DAL->AddJoinedArg(0, MArch, "armv7s");
else
llvm_unreachable("invalid Darwin arch");
@@ -875,6 +815,25 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (BoundArch)
AddDeploymentTarget(*DAL);
+ // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext.
+ // FIXME: It would be far better to avoid inserting those -static arguments,
+ // but we can't check the deployment target in the translation code until
+ // it is set here.
+ if (isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) {
+ for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
+ Arg *A = *it;
+ ++it;
+ if (A->getOption().getID() != options::OPT_mkernel &&
+ A->getOption().getID() != options::OPT_fapple_kext)
+ continue;
+ assert(it != ie && "unexpected argument translation");
+ A = *it;
+ assert(A->getOption().getID() == options::OPT_static &&
+ "missing expected -static argument");
+ it = DAL->getArgs().erase(it);
+ }
+ }
+
// Validate the C++ standard library choice.
CXXStdlibType Type = GetCXXStdlibType(*DAL);
if (Type == ToolChain::CST_Libcxx) {
@@ -882,13 +841,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
StringRef where;
// Complain about targetting iOS < 5.0 in any way.
- if (TargetSimulatorVersionFromDefines != VersionTuple()) {
- if (TargetSimulatorVersionFromDefines < VersionTuple(5, 0))
- where = "iOS 5.0";
- } else if (isTargetIPhoneOS()) {
- if (isIPhoneOSVersionLT(5, 0))
- where = "iOS 5.0";
- }
+ if (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))
+ where = "iOS 5.0";
if (where != StringRef()) {
getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment)
@@ -900,9 +854,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
}
bool Darwin::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
bool Darwin::UseDwarfDebugFlags() const {
@@ -917,19 +869,17 @@ bool Darwin::UseSjLjExceptions() const {
getTriple().getArch() == llvm::Triple::thumb);
}
-const char *Darwin::GetDefaultRelocationModel() const {
- return "pic";
+bool Darwin::isPICDefault() const {
+ return true;
}
-const char *Darwin::GetForcedPicModel() const {
- if (getArchName() == "x86_64")
- return "pic";
- return 0;
+bool Darwin::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
}
bool Darwin::SupportsProfiling() const {
// Profiling instrumentation is only supported on x86.
- return getArchName() == "i386" || getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
}
bool Darwin::SupportsObjCGC() const {
@@ -937,8 +887,10 @@ bool Darwin::SupportsObjCGC() const {
return !isTargetIPhoneOS();
}
-bool Darwin::SupportsObjCARC() const {
- return isTargetIPhoneOS() || !isMacosxVersionLT(10, 6);
+void Darwin::CheckObjCARC() const {
+ if (isTargetIPhoneOS() || !isMacosxVersionLT(10, 6))
+ return;
+ getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
}
std::string
@@ -1013,7 +965,7 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
static StringRef getGCCToolchainDir(const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain);
if (A)
- return A->getValue(Args);
+ return A->getValue();
return GCC_INSTALL_PREFIX;
}
@@ -1072,7 +1024,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
if (!llvm::sys::fs::exists(LibDir))
continue;
for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
- ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]);
+ ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
+ CandidateTripleAliases[k]);
}
for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
const std::string LibDir
@@ -1081,7 +1034,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
continue;
for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
++k)
- ScanLibDirForGCCTriple(TargetArch, LibDir,
+ ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
CandidateMultiarchTripleAliases[k],
/*NeedsMultiarchSuffix=*/true);
}
@@ -1136,7 +1089,10 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
static const char *const MIPSLibDirs[] = { "/lib" };
static const char *const MIPSTriples[] = { "mips-linux-gnu" };
static const char *const MIPSELLibDirs[] = { "/lib" };
- static const char *const MIPSELTriples[] = { "mipsel-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" };
@@ -1264,8 +1220,32 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
MultiarchTripleAliases.push_back(MultiarchTriple.str());
}
+// 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 StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch,
+ const ArgList &Args) {
+ if (TargetArch == llvm::Triple::x86_64 ||
+ TargetArch == llvm::Triple::ppc64)
+ return "/64";
+
+ if (TargetArch == llvm::Triple::mips64 ||
+ TargetArch == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ return "/n32";
+ else
+ return "/64";
+ }
+
+ return "/32";
+}
+
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
- llvm::Triple::ArchType TargetArch, const std::string &LibDir,
+ llvm::Triple::ArchType TargetArch, const ArgList &Args,
+ const std::string &LibDir,
StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
// There are various different suffixes involving the triple we
// check for. We also record what is necessary to walk from each back
@@ -1274,6 +1254,10 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
"/gcc/" + CandidateTriple.str(),
"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
+ // The Freescale PPC SDK has the gcc libraries in
+ // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well.
+ "/" + CandidateTriple.str(),
+
// Ubuntu has a strange mis-matched pair of triples that this happens to
// match.
// FIXME: It may be worthwhile to generalize this and look for a second
@@ -1283,6 +1267,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
const std::string InstallSuffixes[] = {
"/../../..",
"/../../../..",
+ "/../..",
"/../../../.."
};
// Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
@@ -1307,11 +1292,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
// *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
// crtbegin.o without the subdirectory.
- StringRef MultiarchSuffix
- = (TargetArch == llvm::Triple::x86_64 ||
- TargetArch == llvm::Triple::ppc64 ||
- TargetArch == llvm::Triple::mips64 ||
- TargetArch == llvm::Triple::mips64el) ? "/64" : "/32";
+ StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args);
if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) {
GCCMultiarchSuffix = MultiarchSuffix.str();
} else {
@@ -1392,18 +1373,17 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
}
bool Generic_GCC::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Generic_GCC::GetDefaultRelocationModel() const {
- return "static";
+bool Generic_GCC::isPICDefault() const {
+ return false;
}
-const char *Generic_GCC::GetForcedPicModel() const {
- return 0;
+bool Generic_GCC::isPICDefaultForced() const {
+ return false;
}
+
/// Hexagon Toolchain
Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple)
@@ -1457,21 +1437,14 @@ Tool &Hexagon_TC::SelectTool(const Compilation &C,
return *T;
}
-bool Hexagon_TC::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+bool Hexagon_TC::isPICDefault() const {
+ return false;
}
-const char *Hexagon_TC::GetDefaultRelocationModel() const {
- return "static";
+bool Hexagon_TC::isPICDefaultForced() const {
+ return false;
}
-const char *Hexagon_TC::GetForcedPicModel() const {
- return 0;
-} // End Hexagon
-
-
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
/// Currently does not support anything else but compilation.
@@ -1495,16 +1468,12 @@ bool TCEToolChain::IsMathErrnoDefault() const {
return true;
}
-bool TCEToolChain::IsUnwindTablesDefault() const {
+bool TCEToolChain::isPICDefault() const {
return false;
}
-const char *TCEToolChain::GetDefaultRelocationModel() const {
- return "static";
-}
-
-const char *TCEToolChain::GetForcedPicModel() const {
- return 0;
+bool TCEToolChain::isPICDefaultForced() const {
+ return false;
}
Tool &TCEToolChain::SelectTool(const Compilation &C,
@@ -1613,19 +1582,43 @@ void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
- std::string Triple = getTriple().str();
- if (Triple.substr(0, 5) == "amd64")
- Triple.replace(0, 5, "x86_64");
-
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2");
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/backward");
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/" + Triple);
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++");
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/backward");
+ StringRef Triple = getTriple().str();
+ if (Triple.startswith("amd64"))
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/x86_64" +
+ Triple.substr(5));
+ else
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/stdc++/" +
+ Triple);
+ break;
+ }
}
void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-lstdc++");
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lcxxrt");
+ // Include supc++ to provide Unwind until provided by libcxx.
+ CmdArgs.push_back("-lgcc");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lstdc++");
+ break;
+ }
}
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
@@ -2020,6 +2013,46 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
}
+static bool isMipsArch(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips ||
+ Arch == llvm::Triple::mipsel ||
+ Arch == llvm::Triple::mips64 ||
+ Arch == llvm::Triple::mips64el;
+}
+
+static bool 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";
+
+ // 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";
+}
+
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
llvm::Triple::ArchType Arch = Triple.getArch();
@@ -2043,19 +2076,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- const bool IsMips = Arch == llvm::Triple::mips ||
- Arch == llvm::Triple::mipsel ||
- Arch == llvm::Triple::mips64 ||
- Arch == llvm::Triple::mips64el;
-
- const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI;
+ const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android;
// Do not use 'gnu' hash style for Mips targets because .gnu.hash
// and the MIPS ABI require .dynsym to be sorted in different ways.
// .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
// ABI requires a mapping between the GOT and the symbol table.
// Android loader does not support .gnu.hash.
- if (!IsMips && !IsAndroid) {
+ if (!isMipsArch(Arch) && !IsAndroid) {
if (IsRedhat(Distro) || IsOpenSuse(Distro) ||
(IsUbuntu(Distro) && Distro >= UbuntuMaverick))
ExtraOpts.push_back("--hash-style=gnu");
@@ -2084,16 +2112,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// to the link paths.
path_list &Paths = getFilePaths();
- const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64";
+ const std::string Multilib = getMultilibDir(Triple, Args);
const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
- addPathIfExists((GCCInstallation.getInstallPath() +
- GCCInstallation.getMultiarchSuffix()),
- Paths);
+
+ if (IsAndroid && isMipsR2Arch(Triple.getArch(), Args))
+ addPathIfExists(GCCInstallation.getInstallPath() +
+ GCCInstallation.getMultiarchSuffix() +
+ "/mips-r2",
+ Paths);
+ else
+ addPathIfExists((GCCInstallation.getInstallPath() +
+ GCCInstallation.getMultiarchSuffix()),
+ 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.
@@ -2108,6 +2143,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
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);
+ }
}
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
@@ -2326,16 +2366,25 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef Version = GCCInstallation.getVersion().Text;
- if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version,
- (GCCInstallation.getTriple().str() +
- GCCInstallation.getMultiarchSuffix()),
- DriverArgs, CC1Args)) {
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+
+ const std::string IncludePathCandidates[] = {
+ LibDir.str() + "/../include/c++/" + Version.str(),
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try this pattern.
- addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4",
- (GCCInstallation.getTriple().str() +
- GCCInstallation.getMultiarchSuffix()),
- DriverArgs, CC1Args);
+ InstallDir.str() + "/include/g++-v4",
+ // Android standalone toolchain has C++ headers in yet another place.
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.str(),
+ // 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))
+ break;
}
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 95a11beea158..4c267e8a8bfc 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -111,6 +111,7 @@ protected:
SmallVectorImpl<StringRef> &MultiarchTripleAliases);
void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
+ const ArgList &Args,
const std::string &LibDir,
StringRef CandidateTriple,
bool NeedsMultiarchSuffix = false);
@@ -128,8 +129,8 @@ public:
const ActionList &Inputs) const;
virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
protected:
/// \name ToolChain Implementation Helper Functions
@@ -155,9 +156,8 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
- virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
};
/// Darwin - The base Darwin tool chain.
@@ -185,11 +185,6 @@ private:
/// The OS version we are targeting.
mutable VersionTuple TargetVersion;
-protected:
- // FIXME: Remove this once there is a proper way to detect an ARC runtime
- // for the simulator.
- mutable VersionTuple TargetSimulatorVersionFromDefines;
-
private:
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
@@ -243,9 +238,7 @@ public:
}
bool isTargetMacOS() const {
- return !isTargetIOSSimulator() &&
- !isTargetIPhoneOS() &&
- TargetSimulatorVersionFromDefines == VersionTuple();
+ return !isTargetIOSSimulator() && !isTargetIPhoneOS();
}
bool isTargetInitialized() const { return TargetInitialized; }
@@ -325,6 +318,10 @@ public:
return true;
}
+ virtual bool IsEncodeExtendedBlockSignatureDefault() const {
+ return true;
+ }
+
virtual bool IsObjCNonFragileABIDefault() const {
// Non-fragile ABI is default for everything but i386.
return getTriple().getArch() != llvm::Triple::x86;
@@ -347,14 +344,14 @@ public:
virtual RuntimeLibType GetDefaultRuntimeLibType() const {
return ToolChain::RLT_CompilerRT;
}
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
virtual bool SupportsProfiling() const;
virtual bool SupportsObjCGC() const;
- virtual bool SupportsObjCARC() const;
+ virtual void CheckObjCARC() const;
virtual bool UseDwarfDebugFlags() const;
@@ -365,9 +362,6 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
-private:
- void AddGCCLibexecPath(unsigned darwinVersion);
-
public:
DarwinClang(const Driver &D, const llvm::Triple& Triple);
@@ -399,7 +393,7 @@ public:
std::string ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const;
- virtual const char *GetDefaultRelocationModel() const { return "pic"; }
+ virtual bool isPICDefault() const { return false; };
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -540,9 +534,8 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
bool IsMathErrnoDefault() const;
- bool IsUnwindTablesDefault() const;
- const char* GetDefaultRelocationModel() const;
- const char* GetForcedPicModel() const;
+ bool isPICDefault() const;
+ bool isPICDefaultForced() const;
private:
mutable llvm::DenseMap<unsigned, Tool*> Tools;
@@ -564,8 +557,8 @@ public:
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
- virtual const char *GetDefaultRelocationModel() const;
- virtual const char *GetForcedPicModel() const;
+ virtual bool isPICDefault() const;
+ virtual bool isPICDefaultForced() const;
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index ed67f7b9a1e4..e37959be4efa 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -33,6 +33,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "InputInfo.h"
+#include "SanitizerArgs.h"
#include "ToolChains.h"
using namespace clang::driver;
@@ -93,9 +94,15 @@ static void addDirectoryList(const ArgList &Args,
const char *ArgName,
const char *EnvVar) {
const char *DirList = ::getenv(EnvVar);
+ bool CombinedArg = false;
+
if (!DirList)
return; // Nothing to do.
+ StringRef Name(ArgName);
+ if (Name.equals("-I") || Name.equals("-L"))
+ CombinedArg = true;
+
StringRef Dirs(DirList);
if (Dirs.empty()) // Empty string should not add '.'.
return;
@@ -103,21 +110,37 @@ static void addDirectoryList(const ArgList &Args,
StringRef::size_type Delim;
while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
if (Delim == 0) { // Leading colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
} else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim)));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ }
}
Dirs = Dirs.substr(Delim + 1);
}
if (Dirs.empty()) { // Trailing colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
} else { // Add the last path.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs));
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs));
+ }
}
}
@@ -200,6 +223,12 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(ProfileRT));
}
+static bool forwardToGCC(const Option &O) {
+ return !O.hasFlag(options::NoForward) &&
+ !O.hasFlag(options::DriverOption) &&
+ !O.hasFlag(options::LinkerInput);
+}
+
void Clang::AddPreprocessingOptions(Compilation &C,
const Driver &D,
const ArgList &Args,
@@ -219,11 +248,11 @@ void Clang::AddPreprocessingOptions(Compilation &C,
(A = Args.getLastArg(options::OPT_MMD))) {
// Determine the output location.
const char *DepFile;
- if (Output.getType() == types::TY_Dependencies) {
- DepFile = Output.getFilename();
- } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
- DepFile = MF->getValue(Args);
+ if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
+ DepFile = MF->getValue();
C.addFailureResultFile(DepFile);
+ } else if (Output.getType() == types::TY_Dependencies) {
+ DepFile = Output.getFilename();
} else if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MM)) {
DepFile = "-";
@@ -242,7 +271,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
// when we are only generating a dependency file.
Arg *OutputOpt = Args.getLastArg(options::OPT_o);
if (OutputOpt && Output.getType() != types::TY_Dependencies) {
- DepTarget = OutputOpt->getValue(Args);
+ DepTarget = OutputOpt->getValue();
} else {
// Otherwise derive from the base input.
//
@@ -282,7 +311,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
if (A->getOption().matches(options::OPT_MQ)) {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(A->getValue(Args), Quoted);
+ QuoteTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
// -MT flag - no change
@@ -310,7 +339,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
bool FoundPTH = false;
bool FoundPCH = false;
- llvm::sys::Path P(A->getValue(Args));
+ llvm::sys::Path P(A->getValue());
bool Exists;
if (UsePCH) {
P.appendSuffix("pch");
@@ -442,10 +471,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "v7")
+ .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
.Case("cortex-m3", "v7m")
.Case("cortex-m4", "v7m")
.Case("cortex-m0", "v6m")
+ .Case("cortex-a9-mp", "v7f")
+ .Case("swift", "v7s")
.Default("");
}
@@ -458,7 +489,7 @@ static std::string getARMTargetCPU(const ArgList &Args,
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MCPU = A->getValue(Args);
+ StringRef MCPU = A->getValue();
// Handle -mcpu=native.
if (MCPU == "native")
return llvm::sys::getHostCPUName();
@@ -469,7 +500,7 @@ static std::string getARMTargetCPU(const ArgList &Args,
StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
// Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue(Args);
+ MArch = A->getValue();
} else {
// Otherwise, use the Arch from the triple.
MArch = Triple.getArchName();
@@ -500,6 +531,8 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7f", "armv7-f", "cortex-a9-mp")
+ .Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
.Case("ep9312", "ep9312")
@@ -531,7 +564,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
// frontend target.
static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
ArgStringList &CmdArgs) {
- StringRef FPU = A->getValue(Args);
+ StringRef FPU = A->getValue();
// Set the target features based on the FPU.
if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
@@ -569,14 +602,15 @@ static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
// Handle -mfpmath=.
static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
ArgStringList &CmdArgs, StringRef CPU) {
- StringRef FPMath = A->getValue(Args);
+ 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-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp")
+ if (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" ||
@@ -603,7 +637,7 @@ static StringRef getARMFloatABI(const Driver &D,
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
- FloatABI = A->getValue(Args);
+ FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi)
<< A->getAsString(Args);
@@ -643,7 +677,7 @@ static StringRef getARMFloatABI(const Driver &D,
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
- case llvm::Triple::ANDROIDEABI: {
+ case llvm::Triple::Android: {
std::string ArchName =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v7"))
@@ -669,18 +703,29 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs,
bool KernelOrKext) const {
const Driver &D = getToolChain().getDriver();
- llvm::Triple Triple = getToolChain().getTriple();
+ // Get the effective triple, which takes into account the deployment target.
+ std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
+ llvm::Triple Triple(TripleStr);
+ std::string CPUName = getARMTargetCPU(Args, Triple);
// Select the ABI to use.
//
// FIXME: Support -meabi.
const char *ABIName = 0;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
- ABIName = A->getValue(Args);
+ ABIName = A->getValue();
+ } 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")) {
+ ABIName = "aapcs";
+ } else {
+ ABIName = "apcs-gnu";
+ }
} else {
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
- case llvm::Triple::ANDROIDEABI:
+ case llvm::Triple::Android:
case llvm::Triple::GNUEABI:
case llvm::Triple::GNUEABIHF:
ABIName = "aapcs-linux";
@@ -697,7 +742,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Set the CPU based on -march= and -mcpu=.
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(getARMTargetCPU(Args, Triple)));
+ CmdArgs.push_back(Args.MakeArgString(CPUName));
// Determine floating point ABI from the options & target defaults.
StringRef FloatABI = getARMFloatABI(D, Args, Triple);
@@ -754,8 +799,10 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-long-calls");
+ if (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-long-calls");
+ }
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-strict-align");
@@ -777,44 +824,18 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back("-no-implicit-float");
}
-// Get default architecture.
-static const char* getMipsArchFromCPU(StringRef CPUName) {
- if (CPUName == "mips32" || CPUName == "mips32r2")
- return "mips";
-
- assert((CPUName == "mips64" || CPUName == "mips64r2") &&
- "Unexpected cpu name.");
-
- return "mips64";
-}
-
-// Check that ArchName is a known Mips architecture name.
-static bool checkMipsArchName(StringRef ArchName) {
- return ArchName == "mips" ||
- ArchName == "mipsel" ||
- ArchName == "mips64" ||
- ArchName == "mips64el";
-}
-
-// Get default target cpu.
-static const char* getMipsCPUFromArch(StringRef ArchName) {
- if (ArchName == "mips" || ArchName == "mipsel")
+// Translate MIPS CPU name alias option to CPU name.
+static StringRef getMipsCPUFromAlias(const Arg &A) {
+ if (A.getOption().matches(options::OPT_mips32))
return "mips32";
-
- assert((ArchName == "mips64" || ArchName == "mips64el") &&
- "Unexpected arch name.");
-
- return "mips64";
-}
-
-// Get default ABI.
-static const char* getMipsABIFromArch(StringRef ArchName) {
- if (ArchName == "mips" || ArchName == "mipsel")
- return "o32";
-
- assert((ArchName == "mips64" || ArchName == "mips64el") &&
- "Unexpected arch name.");
- return "n64";
+ 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 "";
}
// Get CPU and ABI names. They are not independent
@@ -823,26 +844,53 @@ static void getMipsCPUAndABI(const ArgList &Args,
const ToolChain &TC,
StringRef &CPUName,
StringRef &ABIName) {
- StringRef ArchName;
-
- // Select target cpu and architecture.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- CPUName = A->getValue(Args);
- ArchName = getMipsArchFromCPU(CPUName);
- }
- else {
- ArchName = Args.MakeArgString(TC.getArchName());
- if (!checkMipsArchName(ArchName))
- TC.getDriver().Diag(diag::err_drv_invalid_arch_name) << ArchName;
+ 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 = getMipsCPUFromArch(ArchName);
+ CPUName = A->getValue();
}
-
- // Select the ABI to use.
+
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
- ABIName = A->getValue(Args);
- else
- ABIName = getMipsABIFromArch(ArchName);
+ ABIName = A->getValue();
+
+ // Setup default CPU and ABI names.
+ if (CPUName.empty() && ABIName.empty()) {
+ switch (TC.getTriple().getArch()) {
+ default:
+ llvm_unreachable("Unexpected triple arch name");
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ CPUName = DefMips32CPU;
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ CPUName = DefMips64CPU;
+ break;
+ }
+ }
+
+ if (!ABIName.empty()) {
+ // Deduce CPU name from ABI name.
+ CPUName = llvm::StringSwitch<const char *>(ABIName)
+ .Cases("o32", "eabi", DefMips32CPU)
+ .Cases("n32", "n64", DefMips64CPU)
+ .Default("");
+ }
+ else if (!CPUName.empty()) {
+ // Deduce ABI name from CPU name.
+ ABIName = llvm::StringSwitch<const char *>(CPUName)
+ .Cases("mips32", "mips32r2", "o32")
+ .Cases("mips64", "mips64r2", "n64")
+ .Default("");
+ }
+
+ // FIXME: Warn on inconsistent cpu and abi usage.
}
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
@@ -859,7 +907,7 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
- FloatABI = A->getValue(Args);
+ FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
FloatABI = "hard";
@@ -941,12 +989,19 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
AddTargetFeature(Args, CmdArgs,
options::OPT_mdspr2, options::OPT_mno_dspr2,
"dspr2");
+
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v));
+ A->claim();
+ }
}
/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
static std::string getPPCTargetCPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPUName = A->getValue(Args);
+ StringRef CPUName = A->getValue();
if (CPUName == "native") {
std::string CPU = llvm::sys::getHostCPUName();
@@ -978,6 +1033,8 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
+ .Case("e500mc", "e500mc")
+ .Case("e5500", "e5500")
.Case("power6", "pwr6")
.Case("power7", "pwr7")
.Case("powerpc", "ppc")
@@ -1015,7 +1072,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -1054,6 +1111,8 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
void Clang::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ const bool isAndroid =
+ getToolChain().getTriple().getEnvironment() == llvm::Triple::Android;
if (!Args.hasFlag(options::OPT_mred_zone,
options::OPT_mno_red_zone,
true) ||
@@ -1068,7 +1127,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue(Args)) == "native") {
+ if (StringRef(A->getValue()) == "native") {
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
//
@@ -1078,7 +1137,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (!CPU.empty() && CPU != "generic")
CPUName = Args.MakeArgString(CPU);
} else
- CPUName = A->getValue(Args);
+ CPUName = A->getValue();
}
// Select the default CPU if none was given (or detection failed).
@@ -1118,7 +1177,9 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "pentium4";
+ // All x86 devices running Android have core2 as their common
+ // denominator. This makes a better choice than pentium4.
+ CPUName = isAndroid ? "core2" : "pentium4";
}
}
@@ -1141,8 +1202,8 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
(*it)->claim();
// Skip over "-m".
- assert(Name.startswith("-m") && "Invalid feature name.");
- Name = Name.substr(2);
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
bool IsNegative = Name.startswith("no-");
if (IsNegative)
@@ -1174,7 +1235,7 @@ static Arg* getLastHexagonArchArg (const ArgList &Args)
A->claim();
}
else if ((*it)->getOption().matches(options::OPT_m_Joined)){
- StringRef Value = (*it)->getValue(Args,0);
+ StringRef Value = (*it)->getValue(0);
if (Value.startswith("v")) {
A = *it;
A->claim();
@@ -1191,7 +1252,7 @@ static StringRef getHexagonTargetCPU(const ArgList &Args)
// Select the default CPU (v4) if none was given or detection failed.
if ((A = getLastHexagonArchArg (Args))) {
- WhichHexagon = A->getValue(Args);
+ WhichHexagon = A->getValue();
if (WhichHexagon == "")
return "v4";
else
@@ -1216,7 +1277,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_G,
options::OPT_msmall_data_threshold_EQ)) {
std::string SmallDataThreshold="-small-data-threshold=";
- SmallDataThreshold += A->getValue(Args);
+ SmallDataThreshold += A->getValue();
CmdArgs.push_back ("-mllvm");
CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
A->claim();
@@ -1392,25 +1453,80 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
+SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
+ Kind = 0;
+
+ const Arg *AsanArg, *TsanArg, *UbsanArg;
+ for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
+ unsigned Add = 0, Remove = 0;
+ const char *DeprecatedReplacement = 0;
+ if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) {
+ Add = Address;
+ DeprecatedReplacement = "-fsanitize=address";
+ } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) {
+ Remove = Address;
+ DeprecatedReplacement = "-fno-sanitize=address";
+ } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) {
+ Add = Thread;
+ DeprecatedReplacement = "-fsanitize=thread";
+ } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) {
+ Remove = Thread;
+ DeprecatedReplacement = "-fno-sanitize=thread";
+ } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
+ Add = Undefined;
+ DeprecatedReplacement = "-fsanitize=undefined";
+ } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) {
+ Add = parse(D, *I);
+ } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+ Remove = parse(D, *I);
+ } else {
+ continue;
+ }
+
+ (*I)->claim();
+
+ Kind |= Add;
+ Kind &= ~Remove;
+
+ if (Add & NeedsAsanRt) AsanArg = *I;
+ if (Add & NeedsTsanRt) TsanArg = *I;
+ if (Add & NeedsUbsanRt) UbsanArg = *I;
+
+ // If this is a deprecated synonym, produce a warning directing users
+ // towards the new spelling.
+ if (DeprecatedReplacement)
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << (*I)->getAsString(Args) << DeprecatedReplacement;
+ }
+
+ // Only one runtime library can be used at once.
+ // FIXME: Allow Ubsan to be combined with the other two.
+ bool NeedsAsan = needsAsanRt();
+ bool NeedsTsan = needsTsanRt();
+ bool NeedsUbsan = needsUbsanRt();
+ if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg,
+ NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
+ << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg,
+ NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
+}
+
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
/// 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 (!Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false))
- return;
- if(TC.getTriple().getEnvironment() == llvm::Triple::ANDROIDEABI) {
+ if(TC.getTriple().getEnvironment() == llvm::Triple::Android) {
if (!Args.hasArg(options::OPT_shared)) {
if (!Args.hasArg(options::OPT_pie))
TC.getDriver().Diag(diag::err_drv_asan_android_requires_pie);
- // For an executable, we add a .preinit_array stub.
- CmdArgs.push_back("-u");
- CmdArgs.push_back("__asan_preinit");
- CmdArgs.push_back("-lasan");
}
- CmdArgs.push_back("-lasan_preload");
- CmdArgs.push_back("-ldl");
+ SmallString<128> LibAsan(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibAsan, "lib", "linux",
+ (Twine("libclang_rt.asan-") +
+ TC.getArchName() + "-android.so"));
+ CmdArgs.push_back(Args.MakeArgString(LibAsan));
} else {
if (!Args.hasArg(options::OPT_shared)) {
// LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library
@@ -1431,9 +1547,6 @@ 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.hasFlag(options::OPT_fthread_sanitizer,
- options::OPT_fno_thread_sanitizer, false))
- return;
if (!Args.hasArg(options::OPT_shared)) {
// LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library
// resource directory.
@@ -1448,6 +1561,22 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
}
}
+/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
+/// (Linux).
+static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library
+ // resource directory.
+ SmallString<128> LibUbsan(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibUbsan, "lib", "linux",
+ (Twine("libclang_rt.ubsan-") +
+ TC.getArchName() + ".a"));
+ CmdArgs.push_back(Args.MakeArgString(LibUbsan));
+ CmdArgs.push_back("-lpthread");
+ }
+}
+
static bool shouldUseFramePointer(const ArgList &Args,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
@@ -1516,7 +1645,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
- StringRef Value = A->getValue(Args, i);
+ StringRef Value = A->getValue(i);
if (Value == "-force_cpusubtype_ALL") {
// Do nothing, this is the default and we don't support anything else.
@@ -1600,8 +1729,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-analyzer-eagerly-assume");
- CmdArgs.push_back("-analyzer-ipa=inlining");
-
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
@@ -1627,7 +1754,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// reasons.
CmdArgs.push_back("-analyzer-output");
if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("plist");
@@ -1642,67 +1769,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CheckCodeGenerationOptions(D, Args);
- // Perform argument translation for LLVM backend. This
- // takes some care in reconciling with llvm-gcc. The
- // issue is that llvm-gcc translates these options based on
- // the values in cc1, whereas we are processing based on
- // the driver arguments.
-
- // This comes from the default translation the driver + cc1
- // would do to enable flag_pic.
-
- 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);
- bool PICDisabled = false;
- bool PICEnabled = false;
- bool PICForPIE = false;
- if (LastPICArg) {
- PICForPIE = (LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie));
- PICEnabled = (PICForPIE ||
- LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic));
- PICDisabled = !PICEnabled;
+ // For the PIC and PIE flag options, this logic is different from the legacy
+ // logic in very old versions of GCC, as that logic was just a bug no one had
+ // ever fixed. This logic is both more rational and consistent with GCC's new
+ // logic now that the bugs are fixed. The last argument relating to either
+ // PIC or PIE wins, and no other argument is used. If the last argument is
+ // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any
+ // PIE option implicitly enables PIC at the same level.
+ bool PIE = false;
+ bool PIC = getToolChain().isPICDefault();
+ bool IsPICLevelTwo = PIC;
+ if (Arg *A = 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)) {
+ Option O = A->getOption();
+ if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
+ O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
+ PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
+ PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
+ IsPICLevelTwo = O.matches(options::OPT_fPIE) ||
+ O.matches(options::OPT_fPIC);
+ } else {
+ PIE = PIC = false;
+ }
}
+ // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness
+ // is forced, then neither PIC nor PIE flags will have no effect.
+ if (getToolChain().isPICDefaultForced()) {
+ PIE = false;
+ PIC = getToolChain().isPICDefault();
+ IsPICLevelTwo = PIC;
+ }
+
+ // Inroduce 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).
+ if (PIC && getToolChain().getTriple().isOSDarwin())
+ IsPICLevelTwo |= getToolChain().isPICDefault();
+
// Note that these flags are trump-cards. Regardless of the order w.r.t. the
// PIC or PIE options above, if these show up, PIC is disabled.
- if (Args.hasArg(options::OPT_mkernel))
- PICDisabled = true;
+ llvm::Triple Triple(TripleStr);
+ if ((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ (Triple.getOS() != llvm::Triple::IOS ||
+ Triple.isOSVersionLT(6)))
+ PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
- PICDisabled = true;
- bool DynamicNoPIC = Args.hasArg(options::OPT_mdynamic_no_pic);
-
- // Select the relocation model.
- const char *Model = getToolChain().GetForcedPicModel();
- if (!Model) {
- if (DynamicNoPIC)
- Model = "dynamic-no-pic";
- else if (PICDisabled)
- Model = "static";
- else if (PICEnabled)
- Model = "pic";
- else
- Model = getToolChain().GetDefaultRelocationModel();
- }
- StringRef ModelStr = Model ? Model : "";
- if (Model && ModelStr != "pic") {
- CmdArgs.push_back("-mrelocation-model");
- CmdArgs.push_back(Model);
- }
+ PIC = PIE = false;
- // Infer the __PIC__ and __PIE__ values.
- if (ModelStr == "pic" && PICForPIE) {
- CmdArgs.push_back("-pie-level");
- CmdArgs.push_back((LastPICArg &&
- LastPICArg->getOption().matches(options::OPT_fPIE)) ?
- "2" : "1");
- } else if (ModelStr == "pic" || ModelStr == "dynamic-no-pic") {
- CmdArgs.push_back("-pic-level");
- CmdArgs.push_back(((ModelStr != "dynamic-no-pic" && LastPICArg &&
- LastPICArg->getOption().matches(options::OPT_fPIC)) ||
- getToolChain().getTriple().isOSDarwin()) ? "2" : "1");
+ if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
+ // This is a very special mode. It trumps the other modes, almost no one
+ // uses it, and it isn't even valid on any OS but Darwin.
+ if (!getToolChain().getTriple().isOSDarwin())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getToolChain().getTriple().str();
+
+ // FIXME: Warn when this flag trumps some other PIC or PIE flag.
+
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back("dynamic-no-pic");
+
+ // Only a forced PIC mode can cause the actual compile to have PIC defines
+ // etc., no flags are sufficient. This behavior was selected to closely
+ // match that of llvm-gcc and Apple GCC before that.
+ if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back("2");
+ }
+ } else {
+ // Currently, LLVM only knows about PIC vs. static; the PIE differences are
+ // handled in Clang's IRGen by the -pie-level flag.
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(PIC ? "pic" : "static");
+
+ if (PIC) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ if (PIE) {
+ CmdArgs.push_back("-pie-level");
+ CmdArgs.push_back(IsPICLevelTwo ? "2" : "1");
+ }
+ }
}
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
@@ -1713,7 +1863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
@@ -1741,25 +1891,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// flag disables them after the flag enabling them, enable the codegen
// optimization. This is complicated by several "umbrella" flags.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffinite_math_only,
options::OPT_fno_finite_math_only,
options::OPT_fhonor_infinities,
options::OPT_fno_honor_infinities))
- if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_finite_math_only &&
A->getOption().getID() != options::OPT_fhonor_infinities)
CmdArgs.push_back("-menable-no-infs");
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffinite_math_only,
options::OPT_fno_finite_math_only,
options::OPT_fhonor_nans,
options::OPT_fno_honor_nans))
- if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_finite_math_only &&
A->getOption().getID() != options::OPT_fhonor_nans)
CmdArgs.push_back("-menable-no-nans");
// -fmath-errno is the default on some platforms, e.g. BSD-derived OSes.
bool MathErrno = getToolChain().IsMathErrnoDefault();
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_fmath_errno,
options::OPT_fno_math_errno))
MathErrno = A->getOption().getID() == options::OPT_fmath_errno;
@@ -1772,38 +1927,46 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// madness.
bool AssociativeMath = false;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_fassociative_math,
options::OPT_fno_associative_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fno_associative_math)
AssociativeMath = true;
bool ReciprocalMath = false;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_freciprocal_math,
options::OPT_fno_reciprocal_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fno_reciprocal_math)
ReciprocalMath = true;
bool SignedZeros = true;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_fsigned_zeros,
options::OPT_fno_signed_zeros))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_fsigned_zeros)
SignedZeros = false;
bool TrappingMath = true;
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_funsafe_math_optimizations,
options::OPT_fno_unsafe_math_optimizations,
options::OPT_ftrapping_math,
options::OPT_fno_trapping_math))
- if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ if (A->getOption().getID() != options::OPT_fno_fast_math &&
+ A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
A->getOption().getID() != options::OPT_ftrapping_math)
TrappingMath = false;
if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
@@ -1813,16 +1976,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Validate and pass through -fp-contract option.
if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fno_fast_math,
options::OPT_ffp_contract)) {
if (A->getOption().getID() == options::OPT_ffp_contract) {
- StringRef Val = A->getValue(Args);
+ StringRef Val = A->getValue();
if (Val == "fast" || Val == "on" || Val == "off") {
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
}
- } else { // A is OPT_ffast_math
+ } else if (A->getOption().getID() == options::OPT_ffast_math) {
// If fast-math is set then set the fp-contract mode to fast.
CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
}
@@ -1833,10 +1997,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// preprocessor macros. This is distinct from enabling any optimizations as
// these options induce language changes which must survive serialization
// and deserialization, etc.
- if (Args.hasArg(options::OPT_ffast_math))
- CmdArgs.push_back("-ffast-math");
- if (Args.hasArg(options::OPT_ffinite_math_only))
- CmdArgs.push_back("-ffinite-math-only");
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math))
+ if (A->getOption().matches(options::OPT_ffast_math))
+ CmdArgs.push_back("-ffast-math");
+ if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math))
+ if (A->getOption().matches(options::OPT_ffinite_math_only))
+ CmdArgs.push_back("-ffinite-math-only");
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
@@ -1885,7 +2051,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// FIXME: Handle -mtune=.
@@ -1893,7 +2059,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
CmdArgs.push_back("-mcode-model");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Add target specific cpu and features flags.
@@ -1937,7 +2103,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
CmdArgs.push_back("-target-linker-version");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// -mno-omit-leaf-frame-pointer is the default on Darwin.
@@ -1991,6 +2157,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
Args.ClaimAllArgs(options::OPT_g_flags_Group);
+ if (Args.hasArg(options::OPT_gcolumn_info))
+ CmdArgs.push_back("-dwarf-column-info");
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -2008,7 +2176,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
- CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ SmallString<128> absFilename(Output.getFilename());
+ llvm::sys::fs::make_absolute(absFilename);
+ CmdArgs.push_back(Args.MakeArgString(absFilename));
}
}
@@ -2047,7 +2217,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case options::OPT_ccc_arcmt_migrate:
CmdArgs.push_back("-arcmt-migrate");
CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
@@ -2062,7 +2232,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< A->getAsString(Args) << "-ccc-arcmt-migrate";
}
CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
options::OPT_objcmt_migrate_subscripting)) {
@@ -2094,7 +2264,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (A->getOption().matches(options::OPT_O4))
CmdArgs.push_back("-O3");
else if (A->getOption().matches(options::OPT_O) &&
- A->getValue(Args)[0] == '\0')
+ A->getValue()[0] == '\0')
CmdArgs.push_back("-O2");
else
A->render(Args, CmdArgs);
@@ -2132,8 +2302,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// eventually we want to do all the standard defaulting here instead of
// splitting it between the driver and clang -cc1.
if (!types::isCXX(InputType))
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
+ else if (getToolChain().getTriple().getOS() == llvm::Triple::Win32)
+ CmdArgs.push_back("-std=c++11");
+
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
@@ -2182,18 +2355,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
CmdArgs.push_back("-ftemplate-depth");
- CmdArgs.push_back(A->getValue(Args));
+ 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(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
if (A->getNumValues()) {
- StringRef bytes = A->getValue(Args);
+ StringRef bytes = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
} else
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
@@ -2202,50 +2375,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking,
options::OPT_fbounds_checking_EQ)) {
if (A->getNumValues()) {
- StringRef val = A->getValue(Args);
+ StringRef val = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-fbounds-checking=" + val));
} else
CmdArgs.push_back("-fbounds-checking=1");
}
- if (Args.hasArg(options::OPT__relocatable_pch))
+ if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
CmdArgs.push_back("-ftabstop");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
CmdArgs.push_back("-ferror-limit");
if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("19");
if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
CmdArgs.push_back("-fmacro-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
CmdArgs.push_back("-ftemplate-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
CmdArgs.push_back("-fconstexpr-backtrace-limit");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
@@ -2255,7 +2428,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
@@ -2268,7 +2441,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-ffreestanding");
// Forward -f (flag) options which we can pass directly.
- Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior);
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
@@ -2278,6 +2450,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
+ SanitizerArgs Sanitize(D, Args);
+ Sanitize.addArgs(Args, CmdArgs);
+
// Report and error for -faltivec on anything other then PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
@@ -2288,14 +2463,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false))
- CmdArgs.push_back("-faddress-sanitizer");
-
- if (Args.hasFlag(options::OPT_fthread_sanitizer,
- options::OPT_fno_thread_sanitizer, false))
- CmdArgs.push_back("-fthread-sanitizer");
-
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
options::OPT_fno_lax_vector_conversions))
@@ -2316,7 +2483,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
@@ -2337,6 +2504,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pthread);
+
// -stack-protector=0 is default.
unsigned StackProtectorLevel = 0;
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
@@ -2355,6 +2523,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
}
+ // --param ssp-buffer-size=
+ for (arg_iterator it = Args.filtered_begin(options::OPT__param),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ StringRef Str((*it)->getValue());
+ if (Str.startswith("ssp-buffer-size=")) {
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector-buffer-size");
+ // FIXME: Verify the argument is a valid integer.
+ CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16)));
+ }
+ (*it)->claim();
+ }
+ }
+
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
false)) {
@@ -2370,6 +2552,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
+ if (Args.hasArg(options::OPT_mstrict_align)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-strict-align");
+ }
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -2427,9 +2613,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) ||
- KernelOrKext)
+ KernelOrKext) {
CmdArgs.push_back("-fno-rtti");
+ // -fno-rtti cannot usefully be combined with -fsanitize=vptr.
+ if (Sanitize.sanitizesVptr()) {
+ std::string NoRttiArg =
+ Args.getLastArg(options::OPT_mkernel,
+ options::OPT_fapple_kext,
+ options::OPT_fno_rtti)->getAsString(Args);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=vptr" << NoRttiArg;
+ }
+ }
+
// -fshort-enums=0 is default for all architectures except Hexagon.
if (Args.hasFlag(options::OPT_fshort_enums,
options::OPT_fno_short_enums,
@@ -2537,12 +2734,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
+ // -fencode-extended-block-signature=1 is default.
+ if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
+ CmdArgs.push_back("-fencode-extended-block-signature");
+ }
+
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
// NOTE: This logic is duplicated in ToolChains.cpp.
bool ARC = isObjCAutoRefCount(Args);
if (ARC) {
- if (!getToolChain().SupportsObjCARC())
- D.Diag(diag::err_arc_unsupported);
+ getToolChain().CheckObjCARC();
CmdArgs.push_back("-fobjc-arc");
@@ -2629,7 +2830,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-pack-struct doesn't apply to -fpack-struct=.
if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
std::string PackStructStr = "-fpack-struct=";
- PackStructStr += A->getValue(Args);
+ PackStructStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(PackStructStr));
} else if (Args.hasFlag(options::OPT_fpack_struct,
options::OPT_fno_pack_struct, false)) {
@@ -2678,13 +2879,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
CmdArgs.push_back("-fdiagnostics-show-category");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(
@@ -2776,9 +2977,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Handle serialized diagnostics.
if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
CmdArgs.push_back("-serialize-diagnostic-file");
- CmdArgs.push_back(Args.MakeArgString(A->getValue(Args)));
+ CmdArgs.push_back(Args.MakeArgString(A->getValue()));
}
+ if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
+ CmdArgs.push_back("-fretain-comments-from-system-headers");
+
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
@@ -2788,7 +2992,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm.
- if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns")
+ if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns")
CmdArgs.push_back("-disable-llvm-optzns");
else
(*it)->render(Args, CmdArgs);
@@ -2807,7 +3011,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
CmdArgs.push_back("-x");
- CmdArgs.push_back(types::getTypeName(II.getType()));
+ if (Args.hasArg(options::OPT_rewrite_objc))
+ CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
+ else
+ CmdArgs.push_back(types::getTypeName(II.getType()));
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
@@ -2894,7 +3101,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if (runtimeArg &&
runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) {
ObjCRuntime runtime;
- StringRef value = runtimeArg->getValue(args);
+ StringRef value = runtimeArg->getValue();
if (runtime.tryParse(value)) {
getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
<< value;
@@ -2912,7 +3119,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
unsigned objcABIVersion = 1;
// If -fobjc-abi-version= is present, use that to set the version.
if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
- StringRef value = abiArg->getValue(args);
+ StringRef value = abiArg->getValue();
if (value == "1")
objcABIVersion = 1;
else if (value == "2")
@@ -2940,7 +3147,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if (Arg *abiArg = args.getLastArg(
options::OPT_fobjc_nonfragile_abi_version_EQ)) {
- StringRef value = abiArg->getValue(args);
+ StringRef value = abiArg->getValue();
if (value == "1")
nonFragileABIVersion = 1;
else if (value == "2")
@@ -2993,7 +3200,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
// Legacy behaviour is to target the gnustep runtime if we are i
// non-fragile mode or the GCC runtime in fragile mode.
if (isNonFragile)
- runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple());
+ runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1,6));
else
runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
}
@@ -3116,7 +3323,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().hasForwardToGCC()) {
+ if (forwardToGCC(A->getOption())) {
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -3134,17 +3341,17 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
- const std::string &Arch = getToolChain().getArchName();
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
// FIXME: Remove these special cases.
- if (Arch == "powerpc")
+ if (Arch == llvm::Triple::ppc)
CmdArgs.push_back("ppc");
- else if (Arch == "powerpc64")
+ else if (Arch == llvm::Triple::ppc64)
CmdArgs.push_back("ppc64");
else
- CmdArgs.push_back(Args.MakeArgString(Arch));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
}
// Try to force gcc to match the tool chain we want, if we recognize
@@ -3152,9 +3359,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: The triple class should directly provide the information we want
// here.
- if (Arch == "i386" || Arch == "powerpc")
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
- else if (Arch == "x86_64" || Arch == "powerpc64")
+ else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64)
CmdArgs.push_back("-m64");
if (Output.isFilename()) {
@@ -3341,7 +3548,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
- if (A->getOption().hasForwardToGCC()) {
+ if (forwardToGCC(A->getOption())) {
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -3409,6 +3616,37 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// Hexagon tools end.
+llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
+ // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for
+ // archs which Darwin doesn't use.
+
+ // The matching this routine does is fairly pointless, since it is neither the
+ // complete architecture list, nor a reasonable subset. The problem is that
+ // historically the driver driver accepts this and also ties its -march=
+ // handling to the architecture name, so we need to be careful before removing
+ // support for it.
+
+ // This code must be kept in sync with Clang's Darwin specific argument
+ // translation.
+
+ return llvm::StringSwitch<llvm::Triple::ArchType>(Str)
+ .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc)
+ .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc)
+ .Case("ppc64", llvm::Triple::ppc64)
+ .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
+ .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
+ llvm::Triple::x86)
+ .Case("x86_64", llvm::Triple::x86_64)
+ // This is derived from the driver driver.
+ .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm)
+ .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm)
+ .Case("r600", llvm::Triple::r600)
+ .Case("nvptx", llvm::Triple::nvptx)
+ .Case("nvptx64", llvm::Triple::nvptx64)
+ .Case("amdil", llvm::Triple::amdil)
+ .Case("spir", llvm::Triple::spir)
+ .Default(llvm::Triple::UnknownArch);
+}
const char *darwin::CC1::getCC1Name(types::ID Type) const {
switch (Type) {
@@ -3457,7 +3695,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
std::string Res;
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- std::string Str(OutputOpt->getValue(Args));
+ std::string Str(OutputOpt->getValue());
Res = Str.substr(0, Str.rfind('.'));
} else {
Res = darwin::CC1::getBaseInputStem(Args, Inputs);
@@ -3546,6 +3784,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
.Case("duplicate-method-arg", true)
.Case("dynamic-class-memaccess", true)
.Case("enum-compare", true)
+ .Case("enum-conversion", true)
.Case("exit-time-destructors", true)
.Case("gnu", true)
.Case("gnu-designator", true)
@@ -3555,6 +3794,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
.Case("implicit-atomic-properties", true)
.Case("incompatible-pointer-types", true)
.Case("incomplete-implementation", true)
+ .Case("int-conversion", true)
.Case("initializer-overrides", true)
.Case("invalid-noreturn", true)
.Case("invalid-token-paste", true)
@@ -3619,7 +3859,10 @@ void darwin::CC1::AddCC1Args(const ArgList &Args,
CheckCodeGenerationOptions(D, Args);
// Derived from cc1 spec.
- if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) &&
+ if ((!Args.hasArg(options::OPT_mkernel) ||
+ (getDarwinToolChain().isTargetIPhoneOS() &&
+ !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) &&
+ !Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_mdynamic_no_pic))
CmdArgs.push_back("-fPIC");
@@ -3672,7 +3915,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
Args.hasArg(options::OPT_o)) {
Arg *OutputOpt = Args.getLastArg(options::OPT_o);
CmdArgs.push_back("-auxbase-strip");
- CmdArgs.push_back(OutputOpt->getValue(Args));
+ CmdArgs.push_back(OutputOpt->getValue());
} else {
CmdArgs.push_back("-auxbase");
CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
@@ -3811,7 +4054,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
Args.AddLastArg(CmdArgs, options::OPT_P);
// FIXME: Handle %I properly.
- if (getToolChain().getArchName() == "x86_64") {
+ if (getToolChain().getArch() == llvm::Triple::x86_64) {
CmdArgs.push_back("-imultilib");
CmdArgs.push_back("x86_64");
}
@@ -3837,7 +4080,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
(Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) {
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
CmdArgs.push_back("-MQ");
- CmdArgs.push_back(OutputOpt->getValue(Args));
+ CmdArgs.push_back(OutputOpt->getValue());
}
}
@@ -4073,9 +4316,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-force_cpusubtype_ALL");
if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 &&
- (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext)))
+ (((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ (!getDarwinToolChain().isTargetIPhoneOS() ||
+ getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) ||
+ Args.hasArg(options::OPT_static)))
CmdArgs.push_back("-static");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -4110,16 +4355,29 @@ void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
CmdArgs.push_back("-force_cpusubtype_ALL");
}
+bool darwin::Link::NeedsTempPath(const InputInfoList &Inputs) const {
+ // We only need to generate a temp path for LTO if we aren't compiling object
+ // files. When compiling source files, we run 'dsymutil' after linking. We
+ // don't run 'dsymutil' when compiling object files.
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it)
+ if (it->getType() != types::TY_Object)
+ return true;
+
+ return false;
+}
+
void darwin::Link::AddLinkArgs(Compilation &C,
const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const {
const Driver &D = getToolChain().getDriver();
const toolchains::Darwin &DarwinTC = getDarwinToolChain();
unsigned Version[3] = { 0, 0, 0 };
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0],
+ if (!Driver::GetReleaseVersion(A->getValue(), Version[0],
Version[1], Version[2], HadExtra) ||
HadExtra)
D.Diag(diag::err_drv_invalid_version_number)
@@ -4140,7 +4398,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (StringRef(A->getValue(Args, i)) == "-kext")
+ if (StringRef(A->getValue(i)) == "-kext")
UsesLdClassic = true;
}
}
@@ -4151,7 +4409,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
// If we are using LTO, then automatically create a temporary file path for
// the linker to use, so that it's lifetime will extend past a possible
// dsymutil step.
- if (Version[0] >= 116 && D.IsUsingLTO(Args)) {
+ if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) {
const char *TmpPath = C.getArgs().MakeArgString(
D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
C.addTempFile(TmpPath);
@@ -4286,7 +4544,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
} else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back(A->getValue(Args));
+ CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
@@ -4338,7 +4596,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// I'm not sure why this particular decomposition exists in gcc, but
// we follow suite for ease of comparison.
- AddLinkArgs(C, Args, CmdArgs);
+ AddLinkArgs(C, Args, CmdArgs, Inputs);
Args.AddAllArgs(CmdArgs, options::OPT_d_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -4423,7 +4681,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
} else if (getDarwinToolChain().isTargetIPhoneOS()) {
if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-lcrt1.o");
- else
+ else if (getDarwinToolChain().isIPhoneOSVersionLT(6, 0))
CmdArgs.push_back("-lcrt1.3.1.o");
} else {
if (getDarwinToolChain().isMacosxVersionLT(10, 5))
@@ -4451,11 +4709,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
- // If we're building a dynamic lib with -faddress-sanitizer, unresolved
- // symbols may appear. Mark all of them as dynamic_lookup.
- // Linking executables is handled in lib/Driver/ToolChains.cpp.
- if (Args.hasFlag(options::OPT_faddress_sanitizer,
- options::OPT_fno_address_sanitizer, false)) {
+ SanitizerArgs Sanitize(getToolChain().getDriver(), Args);
+ // If we're building a dynamic lib with -fsanitize=address, or
+ // -fsanitize=undefined, unresolved symbols may appear. Mark all
+ // of them as dynamic_lookup. Linking executables is handled in
+ // lib/Driver/ToolChains.cpp.
+ if (Sanitize.needsAsanRt() || Sanitize.needsUbsanRt()) {
if (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) {
CmdArgs.push_back("-undefined");
@@ -4474,14 +4733,14 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_nodefaultlibs)) {
// Avoid linking compatibility stubs on i386 mac.
if (!getDarwinToolChain().isTargetMacOS() ||
- getDarwinToolChain().getArchName() != "i386") {
+ getDarwinToolChain().getArch() != llvm::Triple::x86) {
// If we don't have ARC or subscripting runtime support, link in the
// runtime stubs. We have to do this *before* adding any of the normal
// linker inputs so that its initializer gets run first.
ObjCRuntime runtime =
getDarwinToolChain().getDefaultObjCRuntime(/*nonfragile*/ true);
// We use arclite library for both ARC and subscripting support.
- if ((!runtime.hasARC() && isObjCAutoRefCount(Args)) ||
+ if ((!runtime.hasNativeARC() && isObjCAutoRefCount(Args)) ||
!runtime.hasSubscripting())
getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
}
@@ -4937,14 +5196,21 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// the default system libraries. Just mimic this for now.
CmdArgs.push_back("-lgcc");
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) &&
+ Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lc_p");
else
CmdArgs.push_back("-lc");
}
+
CmdArgs.push_back("-lgcc");
}
@@ -5056,8 +5322,14 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) &&
+ Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lc_p");
@@ -5108,17 +5380,48 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
-
- if (getToolChain().getArchName() == "powerpc")
+ else if (getToolChain().getArch() == llvm::Triple::ppc)
CmdArgs.push_back("-a32");
+ else 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(), CPUName, ABIName);
- // Set byte order explicitly
- if (getToolChain().getArchName() == "mips")
- CmdArgs.push_back("-EB");
- else if (getToolChain().getArchName() == "mipsel")
- CmdArgs.push_back("-EL");
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ // Convert ABI name to the GNU tools acceptable variant.
+ if (ABIName == "o32")
+ ABIName = "32";
+ else if (ABIName == "n64")
+ ABIName = "64";
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(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);
@@ -5142,7 +5445,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
+ const toolchains::FreeBSD& ToolChain =
+ static_cast<const toolchains::FreeBSD&>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -5156,6 +5461,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
@@ -5168,8 +5476,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
- if (getToolChain().getTriple().getOSMajorVersion() >= 9) {
- llvm::Triple::ArchType Arch = getToolChain().getArch();
+ if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
+ llvm::Triple::ArchType Arch = ToolChain.getArch();
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
CmdArgs.push_back("--hash-style=both");
@@ -5180,12 +5488,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (ToolChain.getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386_fbsd");
}
- if (getToolChain().getArchName() == "powerpc") {
+ if (ToolChain.getArch() == llvm::Triple::ppc) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32ppc_fbsd");
}
@@ -5199,29 +5507,33 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
+ const char *crt1 = NULL;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("gcrt1.o")));
- else {
- const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o";
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath(crt)));
- }
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtbegin.o")));
- } else {
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crtbeginS.o")));
+ crt1 = "gcrt1.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crt1 = "Scrt1.o";
+ else
+ crt1 = "crt1.o";
}
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin = NULL;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- const ToolChain::path_list Paths = getToolChain().getFilePaths();
+ const ToolChain::path_list Paths = ToolChain.getFilePaths();
for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
i != e; ++i)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
@@ -5232,12 +5544,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
@@ -5290,20 +5602,17 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtend.o")));
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtendS.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "crtn.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(ToolChain.GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5320,9 +5629,9 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--32");
// Set byte order explicitly
- if (getToolChain().getArchName() == "mips")
+ if (getToolChain().getArch() == llvm::Triple::mips)
CmdArgs.push_back("-EB");
- else if (getToolChain().getArchName() == "mipsel")
+ else if (getToolChain().getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("-EL");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5547,7 +5856,7 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
static void AddLibgcc(llvm::Triple Triple, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
- bool isAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI;
+ bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_static_libgcc);
if (!D.CCCIsCXX)
@@ -5570,6 +5879,11 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
CmdArgs.push_back("-lgcc");
}
+static bool hasMipsN32ABIArg(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef("n32"));
+}
+
void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -5578,8 +5892,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const toolchains::Linux& ToolChain =
static_cast<const toolchains::Linux&>(getToolChain());
const Driver &D = ToolChain.getDriver();
- const bool isAndroid = ToolChain.getTriple().getEnvironment() ==
- llvm::Triple::ANDROIDEABI;
+ const bool isAndroid =
+ ToolChain.getTriple().getEnvironment() == llvm::Triple::Android;
ArgStringList CmdArgs;
@@ -5626,10 +5940,18 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf32btsmip");
else if (ToolChain.getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("elf32ltsmip");
- else if (ToolChain.getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("elf64btsmip");
- else if (ToolChain.getArch() == llvm::Triple::mips64el)
- CmdArgs.push_back("elf64ltsmip");
+ else if (ToolChain.getArch() == llvm::Triple::mips64) {
+ if (hasMipsN32ABIArg(Args))
+ CmdArgs.push_back("elf32btsmipn32");
+ else
+ CmdArgs.push_back("elf64btsmip");
+ }
+ else if (ToolChain.getArch() == llvm::Triple::mips64el) {
+ if (hasMipsN32ABIArg(Args))
+ CmdArgs.push_back("elf32ltsmipn32");
+ else
+ CmdArgs.push_back("elf64ltsmip");
+ }
else
CmdArgs.push_back("elf_x86_64");
@@ -5641,8 +5963,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-static");
} else if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-shared");
- if ((ToolChain.getArch() == llvm::Triple::arm
- || ToolChain.getArch() == llvm::Triple::thumb) && isAndroid) {
+ if (isAndroid) {
CmdArgs.push_back("-Bsymbolic");
}
}
@@ -5667,8 +5988,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("/lib/ld.so.1");
else if (ToolChain.getArch() == llvm::Triple::mips64 ||
- ToolChain.getArch() == llvm::Triple::mips64el)
- CmdArgs.push_back("/lib64/ld.so.1");
+ 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)
@@ -5699,11 +6024,16 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const char *crtbegin;
if (Args.hasArg(options::OPT_static))
crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ else if (Args.hasArg(options::OPT_shared))
crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
else
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+
+ // Add crtfastmath.o if available and fast math is enabled.
+ ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
@@ -5728,6 +6058,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+ SanitizerArgs Sanitize(D, Args);
+
+ // Call this before we add the C++ ABI library.
+ if (Sanitize.needsUbsanRt())
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+
if (D.CCCIsCXX &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5742,8 +6078,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// Call this before we add the C run-time.
- addAsanRTLinux(getToolChain(), Args, CmdArgs);
- addTsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsAsanRt())
+ addAsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsTsanRt())
+ addTsanRTLinux(getToolChain(), Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5766,8 +6104,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostartfiles)) {
const char *crtend;
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ if (Args.hasArg(options::OPT_shared))
crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
else
crtend = isAndroid ? "crtend_android.o" : "crtend.o";
@@ -5873,7 +6213,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5917,7 +6257,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on DragonFly/pc64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 999c57a2b63a..5898c660a499 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -202,6 +202,8 @@ namespace hexagon {
namespace darwin {
+ llvm::Triple::ArchType getArchTypeForDarwinArchName(StringRef Str);
+
class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
virtual void anchor();
protected:
@@ -288,8 +290,9 @@ namespace darwin {
};
class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool {
+ bool NeedsTempPath(const InputInfoList &Inputs) const;
void AddLinkArgs(Compilation &C, const ArgList &Args,
- ArgStringList &CmdArgs) const;
+ ArgStringList &CmdArgs, const InputInfoList &Inputs) const;
public:
Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 9d8fcfd6bb44..862025ed9a1a 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -94,20 +94,6 @@ bool types::isAcceptedByClang(ID Id) {
}
}
-bool types::isOnlyAcceptedByClang(ID Id) {
- switch (Id) {
- default:
- return false;
-
- case TY_AST:
- case TY_LLVM_IR:
- case TY_LLVM_BC:
- case TY_RewrittenObjC:
- case TY_RewrittenLegacyObjC:
- return true;
- }
-}
-
bool types::isObjC(ID Id) {
switch (Id) {
default:
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index 6827034ef4ca..de2d5352b716 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -81,19 +81,15 @@ bool Windows::IsIntegratedAssemblerDefault() const {
}
bool Windows::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Windows::GetDefaultRelocationModel() const {
- return "static";
+bool Windows::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
}
-const char *Windows::GetForcedPicModel() const {
- if (getArchName() == "x86_64")
- return "pic";
- return 0;
+bool Windows::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
}
// FIXME: This probably should goto to some platform utils place.
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index d15b7a75e8f0..de96fee41618 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_ARCExtendBlockObject:
case CK_NonAtomicToAtomic:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_BuiltinFnToFnPtr:
return false;
}
}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 0f0d8352046d..882d400c4292 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -58,7 +58,7 @@ namespace {
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool TraverseDecl(Decl *D) {
- if (filterMatches(D)) {
+ if (D != NULL && filterMatches(D)) {
Out.changeColor(llvm::raw_ostream::BLUE) <<
(Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
Out.resetColor();
@@ -66,6 +66,7 @@ namespace {
D->dump(Out);
else
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ Out << "\n";
// Don't traverse child nodes to avoid output duplication.
return true;
}
@@ -89,8 +90,6 @@ namespace {
class ASTDeclNodeLister : public ASTConsumer,
public RecursiveASTVisitor<ASTDeclNodeLister> {
- typedef RecursiveASTVisitor<ASTDeclNodeLister> base;
-
public:
ASTDeclNodeLister(raw_ostream *Out = NULL)
: Out(Out ? *Out : llvm::outs()) {}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 9feb3de4f0db..31b1df43df79 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -41,8 +41,9 @@ void ASTMergeAction::ExecuteAction() {
DiagIDs(CI.getDiagnostics().getDiagnosticIDs());
for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(),
- /*ShouldOwnClient=*/false));
+ Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(),
+ CI.getDiagnostics().getClient(),
+ /*ShouldOwnClient=*/false));
ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
CI.getFileSystemOpts(), false);
if (!Unit)
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 42a67720c353..5576854a7d8b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -27,6 +27,7 @@
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
@@ -180,6 +181,14 @@ void OnDiskData::Cleanup() {
CleanPreambleFile();
}
+struct ASTUnit::ASTWriterData {
+ SmallString<128> Buffer;
+ llvm::BitstreamWriter Stream;
+ ASTWriter Writer;
+
+ ASTWriterData() : Stream(Buffer), Writer(Stream) { }
+};
+
void ASTUnit::clearFileLevelDecls() {
for (FileDeclsTy::iterator
I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I)
@@ -495,8 +504,8 @@ class ASTInfoCollector : public ASTReaderListener {
ASTContext &Context;
LangOptions &LangOpt;
HeaderSearch &HSI;
+ IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
- std::string &Predefines;
unsigned &Counter;
unsigned NumHeaderInfos;
@@ -504,54 +513,38 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
- HeaderSearch &HSI,
+ HeaderSearch &HSI,
+ IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target,
- std::string &Predefines,
unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target),
- Predefines(Predefines), Counter(Counter), NumHeaderInfos(0),
+ : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI),
+ TargetOpts(TargetOpts), Target(Target),
+ Counter(Counter), NumHeaderInfos(0),
InitializedLanguage(false) {}
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
if (InitializedLanguage)
return false;
LangOpt = LangOpts;
-
- // Initialize the preprocessor.
- PP.Initialize(*Target);
-
- // Initialize the ASTContext
- Context.InitBuiltinTypes(*Target);
-
InitializedLanguage = true;
+
+ updated();
return false;
}
- virtual bool ReadTargetTriple(StringRef Triple) {
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
// If we've already initialized the target, don't do it again.
if (Target)
return false;
- // FIXME: This is broken, we should store the TargetOptions in the AST file.
- TargetOptions TargetOpts;
- TargetOpts.ABI = "";
- TargetOpts.CXXABI = "";
- TargetOpts.CPU = "";
- TargetOpts.Features.clear();
- TargetOpts.Triple = Triple;
- Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts);
- return false;
- }
+ this->TargetOpts = new TargetOptions(TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
+ *this->TargetOpts);
- virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr) {
- Predefines = Buffers[0].Data;
- for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
- Predefines += Buffers[I].Data;
- }
+ updated();
return false;
}
@@ -559,9 +552,27 @@ public:
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
}
- virtual void ReadCounter(unsigned Value) {
+ virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {
Counter = Value;
}
+
+private:
+ void updated() {
+ if (!Target || !InitializedLanguage)
+ return;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Target->setForcedLangOptions(LangOpt);
+
+ // Initialize the preprocessor.
+ PP.Initialize(*Target);
+
+ // Initialize the ASTContext
+ Context.InitBuiltinTypes(*Target);
+ }
};
class StoredDiagnosticConsumer : public DiagnosticConsumer {
@@ -621,8 +632,10 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
StoredDiags.push_back(StoredDiagnostic(Level, Info));
}
-const std::string &ASTUnit::getOriginalSourceFileName() {
- return OriginalSourceFile;
+ASTDeserializationListener *ASTUnit::getDeserializationListener() {
+ if (WriterData)
+ return &WriterData->Writer;
+ return 0;
}
llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
@@ -638,11 +651,11 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
DiagnosticConsumer *Client = 0;
if (CaptureDiagnostics)
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin,
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
+ ArgEnd-ArgBegin,
ArgBegin, Client,
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/false);
@@ -679,7 +692,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
- AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
+ AST->HSOpts = new HeaderSearchOptions();
+
+ AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
+ AST->getFileManager(),
AST->getDiagnostics(),
AST->ASTFileLangOpts,
/*Target=*/0));
@@ -734,12 +750,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Gather Info for preprocessor construction later on.
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
- std::string Predefines;
unsigned Counter;
OwningPtr<ASTReader> Reader;
- AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts,
+ AST->PP = new Preprocessor(new PreprocessorOptions(),
+ AST->getDiagnostics(), AST->ASTFileLangOpts,
/*Target=*/0, AST->getSourceManager(), HeaderInfo,
*AST,
/*IILookup=*/0,
@@ -757,10 +773,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
/*DelayInitialization=*/true);
ASTContext &Context = *AST->Ctx;
+ bool disableValid = false;
+ if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
+ disableValid = true;
Reader.reset(new ASTReader(PP, Context,
/*isysroot=*/"",
- /*DisableValidation=*/false,
- /*DisableStatCache=*/false,
+ /*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors));
// Recover resources if we crash before exiting this method.
@@ -769,21 +787,25 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
AST->ASTFileLangOpts, HeaderInfo,
- AST->Target, Predefines, Counter));
+ AST->TargetOpts, AST->Target,
+ Counter));
- switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) {
+ switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
break;
case ASTReader::Failure:
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
return NULL;
}
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
- PP.setPredefines(Reader->getSuggestedPredefines());
PP.setCounterValue(Counter);
// Attach the AST reader to the AST context as an external AST
@@ -897,6 +919,10 @@ public:
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
handleTopLevelDecl(*it);
}
+
+ virtual ASTDeserializationListener *GetASTDeserializationListener() {
+ return Unit.getDeserializationListener();
+ }
};
class TopLevelDeclTrackerAction : public ASTFrontendAction {
@@ -1047,14 +1073,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
CCInvocation(new CompilerInvocation(*Invocation));
Clang->setInvocation(CCInvocation.getPtr());
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@@ -1070,9 +1095,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1217,7 +1242,7 @@ 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].File);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
// Check whether there is a file-file remapping of the main file
for (PreprocessorOptions::remapped_file_iterator
@@ -1267,7 +1292,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// If the main source file was not remapped, load it now.
if (!Buffer) {
- Buffer = getBufferForFile(FrontendOpts.Inputs[0].File);
+ Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile());
if (!Buffer)
return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
@@ -1429,7 +1454,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// buffer size we reserved when creating the preamble.
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
}
}
@@ -1482,7 +1507,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
- StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File;
+ StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].getFile();
Preamble.assign(FileMgr->getFile(MainFilename),
NewPreamble.first->getBufferStart(),
NewPreamble.first->getBufferStart()
@@ -1492,7 +1517,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
delete PreambleBuffer;
PreambleBuffer
= llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
NewPreamble.first->getBufferStart(), Preamble.size());
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
@@ -1500,7 +1525,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
// Remap the main source file to the preamble buffer.
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile());
PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
// Tell the compiler invocation to generate a temporary precompiled header.
@@ -1518,15 +1543,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
CICleanup(Clang.get());
Clang->setInvocation(&*PreambleInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing all of the diagnostics produced.
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
@@ -1544,9 +1568,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
// Clear out old caches and data.
@@ -1633,7 +1657,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].File);
+ FrontendOpts.Inputs[0].getFile());
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
@@ -1664,7 +1688,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
}
StringRef ASTUnit::getMainFileName() const {
- return Invocation->getFrontendOpts().Inputs[0].File;
+ return Invocation->getFrontendOpts().Inputs[0].getFile();
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
@@ -1733,9 +1757,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
CI->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
- // Save the target features.
- AST->TargetFeatures = CI->getTargetOpts().Features;
-
// Create the compiler instance to use for building the AST.
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
@@ -1744,14 +1765,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
CICleanup(Clang.get());
Clang->setInvocation(CI);
- AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
Clang->setDiagnostics(&AST->getDiagnostics());
// Create the target instance.
- Clang->getTargetOpts().Features = AST->TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget())
@@ -1765,9 +1785,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not supported here!");
// Configure the various subsystems.
@@ -1840,9 +1860,6 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
Invocation->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
- // Save the target features.
- TargetFeatures = Invocation->getTargetOpts().Features;
-
llvm::MemoryBuffer *OverrideMainBuffer = 0;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
@@ -1909,12 +1926,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool AllowPCHWithCompilerErrors,
bool SkipFunctionBodies,
bool UserFilesAreVolatile,
+ bool ForSerialization,
OwningPtr<ASTUnit> *ErrAST) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin,
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
+ ArgEnd - ArgBegin,
ArgBegin);
}
@@ -1972,6 +1990,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
+ if (ForSerialization)
+ AST->WriterData.reset(new ASTWriterData());
CI = 0; // Zero out now to ease cleanup during crash recovery.
// Recover resources if we crash before exiting this method.
@@ -2002,7 +2022,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
// Remap files.
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
- PPOpts.DisableStatCache = true;
for (PreprocessorOptions::remapped_file_buffer_iterator
R = PPOpts.remapped_file_buffer_begin(),
REnd = PPOpts.remapped_file_buffer_end();
@@ -2238,7 +2257,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
// Adjust priority based on similar type classes.
unsigned Priority = C->Priority;
- CXCursorKind CursorKind = C->Kind;
CodeCompletionString *Completion = C->Completion;
if (!Context.getPreferredType().isNull()) {
if (C->Kind == CXCursor_MacroDefinition) {
@@ -2272,12 +2290,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(),
CCP_CodePattern, C->Availability);
Builder.AddTypedTextChunk(C->Completion->getTypedText());
- CursorKind = CXCursor_NotImplemented;
Priority = CCP_CodePattern;
Completion = Builder.TakeString();
}
- AllResults.push_back(Result(Completion, Priority, CursorKind,
+ AllResults.push_back(Result(Completion, Priority, C->Kind,
C->Availability));
}
@@ -2341,7 +2358,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
CICleanup(Clang.get());
Clang->setInvocation(&*CCInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics produced.
Clang->setDiagnostics(&Diag);
@@ -2351,7 +2368,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
StoredDiagnostics);
// Create the target instance.
- Clang->getTargetOpts().Features = TargetFeatures;
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
@@ -2367,9 +2383,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
"IR inputs not support here!");
@@ -2398,8 +2414,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
= new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts);
Clang->setCodeCompletionConsumer(AugmentedConsumer);
- Clang->getFrontendOpts().SkipFunctionBodies = true;
-
// If we have a precompiled preamble, try to use it. We only allow
// the use of the precompiled preamble if we're if the completion
// point is within the main file, after the end of the precompiled
@@ -2420,7 +2434,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOpts.DisableStatCache = true;
StoredDiagnostics.insert(StoredDiagnostics.end(),
stored_diag_begin(),
stored_diag_afterDriver_begin());
@@ -2438,8 +2451,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
- // Disable the preprocessing record
- PreprocessorOpts.DetailedRecord = false;
+ // Disable the preprocessing record if modules are not enabled.
+ if (!Clang->getLangOpts().Modules)
+ PreprocessorOpts.DetailedRecord = false;
OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
@@ -2457,7 +2471,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
}
-CXSaveError ASTUnit::Save(StringRef File) {
+bool ASTUnit::Save(StringRef File) {
// Write to a temporary file and later rename it to the actual file, to avoid
// possible race conditions.
SmallString<128> TempPath;
@@ -2466,7 +2480,7 @@ CXSaveError ASTUnit::Save(StringRef File) {
int fd;
if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
/*makeAbsolute=*/false))
- return CXSaveError_Unknown;
+ return true;
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
@@ -2476,32 +2490,43 @@ CXSaveError ASTUnit::Save(StringRef File) {
Out.close();
if (Out.has_error()) {
Out.clear_error();
- return CXSaveError_Unknown;
+ return true;
}
if (llvm::sys::fs::rename(TempPath.str(), File)) {
bool exists;
llvm::sys::fs::remove(TempPath.str(), exists);
- return CXSaveError_Unknown;
+ return true;
}
- return CXSaveError_None;
+ return false;
+}
+
+static bool serializeUnit(ASTWriter &Writer,
+ SmallVectorImpl<char> &Buffer,
+ Sema &S,
+ bool hasErrors,
+ raw_ostream &OS) {
+ Writer.WriteAST(S, std::string(), 0, "", hasErrors);
+
+ // Write the generated bitstream to "Out".
+ if (!Buffer.empty())
+ OS.write(Buffer.data(), Buffer.size());
+
+ return false;
}
bool ASTUnit::serialize(raw_ostream &OS) {
bool hasErrors = getDiagnostics().hasErrorOccurred();
+ if (WriterData)
+ return serializeUnit(WriterData->Writer, WriterData->Buffer,
+ getSema(), hasErrors, OS);
+
SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
- // FIXME: Handle modules
- Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors);
-
- // Write the generated bitstream to "Out".
- if (!Buffer.empty())
- OS.write((char *)&Buffer.front(), Buffer.size());
-
- return false;
+ return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
}
typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
@@ -2761,6 +2786,85 @@ SourceLocation ASTUnit::getStartOfMainFileID() {
return SourceMgr->getLocForStartOfFile(FID);
}
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ASTUnit::getLocalPreprocessingEntities() const {
+ if (isMainFileAST()) {
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ return Reader->getModulePreprocessedEntities(Mod);
+ }
+
+ if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
+ return std::make_pair(PPRec->local_begin(), PPRec->local_end());
+
+ return std::make_pair(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
+ if (isMainFileAST()) {
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ ASTReader::ModuleDeclIterator MDI, MDE;
+ llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod);
+ for (; MDI != MDE; ++MDI) {
+ if (!Fn(context, *MDI))
+ return false;
+ }
+
+ return true;
+ }
+
+ for (ASTUnit::top_level_iterator TL = top_level_begin(),
+ TLEnd = top_level_end();
+ TL != TLEnd; ++TL) {
+ if (!Fn(context, *TL))
+ return false;
+ }
+
+ return true;
+}
+
+namespace {
+struct PCHLocatorInfo {
+ serialization::ModuleFile *Mod;
+ PCHLocatorInfo() : Mod(0) {}
+};
+}
+
+static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
+ PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData);
+ switch (M.Kind) {
+ case serialization::MK_Module:
+ return true; // skip dependencies.
+ case serialization::MK_PCH:
+ Info.Mod = &M;
+ return true; // found it.
+ case serialization::MK_Preamble:
+ return false; // look in dependencies.
+ case serialization::MK_MainFile:
+ return false; // look in dependencies.
+ }
+
+ return true;
+}
+
+const FileEntry *ASTUnit::getPCHFile() {
+ if (!Reader)
+ return 0;
+
+ PCHLocatorInfo Info;
+ Reader->getModuleManager().visit(PCHLocator, &Info);
+ if (Info.Mod)
+ return Info.Mod->File;
+
+ return 0;
+}
+
+bool ASTUnit::isModuleFile() {
+ return isMainFileAST() && !ASTFileLangOpts.CurrentModule.empty();
+}
+
void ASTUnit::PreambleData::countLines() const {
NumLines = 0;
if (empty())
diff --git a/lib/Frontend/ChainedDiagnosticConsumer.cpp b/lib/Frontend/ChainedDiagnosticConsumer.cpp
index c1d3db873f1f..d77fd180ea0d 100644
--- a/lib/Frontend/ChainedDiagnosticConsumer.cpp
+++ b/lib/Frontend/ChainedDiagnosticConsumer.cpp
@@ -1,4 +1,4 @@
-//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -*- C++ -*-===//
+//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -----------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index dbb06bd23cdc..2d586400ec46 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -39,14 +39,18 @@ static ASTReader *createASTReader(CompilerInstance &CI,
Reader->addInMemoryBuffer(sr, memBufs[ti]);
}
Reader->setDeserializationListener(deserialListener);
- switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) {
+ switch (Reader->ReadAST(pchFile, serialization::MK_PCH,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
PP.setPredefines(Reader->getSuggestedPredefines());
return Reader.take();
case ASTReader::Failure:
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
break;
}
return 0;
@@ -63,7 +67,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
assert(!includes.empty() && "No '-chain-include' in options!");
OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
- InputKind IK = CI.getFrontendOpts().Inputs[0].Kind;
+ InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
SmallVector<std::string, 4> serialBufNames;
@@ -82,14 +86,14 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
CInvok->getPreprocessorOpts().Macros.clear();
CInvok->getFrontendOpts().Inputs.clear();
- CInvok->getFrontendOpts().Inputs.push_back(FrontendInputFile(includes[i],
- IK));
+ FrontendInputFile InputFile(includes[i], IK);
+ CInvok->getFrontendOpts().Inputs.push_back(InputFile);
TextDiagnosticPrinter *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
Clang->setInvocation(CInvok.take());
@@ -108,6 +112,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
OwningPtr<ASTConsumer> consumer;
consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
/*isysroot=*/"", &OS));
+ Clang->getPreprocessor().setPPMutationListener(
+ consumer->GetPPMutationListener());
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
Clang->setASTConsumer(consumer.take());
@@ -141,7 +147,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
Clang->getASTContext().setExternalSource(Reader);
}
- if (!Clang->InitializeSourceManager(includes[i]))
+ if (!Clang->InitializeSourceManager(InputFile))
return 0;
ParseAST(Clang->getSema());
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 6de153107f3b..22a74fcc35d9 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -52,6 +52,7 @@ CompilerInstance::CompilerInstance()
}
CompilerInstance::~CompilerInstance() {
+ assert(OutputFiles.empty() && "Still output files in flight?");
}
void CompilerInstance::setInvocation(CompilerInvocation *Value) {
@@ -88,19 +89,18 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
- getFrontendOpts().SkipFunctionBodies = Value != 0;
}
// Diagnostics
-static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
+static void SetUpBuildDumpLog(DiagnosticOptions *DiagOpts,
unsigned argc, const char* const *argv,
DiagnosticsEngine &Diags) {
std::string ErrorInfo;
OwningPtr<raw_ostream> OS(
- new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
+ new llvm::raw_fd_ostream(DiagOpts->DumpBuildInformation.c_str(),ErrorInfo));
if (!ErrorInfo.empty()) {
Diags.Report(diag::err_fe_unable_to_open_logfile)
- << DiagOpts.DumpBuildInformation << ErrorInfo;
+ << DiagOpts->DumpBuildInformation << ErrorInfo;
return;
}
@@ -115,20 +115,20 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
-static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
+static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
const CodeGenOptions *CodeGenOpts,
DiagnosticsEngine &Diags) {
std::string ErrorInfo;
bool OwnsStream = false;
raw_ostream *OS = &llvm::errs();
- if (DiagOpts.DiagnosticLogFile != "-") {
+ if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
llvm::raw_fd_ostream *FileOS(
- new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(),
+ new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(),
ErrorInfo, llvm::raw_fd_ostream::F_Append));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
- << DiagOpts.DumpBuildInformation << ErrorInfo;
+ << DiagOpts->DumpBuildInformation << ErrorInfo;
} else {
FileOS->SetUnbuffered();
FileOS->SetUseAtomicWrites(true);
@@ -145,7 +145,7 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
-static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts,
+static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
DiagnosticsEngine &Diags,
StringRef OutputFile) {
std::string ErrorInfo;
@@ -171,13 +171,13 @@ void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient) {
- Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client,
ShouldOwnClient, ShouldCloneClient,
&getCodeGenOpts());
}
IntrusiveRefCntPtr<DiagnosticsEngine>
-CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
+CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
@@ -185,7 +185,7 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
const CodeGenOptions *CodeGenOpts) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(new DiagnosticsEngine(DiagID));
+ Diags(new DiagnosticsEngine(DiagID, Opts));
// Create the diagnostic client for reporting errors or for
// implementing -verify.
@@ -198,22 +198,22 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
// Chain in -verify checker, if requested.
- if (Opts.VerifyDiagnostics)
+ if (Opts->VerifyDiagnostics)
Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
// Chain in -diagnostic-log-file dumper, if requested.
- if (!Opts.DiagnosticLogFile.empty())
+ if (!Opts->DiagnosticLogFile.empty())
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
- if (!Opts.DumpBuildInformation.empty())
+ if (!Opts->DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
- if (!Opts.DiagnosticSerializationFile.empty())
+ if (!Opts->DiagnosticSerializationFile.empty())
SetupSerializedDiagnostics(Opts, *Diags,
- Opts.DiagnosticSerializationFile);
+ Opts->DiagnosticSerializationFile);
// Configure our handling of diagnostics.
- ProcessWarningOptions(*Diags, Opts);
+ ProcessWarningOptions(*Diags, *Opts);
return Diags;
}
@@ -241,11 +241,13 @@ void CompilerInstance::createPreprocessor() {
PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
// Create the Preprocessor.
- HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(),
+ HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(),
+ getFileManager(),
getDiagnostics(),
getLangOpts(),
&getTarget());
- PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
+ PP = new Preprocessor(&getPreprocessorOpts(),
+ getDiagnostics(), getLangOpts(), &getTarget(),
getSourceManager(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true);
@@ -306,14 +308,12 @@ void CompilerInstance::createASTContext() {
void CompilerInstance::createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
void *DeserializationListener){
OwningPtr<ExternalASTSource> Source;
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
DisablePCHValidation,
- DisableStatCache,
AllowPCHWithCompilerErrors,
getPreprocessor(), getASTContext(),
DeserializationListener,
@@ -326,7 +326,6 @@ ExternalASTSource *
CompilerInstance::createPCHExternalASTSource(StringRef Path,
const std::string &Sysroot,
bool DisablePCHValidation,
- bool DisableStatCache,
bool AllowPCHWithCompilerErrors,
Preprocessor &PP,
ASTContext &Context,
@@ -335,14 +334,15 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- DisablePCHValidation, DisableStatCache,
+ DisablePCHValidation,
AllowPCHWithCompilerErrors));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
- : serialization::MK_PCH)) {
+ : serialization::MK_PCH,
+ ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
@@ -353,7 +353,10 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Unrecoverable failure: don't even try to process the input file.
break;
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate:
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
// No suitable PCH file could be found. Return an error.
break;
}
@@ -586,19 +589,29 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
// Initialization Utilities
-bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind){
- return InitializeSourceManager(InputFile, Kind, getDiagnostics(),
+bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){
+ return InitializeSourceManager(Input, getDiagnostics(),
getFileManager(), getSourceManager(),
getFrontendOpts());
}
-bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
- SrcMgr::CharacteristicKind Kind,
+bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
const FrontendOptions &Opts) {
+ SrcMgr::CharacteristicKind
+ Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+
+ if (Input.isBuffer()) {
+ SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind);
+ assert(!SourceMgr.getMainFileID().isInvalid() &&
+ "Couldn't establish MainFileID!");
+ return true;
+ }
+
+ StringRef InputFile = Input.getFile();
+
// Figure out where to get and map in the main file.
if (InputFile != "-") {
const FileEntry *File = FileMgr.getFile(InputFile);
@@ -607,6 +620,19 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
return false;
}
SourceMgr.createMainFileID(File, Kind);
+
+ // 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.
+ 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();
+ return false;
+ }
+ SourceMgr.overrideFileContents(File, MB.take());
+ }
} else {
OwningPtr<llvm::MemoryBuffer> SB;
if (llvm::MemoryBuffer::getSTDIN(SB)) {
@@ -746,7 +772,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Someone else is responsible for building the module. Wait for them to
// finish.
Locked.waitForUnlock();
- break;
+ return;
}
ModuleMap &ModMap
@@ -836,6 +862,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// FIXME: Even though we're executing under crash protection, it would still
// 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();
}
@@ -939,13 +966,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
ModuleManager = new ASTReader(getPreprocessor(), *Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- PPOpts.DisableStatCache);
+ PPOpts.DisablePCHValidation);
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
getASTConsumer().GetASTDeserializationListener());
getASTContext().setASTMutationListener(
getASTConsumer().GetASTMutationListener());
+ getPreprocessor().setPPMutationListener(
+ getASTConsumer().GetPPMutationListener());
}
OwningPtr<ExternalASTSource> Source;
Source.reset(ModuleManager);
@@ -957,12 +985,39 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Try to load the module we found.
+ unsigned ARRFlags = ASTReader::ARR_None;
+ if (Module)
+ ARRFlags |= ASTReader::ARR_OutOfDate;
switch (ModuleManager->ReadAST(ModuleFile->getName(),
- serialization::MK_Module)) {
+ serialization::MK_Module,
+ ARRFlags)) {
case ASTReader::Success:
break;
- case ASTReader::IgnorePCH:
+ case ASTReader::OutOfDate: {
+ // The module file is out-of-date. Rebuild it.
+ getFileManager().invalidateCache(ModuleFile);
+ bool Existed;
+ llvm::sys::fs::remove(ModuleFileName, Existed);
+ compileModule(*this, Module, ModuleFileName);
+
+ // Try loading the module again.
+ ModuleFile = FileMgr->getFile(ModuleFileName);
+ if (!ModuleFile ||
+ ModuleManager->ReadAST(ModuleFileName,
+ serialization::MK_Module,
+ ASTReader::ARR_None) != ASTReader::Success) {
+ KnownModules[Path[0].first] = 0;
+ return 0;
+ }
+
+ // Okay, we've rebuilt and now loaded the module.
+ break;
+ }
+
+ case ASTReader::VersionMismatch:
+ case ASTReader::ConfigurationMismatch:
+ case ASTReader::HadErrors:
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = 0;
@@ -980,6 +1035,9 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
Module = PP->getHeaderSearchInfo().getModuleMap()
.findModule((Path[0].first->getName()));
}
+
+ if (Module)
+ Module->setASTFile(ModuleFile);
// Cache the result of this top-level module lookup for later.
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
@@ -1079,9 +1137,12 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
- TU->addDecl(ImportDecl::CreateImplicit(getASTContext(), TU,
- ImportLoc, Module,
- Path.back().second));
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ ImportLoc, Module,
+ Path.back().second);
+ TU->addDecl(ImportD);
+ if (Consumer)
+ Consumer->HandleImplicitImportDecl(ImportD);
}
LastModuleImportLoc = ImportLoc;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d39679caf13e..b9c198b11191 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
@@ -20,6 +21,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
@@ -35,917 +37,21 @@ using namespace clang;
//===----------------------------------------------------------------------===//
CompilerInvocationBase::CompilerInvocationBase()
- : LangOpts(new LangOptions()) {}
+ : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
+ DiagnosticOpts(new DiagnosticOptions()),
+ HeaderSearchOpts(new HeaderSearchOptions()),
+ PreprocessorOpts(new PreprocessorOptions()) {}
CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
: RefCountedBase<CompilerInvocation>(),
- LangOpts(new LangOptions(*X.getLangOpts())) {}
+ LangOpts(new LangOptions(*X.getLangOpts())),
+ TargetOpts(new TargetOptions(X.getTargetOpts())),
+ DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
+ HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
+ PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {}
//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static const char *getAnalysisStoreName(AnalysisStores Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis store!");
-#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
- case NAME##Model: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis constraints!");
-#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
- case NAME##Model: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis client!");
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
- case PD_##NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis purge mode!");
-#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis ipa mode!");
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-static const char *
- getAnalysisInliningModeName(AnalysisInliningMode Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis inlining mode!");
-#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \
- case NAME: return CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Serialization (to args)
-//===----------------------------------------------------------------------===//
-
-namespace {
- /// ToArgsList - Helper class to create a list of std::strings.
- class ToArgsList {
- std::vector<std::string> &Res;
- public:
- explicit ToArgsList(std::vector<std::string> &Res) : Res(Res) {}
-
- void push_back(StringRef Str) {
- // Avoid creating a temporary string.
- Res.push_back(std::string());
- Res.back().assign(Str.data(), Str.size());
- }
-
- void push_back(StringRef Str1, StringRef Str2) {
- push_back(Str1);
- push_back(Str2);
- }
- };
-}
-
-static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) {
- if (Opts.ShowCheckerHelp)
- Res.push_back("-analyzer-checker-help");
- if (Opts.AnalysisStoreOpt != RegionStoreModel)
- Res.push_back("-analyzer-store",
- getAnalysisStoreName(Opts.AnalysisStoreOpt));
- if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel)
- Res.push_back("-analyzer-constraints",
- getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
- if (Opts.AnalysisDiagOpt != PD_HTML)
- Res.push_back("-analyzer-output",
- getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
- if (Opts.AnalysisPurgeOpt != PurgeStmt)
- Res.push_back("-analyzer-purge",
- getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
- if (!Opts.AnalyzeSpecificFunction.empty())
- Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction);
- if (Opts.IPAMode != Inlining)
- Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode));
- if (Opts.InliningMode != NoRedundancy)
- Res.push_back("-analyzer-inlining-mode",
- getAnalysisInliningModeName(Opts.InliningMode));
-
- if (Opts.AnalyzeAll)
- Res.push_back("-analyzer-opt-analyze-headers");
- if (Opts.AnalyzerDisplayProgress)
- Res.push_back("-analyzer-display-progress");
- if (Opts.AnalyzeNestedBlocks)
- Res.push_back("-analyzer-opt-analyze-nested-blocks");
- if (Opts.EagerlyAssume)
- Res.push_back("-analyzer-eagerly-assume");
- if (Opts.TrimGraph)
- Res.push_back("-trim-egraph");
- if (Opts.VisualizeEGDot)
- Res.push_back("-analyzer-viz-egraph-graphviz");
- if (Opts.VisualizeEGUbi)
- Res.push_back("-analyzer-viz-egraph-ubigraph");
- if (Opts.NoRetryExhausted)
- Res.push_back("-analyzer-disable-retry-exhausted");
-
- for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) {
- const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i];
- if (opt.second)
- Res.push_back("-analyzer-disable-checker");
- else
- Res.push_back("-analyzer-checker");
- Res.push_back(opt.first);
- }
-}
-
-static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) {
- switch (Opts.DebugInfo) {
- case CodeGenOptions::NoDebugInfo:
- break;
- case CodeGenOptions::DebugLineTablesOnly:
- Res.push_back("-gline-tables-only");
- break;
- case CodeGenOptions::LimitedDebugInfo:
- Res.push_back("-g");
- Res.push_back("-flimit-debug-info");
- break;
- case CodeGenOptions::FullDebugInfo:
- Res.push_back("-g");
- Res.push_back("-fno-limit-debug-info");
- break;
- }
- if (Opts.DisableLLVMOpts)
- Res.push_back("-disable-llvm-optzns");
- if (Opts.DisableRedZone)
- Res.push_back("-disable-red-zone");
- if (Opts.DisableTailCalls)
- Res.push_back("-mdisable-tail-calls");
- if (!Opts.DebugCompilationDir.empty())
- Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir);
- if (!Opts.DwarfDebugFlags.empty())
- Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags);
- if (Opts.EmitGcovArcs)
- Res.push_back("-femit-coverage-data");
- if (Opts.EmitGcovNotes)
- Res.push_back("-femit-coverage-notes");
- if (Opts.EmitOpenCLArgMetadata)
- Res.push_back("-cl-kernel-arg-info");
- if (!Opts.MergeAllConstants)
- Res.push_back("-fno-merge-all-constants");
- if (Opts.NoCommon)
- Res.push_back("-fno-common");
- if (Opts.ForbidGuardVariables)
- Res.push_back("-fforbid-guard-variables");
- if (Opts.UseRegisterSizedBitfieldAccess)
- Res.push_back("-fuse-register-sized-bitfield-access");
- if (Opts.NoImplicitFloat)
- Res.push_back("-no-implicit-float");
- if (Opts.OmitLeafFramePointer)
- Res.push_back("-momit-leaf-frame-pointer");
- if (Opts.OptimizeSize) {
- assert(Opts.OptimizationLevel == 2 && "Invalid options!");
- Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz");
- } else if (Opts.OptimizationLevel != 0)
- Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
- if (!Opts.MainFileName.empty())
- Res.push_back("-main-file-name", Opts.MainFileName);
- if (Opts.NoInfsFPMath)
- Res.push_back("-menable-no-infinities");
- if (Opts.NoNaNsFPMath)
- Res.push_back("-menable-no-nans");
- // SimplifyLibCalls is only derived.
- // TimePasses is only derived.
- // UnitAtATime is unused.
- // Inlining is only derived.
-
- // UnrollLoops is derived, but also accepts an option, no
- // harm in pushing it back here.
- if (Opts.UnrollLoops)
- Res.push_back("-funroll-loops");
- if (Opts.DataSections)
- Res.push_back("-fdata-sections");
- if (Opts.FunctionSections)
- Res.push_back("-ffunction-sections");
- if (Opts.AsmVerbose)
- Res.push_back("-masm-verbose");
- if (!Opts.CodeModel.empty())
- Res.push_back("-mcode-model", Opts.CodeModel);
- if (Opts.CUDAIsDevice)
- Res.push_back("-fcuda-is-device");
- if (!Opts.CXAAtExit)
- Res.push_back("-fno-use-cxa-atexit");
- if (Opts.CXXCtorDtorAliases)
- Res.push_back("-mconstructor-aliases");
- if (Opts.ObjCAutoRefCountExceptions)
- Res.push_back("-fobjc-arc-eh");
- if (!Opts.DebugPass.empty()) {
- Res.push_back("-mdebug-pass", Opts.DebugPass);
- }
- if (Opts.DisableFPElim)
- Res.push_back("-mdisable-fp-elim");
- if (!Opts.FloatABI.empty())
- Res.push_back("-mfloat-abi", Opts.FloatABI);
- if (!Opts.LimitFloatPrecision.empty())
- Res.push_back("-mlimit-float-precision", Opts.LimitFloatPrecision);
- if (Opts.NoZeroInitializedInBSS)
- Res.push_back("-mno-zero-initialized-bss");
- switch (Opts.getObjCDispatchMethod()) {
- case CodeGenOptions::Legacy:
- break;
- case CodeGenOptions::Mixed:
- Res.push_back("-fobjc-dispatch-method=mixed");
- break;
- case CodeGenOptions::NonLegacy:
- Res.push_back("-fobjc-dispatch-method=non-legacy");
- break;
- }
- if (Opts.BoundsChecking > 0)
- Res.push_back("-fbounds-checking=" + llvm::utostr(Opts.BoundsChecking));
- if (Opts.NumRegisterParameters)
- Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters));
- if (Opts.NoGlobalMerge)
- Res.push_back("-mno-global-merge");
- if (Opts.NoExecStack)
- Res.push_back("-mnoexecstack");
- if (Opts.RelaxAll)
- Res.push_back("-mrelax-all");
- if (Opts.SaveTempLabels)
- Res.push_back("-msave-temp-labels");
- if (Opts.NoDwarf2CFIAsm)
- Res.push_back("-fno-dwarf2-cfi-asm");
- if (Opts.NoDwarfDirectoryAsm)
- Res.push_back("-fno-dwarf-directory-asm");
- if (Opts.SoftFloat)
- Res.push_back("-msoft-float");
- if (Opts.StrictEnums)
- Res.push_back("-fstrict-enums");
- if (Opts.UnwindTables)
- Res.push_back("-munwind-tables");
- if (Opts.RelocationModel != "pic")
- Res.push_back("-mrelocation-model", Opts.RelocationModel);
- if (!Opts.VerifyModule)
- Res.push_back("-disable-llvm-verifier");
- for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i)
- Res.push_back("-backend-option", Opts.BackendOptions[i]);
-
- switch (Opts.DefaultTLSModel) {
- case CodeGenOptions::GeneralDynamicTLSModel:
- break;
- case CodeGenOptions::LocalDynamicTLSModel:
- Res.push_back("-ftls-model=local-dynamic");
- break;
- case CodeGenOptions::InitialExecTLSModel:
- Res.push_back("-ftls-model=initial-exec");
- break;
- case CodeGenOptions::LocalExecTLSModel:
- Res.push_back("-ftls-model=local-exec");
- break;
- }
-}
-
-static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IncludeSystemHeaders)
- Res.push_back("-sys-header-deps");
- if (Opts.ShowHeaderIncludes)
- Res.push_back("-H");
- if (!Opts.HeaderIncludeOutputFile.empty())
- Res.push_back("-header-include-file", Opts.HeaderIncludeOutputFile);
- if (Opts.UsePhonyTargets)
- Res.push_back("-MP");
- if (!Opts.OutputFile.empty())
- Res.push_back("-dependency-file", Opts.OutputFile);
- for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i)
- Res.push_back("-MT", Opts.Targets[i]);
-}
-
-static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IgnoreWarnings)
- Res.push_back("-w");
- if (Opts.NoRewriteMacros)
- Res.push_back("-Wno-rewrite-macros");
- if (Opts.Pedantic)
- Res.push_back("-pedantic");
- if (Opts.PedanticErrors)
- Res.push_back("-pedantic-errors");
- if (!Opts.ShowColumn)
- Res.push_back("-fno-show-column");
- if (!Opts.ShowLocation)
- Res.push_back("-fno-show-source-location");
- if (!Opts.ShowCarets)
- Res.push_back("-fno-caret-diagnostics");
- if (!Opts.ShowFixits)
- Res.push_back("-fno-diagnostics-fixit-info");
- if (Opts.ShowSourceRanges)
- Res.push_back("-fdiagnostics-print-source-range-info");
- if (Opts.ShowParseableFixits)
- Res.push_back("-fdiagnostics-parseable-fixits");
- if (Opts.ShowColors)
- Res.push_back("-fcolor-diagnostics");
- if (Opts.VerifyDiagnostics)
- Res.push_back("-verify");
- if (Opts.ShowOptionNames)
- Res.push_back("-fdiagnostics-show-option");
- if (Opts.ShowCategories == 1)
- Res.push_back("-fdiagnostics-show-category=id");
- else if (Opts.ShowCategories == 2)
- Res.push_back("-fdiagnostics-show-category=name");
- switch (Opts.Format) {
- case DiagnosticOptions::Clang:
- Res.push_back("-fdiagnostics-format=clang"); break;
- case DiagnosticOptions::Msvc:
- Res.push_back("-fdiagnostics-format=msvc"); break;
- case DiagnosticOptions::Vi:
- Res.push_back("-fdiagnostics-format=vi"); break;
- }
- if (Opts.ErrorLimit)
- Res.push_back("-ferror-limit", llvm::utostr(Opts.ErrorLimit));
- if (!Opts.DiagnosticLogFile.empty())
- Res.push_back("-diagnostic-log-file", Opts.DiagnosticLogFile);
- if (Opts.MacroBacktraceLimit
- != DiagnosticOptions::DefaultMacroBacktraceLimit)
- Res.push_back("-fmacro-backtrace-limit",
- llvm::utostr(Opts.MacroBacktraceLimit));
- if (Opts.TemplateBacktraceLimit
- != DiagnosticOptions::DefaultTemplateBacktraceLimit)
- Res.push_back("-ftemplate-backtrace-limit",
- llvm::utostr(Opts.TemplateBacktraceLimit));
- if (Opts.ConstexprBacktraceLimit
- != DiagnosticOptions::DefaultConstexprBacktraceLimit)
- Res.push_back("-fconstexpr-backtrace-limit",
- llvm::utostr(Opts.ConstexprBacktraceLimit));
-
- if (Opts.TabStop != DiagnosticOptions::DefaultTabStop)
- Res.push_back("-ftabstop", llvm::utostr(Opts.TabStop));
- if (Opts.MessageLength)
- Res.push_back("-fmessage-length", llvm::utostr(Opts.MessageLength));
- if (!Opts.DumpBuildInformation.empty())
- Res.push_back("-dump-build-information", Opts.DumpBuildInformation);
- for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
- Res.push_back("-W" + Opts.Warnings[i]);
-}
-
-static const char *getInputKindName(InputKind Kind) {
- switch (Kind) {
- case IK_None: break;
- case IK_AST: return "ast";
- case IK_Asm: return "assembler-with-cpp";
- case IK_C: return "c";
- case IK_CXX: return "c++";
- case IK_LLVM_IR: return "ir";
- case IK_ObjC: return "objective-c";
- case IK_ObjCXX: return "objective-c++";
- case IK_OpenCL: return "cl";
- case IK_CUDA: return "cuda";
- case IK_PreprocessedC: return "cpp-output";
- case IK_PreprocessedCXX: return "c++-cpp-output";
- case IK_PreprocessedObjC: return "objective-c-cpp-output";
- case IK_PreprocessedObjCXX:return "objective-c++-cpp-output";
- }
-
- llvm_unreachable("Unexpected language kind!");
-}
-
-static const char *getActionName(frontend::ActionKind Kind) {
- switch (Kind) {
- case frontend::PluginAction:
- llvm_unreachable("Invalid kind!");
-
- case frontend::ASTDeclList: return "-ast-list";
- case frontend::ASTDump: return "-ast-dump";
- case frontend::ASTDumpXML: return "-ast-dump-xml";
- case frontend::ASTPrint: return "-ast-print";
- case frontend::ASTView: return "-ast-view";
- case frontend::DumpRawTokens: return "-dump-raw-tokens";
- case frontend::DumpTokens: return "-dump-tokens";
- case frontend::EmitAssembly: return "-S";
- case frontend::EmitBC: return "-emit-llvm-bc";
- case frontend::EmitHTML: return "-emit-html";
- case frontend::EmitLLVM: return "-emit-llvm";
- case frontend::EmitLLVMOnly: return "-emit-llvm-only";
- case frontend::EmitCodeGenOnly: return "-emit-codegen-only";
- case frontend::EmitObj: return "-emit-obj";
- case frontend::FixIt: return "-fixit";
- case frontend::GenerateModule: return "-emit-module";
- case frontend::GeneratePCH: return "-emit-pch";
- case frontend::GeneratePTH: return "-emit-pth";
- case frontend::InitOnly: return "-init-only";
- case frontend::ParseSyntaxOnly: return "-fsyntax-only";
- case frontend::PrintDeclContext: return "-print-decl-contexts";
- case frontend::PrintPreamble: return "-print-preamble";
- case frontend::PrintPreprocessedInput: return "-E";
- case frontend::RewriteMacros: return "-rewrite-macros";
- case frontend::RewriteObjC: return "-rewrite-objc";
- case frontend::RewriteTest: return "-rewrite-test";
- case frontend::RunAnalysis: return "-analyze";
- case frontend::MigrateSource: return "-migrate";
- case frontend::RunPreprocessorOnly: return "-Eonly";
- }
-
- llvm_unreachable("Unexpected language kind!");
-}
-
-static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res){
- if (!Opts.WorkingDir.empty())
- Res.push_back("-working-directory", Opts.WorkingDir);
-}
-
-static void CodeCompleteOptionsToArgs(const CodeCompleteOptions &Opts,
- ToArgsList &Res) {
- if (Opts.IncludeMacros)
- Res.push_back("-code-completion-macros");
- if (Opts.IncludeCodePatterns)
- Res.push_back("-code-completion-patterns");
- if (!Opts.IncludeGlobals)
- Res.push_back("-no-code-completion-globals");
- if (Opts.IncludeBriefComments)
- Res.push_back("-code-completion-brief-comments");
-}
-
-static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) {
- if (Opts.DisableFree)
- Res.push_back("-disable-free");
- if (Opts.RelocatablePCH)
- Res.push_back("-relocatable-pch");
- if (Opts.ShowHelp)
- Res.push_back("-help");
- if (Opts.ShowStats)
- Res.push_back("-print-stats");
- if (Opts.ShowTimers)
- Res.push_back("-ftime-report");
- if (Opts.ShowVersion)
- Res.push_back("-version");
- if (Opts.FixWhatYouCan)
- Res.push_back("-fix-what-you-can");
- if (Opts.FixOnlyWarnings)
- Res.push_back("-fix-only-warnings");
- if (Opts.FixAndRecompile)
- Res.push_back("-fixit-recompile");
- if (Opts.FixToTemporaries)
- Res.push_back("-fixit-to-temporary");
- switch (Opts.ARCMTAction) {
- case FrontendOptions::ARCMT_None:
- break;
- case FrontendOptions::ARCMT_Check:
- Res.push_back("-arcmt-check");
- break;
- case FrontendOptions::ARCMT_Modify:
- Res.push_back("-arcmt-modify");
- break;
- case FrontendOptions::ARCMT_Migrate:
- Res.push_back("-arcmt-migrate");
- break;
- }
- CodeCompleteOptionsToArgs(Opts.CodeCompleteOpts, Res);
- if (!Opts.MTMigrateDir.empty())
- Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir);
- if (!Opts.ARCMTMigrateReportOut.empty())
- Res.push_back("-arcmt-migrate-report-output", Opts.ARCMTMigrateReportOut);
- if (Opts.ARCMTMigrateEmitARCErrors)
- Res.push_back("-arcmt-migrate-emit-errors");
-
- if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals)
- Res.push_back("-objcmt-migrate-literals");
- if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting)
- Res.push_back("-objcmt-migrate-subscripting");
-
- bool NeedLang = false;
- for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
- if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) !=
- Opts.Inputs[i].Kind)
- NeedLang = true;
- if (NeedLang)
- Res.push_back("-x", getInputKindName(Opts.Inputs[0].Kind));
- for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
- assert((!NeedLang || Opts.Inputs[i].Kind == Opts.Inputs[0].Kind) &&
- "Unable to represent this input vector!");
- Res.push_back(Opts.Inputs[i].File);
- }
-
- if (!Opts.OutputFile.empty())
- Res.push_back("-o", Opts.OutputFile);
- if (!Opts.CodeCompletionAt.FileName.empty())
- Res.push_back("-code-completion-at",
- Opts.CodeCompletionAt.FileName + ":" +
- llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
- llvm::utostr(Opts.CodeCompletionAt.Column));
- if (Opts.ProgramAction != frontend::PluginAction)
- Res.push_back(getActionName(Opts.ProgramAction));
- if (!Opts.ActionName.empty()) {
- Res.push_back("-plugin", Opts.ActionName);
- for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i)
- Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]);
- }
- if (!Opts.ASTDumpFilter.empty())
- Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter);
- for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i)
- Res.push_back("-load", Opts.Plugins[i]);
- for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
- Res.push_back("-add-plugin", Opts.AddPluginActions[i]);
- for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai)
- Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i],
- Opts.AddPluginArgs[i][ai]);
- }
- for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i)
- Res.push_back("-ast-merge", Opts.ASTMergeFiles[i]);
- for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i)
- Res.push_back("-mllvm", Opts.LLVMArgs[i]);
- if (!Opts.OverrideRecordLayoutsFile.empty())
- Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile);
-}
-
-static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
- ToArgsList &Res) {
- if (Opts.Sysroot != "/") {
- Res.push_back("-isysroot");
- Res.push_back(Opts.Sysroot);
- }
-
- /// User specified include entries.
- for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
- const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
- if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
- llvm::report_fatal_error("Invalid option set!");
- if (E.IsUserSupplied) {
- switch (E.Group) {
- case frontend::After:
- Res.push_back("-idirafter");
- break;
-
- case frontend::Quoted:
- Res.push_back("-iquote");
- break;
-
- case frontend::System:
- Res.push_back("-isystem");
- break;
-
- case frontend::IndexHeaderMap:
- Res.push_back("-index-header-map");
- Res.push_back(E.IsFramework? "-F" : "-I");
- break;
-
- case frontend::CSystem:
- Res.push_back("-c-isystem");
- break;
-
- case frontend::CXXSystem:
- Res.push_back("-cxx-isystem");
- break;
-
- case frontend::ObjCSystem:
- Res.push_back("-objc-isystem");
- break;
-
- case frontend::ObjCXXSystem:
- Res.push_back("-objcxx-isystem");
- break;
-
- case frontend::Angled:
- Res.push_back(E.IsFramework ? "-F" : "-I");
- break;
- }
- } else {
- if (E.IsInternal) {
- assert(E.Group == frontend::System && "Unexpected header search group");
- if (E.ImplicitExternC)
- Res.push_back("-internal-externc-isystem");
- else
- Res.push_back("-internal-isystem");
- } else {
- if (E.Group != frontend::Angled && E.Group != frontend::System)
- llvm::report_fatal_error("Invalid option set!");
- Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
- "-iwithprefix");
- }
- }
- Res.push_back(E.Path);
- }
-
- /// User-specified system header prefixes.
- for (unsigned i = 0, e = Opts.SystemHeaderPrefixes.size(); i != e; ++i) {
- if (Opts.SystemHeaderPrefixes[i].IsSystemHeader)
- Res.push_back("-isystem-prefix");
- else
- Res.push_back("-ino-system-prefix");
-
- Res.push_back(Opts.SystemHeaderPrefixes[i].Prefix);
- }
-
- if (!Opts.ResourceDir.empty())
- Res.push_back("-resource-dir", Opts.ResourceDir);
- if (!Opts.ModuleCachePath.empty())
- Res.push_back("-fmodule-cache-path", Opts.ModuleCachePath);
- if (!Opts.UseStandardSystemIncludes)
- Res.push_back("-nostdsysteminc");
- if (!Opts.UseStandardCXXIncludes)
- Res.push_back("-nostdinc++");
- if (Opts.UseLibcxx)
- Res.push_back("-stdlib=libc++");
- if (Opts.Verbose)
- Res.push_back("-v");
-}
-
-static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) {
- LangOptions DefaultLangOpts;
-
- // FIXME: Need to set -std to get all the implicit options.
-
- // FIXME: We want to only pass options relative to the defaults, which
- // requires constructing a target. :(
- //
- // It would be better to push the all target specific choices into the driver,
- // so that everything below that was more uniform.
-
- if (Opts.Trigraphs)
- Res.push_back("-trigraphs");
- // Implicit based on the input kind:
- // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL
- // Implicit based on the input language standard:
- // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
- if (Opts.DollarIdents)
- Res.push_back("-fdollars-in-identifiers");
- if (Opts.GNUMode && !Opts.GNUKeywords)
- Res.push_back("-fno-gnu-keywords");
- if (!Opts.GNUMode && Opts.GNUKeywords)
- Res.push_back("-fgnu-keywords");
- if (Opts.MicrosoftExt)
- Res.push_back("-fms-extensions");
- if (Opts.MicrosoftMode)
- Res.push_back("-fms-compatibility");
- if (Opts.MSCVersion != 0)
- Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
- if (Opts.Borland)
- Res.push_back("-fborland-extensions");
- if (Opts.ObjCDefaultSynthProperties)
- Res.push_back("-fobjc-default-synthesize-properties");
- // NoInline is implicit.
- if (!Opts.CXXOperatorNames)
- Res.push_back("-fno-operator-names");
- if (Opts.PascalStrings)
- Res.push_back("-fpascal-strings");
- if (Opts.CatchUndefined)
- Res.push_back("-fcatch-undefined-behavior");
- if (Opts.AddressSanitizer)
- Res.push_back("-faddress-sanitizer");
- if (Opts.ThreadSanitizer)
- Res.push_back("-fthread-sanitizer");
- if (Opts.WritableStrings)
- Res.push_back("-fwritable-strings");
- if (Opts.ConstStrings)
- Res.push_back("-fconst-strings");
- if (!Opts.LaxVectorConversions)
- Res.push_back("-fno-lax-vector-conversions");
- if (Opts.AltiVec)
- Res.push_back("-faltivec");
- if (Opts.Exceptions)
- Res.push_back("-fexceptions");
- if (Opts.ObjCExceptions)
- Res.push_back("-fobjc-exceptions");
- if (Opts.CXXExceptions)
- Res.push_back("-fcxx-exceptions");
- if (Opts.SjLjExceptions)
- Res.push_back("-fsjlj-exceptions");
- if (Opts.TraditionalCPP)
- Res.push_back("-traditional-cpp");
- if (!Opts.RTTI)
- Res.push_back("-fno-rtti");
- if (Opts.MSBitfields)
- Res.push_back("-mms-bitfields");
- if (Opts.Freestanding)
- Res.push_back("-ffreestanding");
- if (Opts.NoBuiltin)
- Res.push_back("-fno-builtin");
- if (!Opts.AssumeSaneOperatorNew)
- Res.push_back("-fno-assume-sane-operator-new");
- if (!Opts.ThreadsafeStatics)
- Res.push_back("-fno-threadsafe-statics");
- if (Opts.POSIXThreads)
- Res.push_back("-pthread");
- if (Opts.Blocks)
- Res.push_back("-fblocks");
- if (Opts.BlocksRuntimeOptional)
- Res.push_back("-fblocks-runtime-optional");
- if (Opts.Modules)
- Res.push_back("-fmodules");
- if (Opts.EmitAllDecls)
- Res.push_back("-femit-all-decls");
- if (Opts.MathErrno)
- Res.push_back("-fmath-errno");
- switch (Opts.getSignedOverflowBehavior()) {
- case LangOptions::SOB_Undefined: break;
- case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break;
- case LangOptions::SOB_Trapping:
- Res.push_back("-ftrapv");
- if (!Opts.OverflowHandler.empty())
- Res.push_back("-ftrapv-handler", Opts.OverflowHandler);
- break;
- }
- switch (Opts.getFPContractMode()) {
- case LangOptions::FPC_Off: Res.push_back("-ffp-contract=off"); break;
- case LangOptions::FPC_On: Res.push_back("-ffp-contract=on"); break;
- case LangOptions::FPC_Fast: Res.push_back("-ffp-contract=fast"); break;
- }
- if (Opts.HeinousExtensions)
- Res.push_back("-fheinous-gnu-extensions");
- // Optimize is implicit.
- // OptimizeSize is implicit.
- if (Opts.FastMath)
- Res.push_back("-ffast-math");
- if (Opts.Static)
- Res.push_back("-static-define");
- if (Opts.DumpRecordLayoutsSimple)
- Res.push_back("-fdump-record-layouts-simple");
- else if (Opts.DumpRecordLayouts)
- Res.push_back("-fdump-record-layouts");
- if (Opts.DumpVTableLayouts)
- Res.push_back("-fdump-vtable-layouts");
- if (Opts.NoBitFieldTypeAlign)
- Res.push_back("-fno-bitfield-type-alignment");
- if (Opts.PICLevel)
- Res.push_back("-pic-level", llvm::utostr(Opts.PICLevel));
- if (Opts.PIELevel)
- Res.push_back("-pie-level", llvm::utostr(Opts.PIELevel));
- if (Opts.ObjCGCBitmapPrint)
- Res.push_back("-print-ivar-layout");
- if (Opts.NoConstantCFStrings)
- Res.push_back("-fno-constant-cfstrings");
- if (!Opts.AccessControl)
- Res.push_back("-fno-access-control");
- if (!Opts.CharIsSigned)
- Res.push_back("-fno-signed-char");
- if (Opts.ShortWChar)
- Res.push_back("-fshort-wchar");
- if (!Opts.ElideConstructors)
- Res.push_back("-fno-elide-constructors");
- if (Opts.getGC() != LangOptions::NonGC) {
- if (Opts.getGC() == LangOptions::HybridGC) {
- Res.push_back("-fobjc-gc");
- } else {
- assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!");
- Res.push_back("-fobjc-gc-only");
- }
- }
- Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString());
- if (Opts.ObjCAutoRefCount)
- Res.push_back("-fobjc-arc");
- if (Opts.ObjCRuntimeHasWeak)
- Res.push_back("-fobjc-runtime-has-weak");
- if (!Opts.ObjCInferRelatedResultType)
- Res.push_back("-fno-objc-infer-related-result-type");
-
- if (Opts.AppleKext)
- Res.push_back("-fapple-kext");
-
- if (Opts.getVisibilityMode() != DefaultVisibility) {
- Res.push_back("-fvisibility");
- if (Opts.getVisibilityMode() == HiddenVisibility) {
- Res.push_back("hidden");
- } else {
- assert(Opts.getVisibilityMode() == ProtectedVisibility &&
- "Invalid visibility!");
- Res.push_back("protected");
- }
- }
- if (Opts.InlineVisibilityHidden)
- Res.push_back("-fvisibility-inlines-hidden");
-
- if (Opts.getStackProtector() != 0)
- Res.push_back("-stack-protector", llvm::utostr(Opts.getStackProtector()));
- if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth)
- Res.push_back("-ftemplate-depth", llvm::utostr(Opts.InstantiationDepth));
- if (Opts.ConstexprCallDepth != DefaultLangOpts.ConstexprCallDepth)
- Res.push_back("-fconstexpr-depth", llvm::utostr(Opts.ConstexprCallDepth));
- if (!Opts.ObjCConstantStringClass.empty())
- Res.push_back("-fconstant-string-class", Opts.ObjCConstantStringClass);
- if (Opts.FakeAddressSpaceMap)
- Res.push_back("-ffake-address-space-map");
- if (Opts.ParseUnknownAnytype)
- Res.push_back("-funknown-anytype");
- if (Opts.DebuggerSupport)
- Res.push_back("-fdebugger-support");
- if (Opts.DebuggerCastResultToId)
- Res.push_back("-fdebugger-cast-result-to-id");
- if (Opts.DebuggerObjCLiteral)
- Res.push_back("-fdebugger-objc-literal");
- if (Opts.DelayedTemplateParsing)
- Res.push_back("-fdelayed-template-parsing");
- if (Opts.Deprecated)
- Res.push_back("-fdeprecated-macro");
- if (Opts.ApplePragmaPack)
- Res.push_back("-fapple-pragma-pack");
- if (!Opts.CurrentModule.empty())
- Res.push_back("-fmodule-name=" + Opts.CurrentModule);
-}
-
-static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
- ToArgsList &Res) {
- for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
- Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") +
- Opts.Macros[i].first);
- for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
- // FIXME: We need to avoid reincluding the implicit PCH and PTH includes.
- Res.push_back("-include", Opts.Includes[i]);
- }
- for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i)
- Res.push_back("-imacros", Opts.MacroIncludes[i]);
- if (!Opts.UsePredefines)
- Res.push_back("-undef");
- if (Opts.DetailedRecord)
- Res.push_back("-detailed-preprocessing-record");
- if (!Opts.ImplicitPCHInclude.empty())
- Res.push_back("-include-pch", Opts.ImplicitPCHInclude);
- if (!Opts.ImplicitPTHInclude.empty())
- Res.push_back("-include-pth", Opts.ImplicitPTHInclude);
- if (!Opts.TokenCache.empty()) {
- if (Opts.ImplicitPTHInclude.empty())
- Res.push_back("-token-cache", Opts.TokenCache);
- else
- assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
- "Unsupported option combination!");
- }
- for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i)
- Res.push_back("-chain-include", Opts.ChainedIncludes[i]);
- for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
- Res.push_back("-remap-file", Opts.RemappedFiles[i].first + ";" +
- Opts.RemappedFiles[i].second);
- }
-}
-
-static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
- ToArgsList &Res) {
- if (!Opts.ShowCPP && !Opts.ShowMacros)
- llvm::report_fatal_error("Invalid option combination!");
-
- if (Opts.ShowCPP && Opts.ShowMacros)
- Res.push_back("-dD");
- else if (!Opts.ShowCPP && Opts.ShowMacros)
- Res.push_back("-dM");
-
- if (!Opts.ShowLineMarkers)
- Res.push_back("-P");
- if (Opts.ShowComments)
- Res.push_back("-C");
- if (Opts.ShowMacroComments)
- Res.push_back("-CC");
-}
-
-static void TargetOptsToArgs(const TargetOptions &Opts,
- ToArgsList &Res) {
- Res.push_back("-triple");
- Res.push_back(Opts.Triple);
- if (!Opts.CPU.empty())
- Res.push_back("-target-cpu", Opts.CPU);
- if (!Opts.ABI.empty())
- Res.push_back("-target-abi", Opts.ABI);
- if (!Opts.LinkerVersion.empty())
- Res.push_back("-target-linker-version", Opts.LinkerVersion);
- if (!Opts.CXXABI.empty())
- Res.push_back("-cxx-abi", Opts.CXXABI);
- for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i)
- Res.push_back("-target-feature", Opts.Features[i]);
-}
-
-void CompilerInvocation::toArgs(std::vector<std::string> &Res) const {
- ToArgsList List(Res);
- AnalyzerOptsToArgs(getAnalyzerOpts(), List);
- CodeGenOptsToArgs(getCodeGenOpts(), List);
- DependencyOutputOptsToArgs(getDependencyOutputOpts(), List);
- DiagnosticOptsToArgs(getDiagnosticOpts(), List);
- FileSystemOptsToArgs(getFileSystemOpts(), List);
- FrontendOptsToArgs(getFrontendOpts(), List);
- HeaderSearchOptsToArgs(getHeaderSearchOpts(), List);
- LangOptsToArgs(*getLangOpts(), List);
- PreprocessorOptsToArgs(getPreprocessorOpts(), List);
- PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), List);
- TargetOptsToArgs(getTargetOpts(), List);
-}
-
-//===----------------------------------------------------------------------===//
-// Deserialization (to args)
+// Deserialization (from args)
//===----------------------------------------------------------------------===//
using namespace clang::driver;
@@ -965,7 +71,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
assert (A->getOption().matches(options::OPT_O));
- llvm::StringRef S(A->getValue(Args));
+ llvm::StringRef S(A->getValue());
if (S == "s" || S == "z" || S.empty())
return 2;
@@ -979,7 +85,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O)) {
- switch (A->getValue(Args)[0]) {
+ switch (A->getValue()[0]) {
default:
return 0;
case 's':
@@ -996,14 +102,14 @@ static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) {
for (arg_iterator I = Args.filtered_begin(OPT_W_Group),
E = Args.filtered_end(); I != E; ++I) {
Arg *A = *I;
- // If the argument is a pure flag, add its name (minus the "-W" at the beginning)
+ // If the argument is a pure flag, add its name (minus the "W" at the beginning)
// to the warning list. Else, add its value (for the OPT_W case).
if (A->getOption().getKind() == Option::FlagClass) {
- Warnings.push_back(A->getOption().getName().substr(2));
+ Warnings.push_back(A->getOption().getName().substr(1));
} else {
for (unsigned Idx = 0, End = A->getNumValues();
Idx < End; ++Idx) {
- StringRef V = A->getValue(Args, Idx);
+ StringRef V = A->getValue(Idx);
// "-Wl," and such are not warning options.
// FIXME: Should be handled by putting these in separate flags.
if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,"))
@@ -1020,11 +126,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
using namespace options;
bool Success = true;
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumStores);
if (Value == NumStores) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1036,11 +142,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
.Case(CMDFLAG, NAME##Model)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumConstraints);
if (Value == NumConstraints) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1052,11 +158,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \
.Case(CMDFLAG, PD_##NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
if (Value == NUM_ANALYSIS_DIAG_CLIENTS) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1068,11 +174,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name)
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumPurgeModes);
if (Value == NumPurgeModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1084,11 +190,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumIPAModes);
if (Value == NumIPAModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1100,11 +206,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
.Case(CMDFLAG, NAME)
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
.Default(NumInliningModes);
if (Value == NumInliningModes) {
Diags.Report(diag::err_drv_invalid_value)
@@ -1116,21 +222,21 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
- Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
- Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
+ Opts.visualizeExplodedGraphWithGraphViz =
+ Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
+ Opts.visualizeExplodedGraphWithUbiGraph =
+ Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted);
Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
- Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
+ Opts.eagerlyAssumeBinOpBifurcation = Args.hasArg(OPT_analyzer_eagerly_assume);
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
- Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
- Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
- Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
+ Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
Opts.PrintStats = Args.hasArg(OPT_analyzer_stats);
Opts.InlineMaxStackDepth =
Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth,
@@ -1148,12 +254,42 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
bool enable = (A->getOption().getID() == OPT_analyzer_checker);
// We can have a list of comma separated checker names, e.g:
// '-analyzer-checker=cocoa,unix'
- StringRef checkerList = A->getValue(Args);
+ StringRef checkerList = A->getValue();
SmallVector<StringRef, 4> checkers;
checkerList.split(checkers, ",");
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
}
+
+ // Go through the analyzer configuration options.
+ for (arg_iterator it = Args.filtered_begin(OPT_analyzer_config),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = *it;
+ A->claim();
+ // We can have a list of comma separated config names, e.g:
+ // '-analyzer-config key1=val1,key2=val2'
+ StringRef configList = A->getValue();
+ SmallVector<StringRef, 4> configVals;
+ configList.split(configVals, ",");
+ for (unsigned i = 0, e = configVals.size(); i != e; ++i) {
+ StringRef key, val;
+ llvm::tie(key, val) = configVals[i].split("=");
+ if (val.empty()) {
+ Diags.Report(SourceLocation(),
+ diag::err_analyzer_config_no_value) << configVals[i];
+ Success = false;
+ break;
+ }
+ if (val.find('=') != StringRef::npos) {
+ Diags.Report(SourceLocation(),
+ diag::err_analyzer_config_multiple_values)
+ << configVals[i];
+ Success = false;
+ break;
+ }
+ Opts.Config[key] = val;
+ }
+ }
return Success;
}
@@ -1179,21 +315,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.OptimizationLevel = OptLevel;
// We must always run at least the always inlining pass.
- Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
- : CodeGenOptions::OnlyAlwaysInlining;
+ Opts.setInlining(
+ (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
+ : CodeGenOptions::OnlyAlwaysInlining);
// -fno-inline-functions overrides OptimizationLevel > 1.
Opts.NoInline = Args.hasArg(OPT_fno_inline);
- Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ?
- CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining;
+ Opts.setInlining(Args.hasArg(OPT_fno_inline_functions) ?
+ CodeGenOptions::OnlyAlwaysInlining : Opts.getInlining());
if (Args.hasArg(OPT_gline_tables_only)) {
- Opts.DebugInfo = CodeGenOptions::DebugLineTablesOnly;
+ Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
} else if (Args.hasArg(OPT_g_Flag)) {
if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true))
- Opts.DebugInfo = CodeGenOptions::LimitedDebugInfo;
+ Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
else
- Opts.DebugInfo = CodeGenOptions::FullDebugInfo;
+ Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
}
+ Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
@@ -1263,18 +401,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
- Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm);
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
+ Opts.SSPBufferSize =
+ Args.getLastArgIntValue(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(Args);
- Val.getAsInteger(10, Opts.StackAlignment);
+ StringRef Val = A->getValue();
+ unsigned StackAlignment = Opts.StackAlignment;
+ Val.getAsInteger(10, StackAlignment);
+ Opts.StackAlignment = StackAlignment;
}
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Method = llvm::StringSwitch<unsigned>(Name)
.Case("legacy", CodeGenOptions::Legacy)
.Case("non-legacy", CodeGenOptions::NonLegacy)
@@ -1284,12 +425,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
Success = false;
} else {
- Opts.ObjCDispatchMethod = Method;
+ Opts.setObjCDispatchMethod(
+ static_cast<CodeGenOptions::ObjCDispatchMethodKind>(Method));
}
}
if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Model = llvm::StringSwitch<unsigned>(Name)
.Case("global-dynamic", CodeGenOptions::GeneralDynamicTLSModel)
.Case("local-dynamic", CodeGenOptions::LocalDynamicTLSModel)
@@ -1300,7 +442,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
Success = false;
} else {
- Opts.DefaultTLSModel = static_cast<CodeGenOptions::TLSModel>(Model);
+ Opts.setDefaultTLSModel(static_cast<CodeGenOptions::TLSModel>(Model));
}
}
@@ -1351,9 +493,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
StringRef ShowOverloads =
Args.getLastArgValue(OPT_fshow_overloads_EQ, "all");
if (ShowOverloads == "best")
- Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best;
+ Opts.setShowOverloads(Ovl_Best);
else if (ShowOverloads == "all")
- Opts.ShowOverloads = DiagnosticsEngine::Ovl_All;
+ Opts.setShowOverloads(Ovl_All);
else {
Success = false;
if (Diags)
@@ -1381,11 +523,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
StringRef Format =
Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
if (Format == "clang")
- Opts.Format = DiagnosticOptions::Clang;
+ Opts.setFormat(DiagnosticOptions::Clang);
else if (Format == "msvc")
- Opts.Format = DiagnosticOptions::Msvc;
+ Opts.setFormat(DiagnosticOptions::Msvc);
else if (Format == "vi")
- Opts.Format = DiagnosticOptions::Vi;
+ Opts.setFormat(DiagnosticOptions::Vi);
else {
Success = false;
if (Diags)
@@ -1467,7 +609,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_emit_obj:
Opts.ProgramAction = frontend::EmitObj; break;
case OPT_fixit_EQ:
- Opts.FixItSuffix = A->getValue(Args);
+ Opts.FixItSuffix = A->getValue();
// fall-through!
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
@@ -1503,14 +645,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
}
if (const Arg* A = Args.getLastArg(OPT_plugin)) {
- Opts.Plugins.push_back(A->getValue(Args,0));
+ Opts.Plugins.push_back(A->getValue(0));
Opts.ProgramAction = frontend::PluginAction;
- Opts.ActionName = A->getValue(Args);
+ Opts.ActionName = A->getValue();
for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
end = Args.filtered_end(); it != end; ++it) {
- if ((*it)->getValue(Args, 0) == Opts.ActionName)
- Opts.PluginArgs.push_back((*it)->getValue(Args, 1));
+ if ((*it)->getValue(0) == Opts.ActionName)
+ Opts.PluginArgs.push_back((*it)->getValue(1));
}
}
@@ -1519,17 +661,17 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
end = Args.filtered_end(); it != end; ++it) {
- if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i])
- Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1));
+ if ((*it)->getValue(0) == Opts.AddPluginActions[i])
+ Opts.AddPluginArgs[i].push_back((*it)->getValue(1));
}
}
if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
Opts.CodeCompletionAt =
- ParsedSourceLocation::FromString(A->getValue(Args));
+ ParsedSourceLocation::FromString(A->getValue());
if (Opts.CodeCompletionAt.FileName.empty())
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
Opts.DisableFree = Args.hasArg(OPT_disable_free);
@@ -1595,7 +737,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
- DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
+ DashX = llvm::StringSwitch<InputKind>(A->getValue())
.Case("c", IK_C)
.Case("cl", IK_OpenCL)
.Case("cuda", IK_CUDA)
@@ -1619,7 +761,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Default(IK_None);
if (DashX == IK_None)
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
// '-' is the default input if none is given.
@@ -1667,7 +809,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc);
Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
- Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0);
+ Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
@@ -1686,7 +828,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
frontend::IncludeDirGroup Group
= IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
- Opts.AddPath((*it)->getValue(Args), Group, true,
+ Opts.AddPath((*it)->getValue(), Group, true,
/*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
IsIndexHeaderMap = false;
}
@@ -1698,43 +840,43 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
if (A->getOption().matches(OPT_iprefix))
- Prefix = A->getValue(Args);
+ Prefix = A->getValue();
else if (A->getOption().matches(OPT_iwithprefix))
- Opts.AddPath(Prefix.str() + A->getValue(Args),
+ Opts.AddPath(Prefix.str() + A->getValue(),
frontend::System, false, false, false);
else
- Opts.AddPath(Prefix.str() + A->getValue(Args),
+ Opts.AddPath(Prefix.str() + A->getValue(),
frontend::Angled, false, false, false);
}
for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::After, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false);
for (arg_iterator it = Args.filtered_begin(OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::System, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::System, true, false,
!(*it)->getOption().matches(OPT_iwithsysroot));
for (arg_iterator it = Args.filtered_begin(OPT_iframework),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::System, true, true,
+ Opts.AddPath((*it)->getValue(), frontend::System, true, true,
true);
// Add the paths for the various language specific isystem flags.
for (arg_iterator it = Args.filtered_begin(OPT_c_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true);
for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false,
true);
// Add the internal paths from a driver that detects standard include paths.
@@ -1742,7 +884,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
OPT_internal_externc_isystem),
E = Args.filtered_end();
I != E; ++I)
- Opts.AddPath((*I)->getValue(Args), frontend::System,
+ Opts.AddPath((*I)->getValue(), frontend::System,
false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true,
(*I)->getOption().matches(OPT_internal_externc_isystem));
@@ -1751,7 +893,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
OPT_ino_system_prefix),
E = Args.filtered_end();
I != E; ++I)
- Opts.AddSystemHeaderPrefix((*I)->getValue(Args),
+ Opts.AddSystemHeaderPrefix((*I)->getValue(),
(*I)->getOption().matches(OPT_isystem_prefix));
}
@@ -1799,11 +941,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
- Opts.BCPLComment = Std.hasBCPLComments();
+ Opts.LineComment = Std.hasLineComments();
Opts.C99 = Std.isC99();
Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.CPlusPlus1y = Std.isCPlusPlus1y();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Std.isC99();
@@ -1838,6 +981,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ // C++ has wchar_t keyword.
+ Opts.WChar = Opts.CPlusPlus;
+
Opts.GNUKeywords = Opts.GNUMode;
Opts.CXXOperatorNames = Opts.CPlusPlus;
@@ -1853,14 +999,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
- LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+ LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
#define LANGSTANDARD(id, name, desc, features) \
.Case(name, LangStandard::lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(LangStandard::lang_unspecified);
if (LangStd == LangStandard::lang_unspecified)
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
else {
// Valid standard, check to make sure language and standard are compatable.
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
@@ -1901,7 +1047,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// Override the -std option in this case.
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
LangStandard::Kind OpenCLLangStd
- = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args))
+ = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
.Case("CL", LangStandard::lang_opencl)
.Case("CL1.1", LangStandard::lang_opencl11)
.Case("CL1.2", LangStandard::lang_opencl12)
@@ -1909,7 +1055,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (OpenCLLangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue(Args);
+ << A->getAsString(Args) << A->getValue();
}
else
LangStd = OpenCLLangStd;
@@ -1930,7 +1076,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Opts.ObjC1) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
- StringRef value = arg->getValue(Args);
+ StringRef value = arg->getValue();
if (Opts.ObjCRuntime.tryParse(value))
Diags.Report(diag::err_drv_unknown_objc_runtime) << value;
}
@@ -1941,14 +1087,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.setGC(LangOptions::HybridGC);
else if (Args.hasArg(OPT_fobjc_arc)) {
Opts.ObjCAutoRefCount = 1;
- if (!Opts.ObjCRuntime.isNonFragile())
- Diags.Report(diag::err_arc_nonfragile_abi);
+ if (!Opts.ObjCRuntime.allowsARC())
+ Diags.Report(diag::err_arc_unsupported_on_runtime);
+
+ // Only set ObjCARCWeak if ARC is enabled.
+ if (Args.hasArg(OPT_fobjc_runtime_has_weak))
+ Opts.ObjCARCWeak = 1;
+ else
+ Opts.ObjCARCWeak = Opts.ObjCRuntime.allowsWeak();
}
- Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak();
- if (Args.hasArg(OPT_fobjc_runtime_has_weak))
- Opts.ObjCRuntimeHasWeak = 1;
-
if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
Opts.ObjCInferRelatedResultType = 0;
}
@@ -1990,7 +1138,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
<< Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue(Args);
+ StringRef Val = A->getValue();
if (Val == "fast")
Opts.setFPContractMode(LangOptions::FPC_Fast);
else if (Val == "on")
@@ -2043,6 +1191,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
Opts.CharIsSigned = !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);
@@ -2064,7 +1213,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.getLastArgValue(OPT_fconstant_string_class);
Opts.ObjCDefaultSynthProperties =
Args.hasArg(OPT_fobjc_default_synthesize_properties);
- Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
+ 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);
@@ -2085,8 +1235,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id);
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
- Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer);
- Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
@@ -2109,6 +1257,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.FastMath = Args.hasArg(OPT_ffast_math);
Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only);
+ Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm);
+
+ Opts.RetainCommentsFromSystemHeaders =
+ Args.hasArg(OPT_fretain_comments_from_system_headers);
+
unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
switch (SSP) {
default:
@@ -2119,6 +1272,37 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
case 1: Opts.setStackProtector(LangOptions::SSPOn); break;
case 2: Opts.setStackProtector(LangOptions::SSPReq); break;
}
+
+ // Parse -fsanitize= arguments.
+ std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ);
+ for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) {
+ // Since the Opts.Sanitize* values are bitfields, it's a little tricky to
+ // efficiently map string values to them. Perform the mapping indirectly:
+ // convert strings to enumerated values, then switch over the enum to set
+ // the right bitfield value.
+ enum Sanitizer {
+#define SANITIZER(NAME, ID) \
+ ID,
+#include "clang/Basic/Sanitizers.def"
+ Unknown
+ };
+ switch (llvm::StringSwitch<unsigned>(Sanitizers[I])
+#define SANITIZER(NAME, ID) \
+ .Case(NAME, ID)
+#include "clang/Basic/Sanitizers.def"
+ .Default(Unknown)) {
+#define SANITIZER(NAME, ID) \
+ case ID: \
+ Opts.Sanitize##ID = true; \
+ break;
+#include "clang/Basic/Sanitizers.def"
+
+ case Unknown:
+ Diags.Report(diag::err_drv_invalid_value)
+ << "-fsanitize=" << Sanitizers[I];
+ break;
+ }
+ }
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
@@ -2128,7 +1312,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
if (const Arg *A = Args.getLastArg(OPT_token_cache))
- Opts.TokenCache = A->getValue(Args);
+ Opts.TokenCache = A->getValue();
else
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
@@ -2139,11 +1323,11 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args));
+ Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue());
}
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
- StringRef Value(A->getValue(Args));
+ StringRef Value(A->getValue());
size_t Comma = Value.find(',');
unsigned Bytes = 0;
unsigned EndOfLine = 0;
@@ -2162,9 +1346,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
if ((*it)->getOption().matches(OPT_D))
- Opts.addMacroDef((*it)->getValue(Args));
+ Opts.addMacroDef((*it)->getValue());
else
- Opts.addMacroUndef((*it)->getValue(Args));
+ Opts.addMacroUndef((*it)->getValue());
}
Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
@@ -2174,22 +1358,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
OPT_include_pth),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- // PCH is handled specially, we need to extra the original include path.
- if (A->getOption().matches(OPT_include_pch)) {
- std::string OriginalFile =
- ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags);
- if (OriginalFile.empty())
- continue;
-
- Opts.Includes.push_back(OriginalFile);
- } else
- Opts.Includes.push_back(A->getValue(Args));
+ Opts.Includes.push_back(A->getValue());
}
for (arg_iterator it = Args.filtered_begin(OPT_chain_include),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
- Opts.ChainedIncludes.push_back(A->getValue(Args));
+ Opts.ChainedIncludes.push_back(A->getValue());
}
// Include 'altivec.h' if -faltivec option present
@@ -2200,7 +1375,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
std::pair<StringRef,StringRef> Split =
- StringRef(A->getValue(Args)).split(';');
+ StringRef(A->getValue()).split(';');
if (Split.second.empty()) {
Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args);
@@ -2211,7 +1386,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
- StringRef Name = A->getValue(Args);
+ StringRef Name = A->getValue();
unsigned Library = llvm::StringSwitch<unsigned>(Name)
.Case("libc++", ARCXX_libcxx)
.Case("libstdc++", ARCXX_libstdcxx)
@@ -2240,7 +1415,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.Features = Args.getAllArgValues(OPT_target_feature);
+ Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
@@ -2280,13 +1455,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// 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().isCC1Option()) {
+ 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 = ParseAnalyzerArgs(*Res.getAnalyzerOpts(), *Args, Diags) && Success;
Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success;
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags)
@@ -2368,53 +1543,49 @@ llvm::APInt ModuleSignature::getAsInteger() const {
}
std::string CompilerInvocation::getModuleHash() const {
- ModuleSignature Signature;
-
+ using llvm::hash_code;
+ using llvm::hash_value;
+ using llvm::hash_combine;
+
// Start the signature with the compiler version.
- // FIXME: The full version string can be quite long. Omit it from the
- // module hash for now to avoid failures where the path name becomes too
- // long. An MD5 or similar checksum would work well here.
- // Signature.add(getClangFullRepositoryVersion());
-
+ // FIXME: We'd rather use something more cryptographically sound than
+ // CityHash, but this will do for now.
+ hash_code code = hash_value(getClangFullRepositoryVersion());
+
// Extend the signature with the language options
#define LANGOPT(Name, Bits, Default, Description) \
- Signature.add(LangOpts->Name, Bits);
+ code = hash_combine(code, LangOpts->Name);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits);
+ code = hash_combine(code, static_cast<unsigned>(LangOpts->get##Name()));
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- // Extend the signature with the target triple
- llvm::Triple T(TargetOpts.Triple);
- Signature.add((unsigned)T.getArch(), 5);
- Signature.add((unsigned)T.getVendor(), 4);
- Signature.add((unsigned)T.getOS(), 5);
- Signature.add((unsigned)T.getEnvironment(), 4);
+ // Extend the signature with the target options.
+ code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU,
+ TargetOpts->ABI, TargetOpts->CXXABI,
+ TargetOpts->LinkerVersion);
+ for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i)
+ code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]);
// Extend the signature with preprocessor options.
- Signature.add(getPreprocessorOpts().UsePredefines, 1);
- Signature.add(getPreprocessorOpts().DetailedRecord, 1);
-
- // Hash the preprocessor defines.
- // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines.
+ const PreprocessorOptions &ppOpts = getPreprocessorOpts();
+ code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
+
std::vector<StringRef> MacroDefs;
for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
I != IEnd; ++I) {
- if (!I->second)
- MacroDefs.push_back(I->first);
+ code = hash_combine(code, I->first, I->second);
}
- llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end());
-
- unsigned PPHashResult = 0;
- for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I)
- PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult);
- Signature.add(PPHashResult, 32);
-
- // We've generated the signature. Treat it as one large APInt that we'll
- // encode in base-36 and return.
- Signature.flush();
- return Signature.getAsInteger().toString(36, /*Signed=*/false);
+
+ // Extend the signature with the sysroot.
+ const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
+ code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
+ hsOpts.UseStandardSystemIncludes,
+ hsOpts.UseStandardCXXIncludes,
+ hsOpts.UseLibcxx);
+
+ return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 0aca86e2c97f..d82cb6d05157 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/Utils.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -34,8 +34,8 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticOptions DiagOpts;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgList.size(),
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ ArgList.size(),
ArgList.begin());
}
@@ -49,11 +49,6 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
"a.out", false, *Diags);
- // Force driver to use clang.
- // FIXME: This seems like a hack. Maybe the "Clang" tool subclass should be
- // available for using it to get the arguments, thus avoiding the overkill
- // of using the driver.
- TheDriver.setForcedClangUse();
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 21f5daa9ee39..53ea8befbc09 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -59,10 +59,11 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
virtual void EndOfMainFile() {
OutputDependencyFile();
@@ -132,10 +133,11 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
if (!File) {
if (AddMissingHeaderDeps)
AddFilename(FileName);
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index eebaf0c8fe48..28d9c5d320e2 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -51,10 +51,11 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
virtual void EndOfMainFile() {
OutputGraphFile();
@@ -72,10 +73,11 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
if (!File)
return;
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index f052f90fa953..359b82be6062 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
@@ -18,6 +18,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include <algorithm>
using namespace clang;
@@ -60,8 +61,8 @@ static StringRef getImmediateMacroName(SourceLocation Loc,
}
DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
-: LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
+ DiagnosticOptions *DiagOpts)
+ : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
DiagnosticRenderer::~DiagnosticRenderer() {}
@@ -194,7 +195,7 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
return;
LastIncludeLoc = Loc;
- if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+ if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
return;
emitIncludeStackRecursively(Loc, SM);
@@ -218,6 +219,53 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
emitIncludeLocation(Loc, PLoc, SM);
}
+// Helper function to fix up source ranges. It takes in an array of ranges,
+// and outputs an array of ranges where we want to draw the range highlighting
+// around the location specified by CaretLoc.
+//
+// To find locations which correspond to the caret, we crawl the macro caller
+// chain for the beginning and end of each range. If the caret location
+// is in a macro expansion, we search each chain for a location
+// in the same expansion as the caret; otherwise, we crawl to the top of
+// each chain. Two locations are part of the same macro expansion
+// iff the FileID is the same.
+static void mapDiagnosticRanges(
+ SourceLocation CaretLoc,
+ const SmallVectorImpl<CharSourceRange>& Ranges,
+ SmallVectorImpl<CharSourceRange>& SpellingRanges,
+ const SourceManager *SM) {
+ FileID CaretLocFileID = SM->getFileID(CaretLoc);
+
+ for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ SourceLocation Begin = I->getBegin(), End = I->getEnd();
+ bool IsTokenRange = I->isTokenRange();
+
+ // Search the macro caller chain for the beginning of the range.
+ while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID)
+ Begin = SM->getImmediateMacroCallerLoc(Begin);
+
+ // Search the macro caller chain for the beginning of the range.
+ while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) {
+ // The computation of the next End is an inlined version of
+ // getImmediateMacroCallerLoc, except it chooses the end of an
+ // expansion range.
+ if (SM->isMacroArgExpansion(End)) {
+ End = SM->getImmediateSpellingLoc(End);
+ } else {
+ End = SM->getImmediateExpansionRange(End).second;
+ }
+ }
+
+ // Return the spelling location of the beginning and end of the range.
+ Begin = SM->getSpellingLoc(Begin);
+ End = SM->getSpellingLoc(End);
+ SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End),
+ IsTokenRange));
+ }
+}
+
/// \brief Recursively emit notes for each macro expansion and caret
/// diagnostics where appropriate.
///
@@ -245,9 +293,13 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
// If this is a file source location, directly emit the source snippet and
// caret line. Also record the macro depth reached.
if (Loc.isFileID()) {
+ // Map the ranges.
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+
assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
MacroDepth = OnMacroInst;
- emitCodeContext(Loc, Level, Ranges, Hints, SM);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
return;
}
// Otherwise recurse through each macro expansion layer.
@@ -257,8 +309,7 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
Loc = SM.skipToMacroArgExpansion(Loc);
SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
-
- // FIXME: Map ranges?
+
emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth,
OnMacroInst + 1);
@@ -269,28 +320,17 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
Loc = SM.getImmediateMacroCalleeLoc(Loc);
unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
- if (MacroDepth > DiagOpts.MacroBacktraceLimit &&
- DiagOpts.MacroBacktraceLimit != 0) {
- MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
- DiagOpts.MacroBacktraceLimit % 2;
- MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
+ if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
+ DiagOpts->MacroBacktraceLimit != 0) {
+ MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
+ DiagOpts->MacroBacktraceLimit % 2;
+ MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
}
// Whether to suppress printing this macro expansion.
bool Suppressed = (OnMacroInst >= MacroSkipStart &&
OnMacroInst < MacroSkipEnd);
- // Map the ranges.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- SourceLocation Start = I->getBegin(), End = I->getEnd();
- if (Start.isMacroID())
- I->setBegin(SM.getImmediateMacroCalleeLoc(Start));
- if (End.isMacroID())
- I->setEnd(SM.getImmediateMacroCalleeLoc(End));
- }
-
if (Suppressed) {
// Tell the user that we've skipped contexts.
if (OnMacroInst == MacroSkipStart) {
@@ -303,14 +343,18 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
}
return;
}
-
+
+ // Map the ranges.
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM);
+
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "expanded from macro '"
<< getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
Message.str(),
- Ranges, ArrayRef<FixItHint>(), &SM);
+ SpellingRanges, ArrayRef<FixItHint>(), &SM);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index a4321e720ed0..2e9a791c3039 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -23,10 +23,12 @@
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Timer.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/Timer.h"
using namespace clang;
namespace {
@@ -155,20 +157,22 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return new MultiplexConsumer(Consumers);
}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
- assert(!Input.File.empty() && "Unexpected empty filename!");
+ assert(!Input.isEmpty() && "Unexpected empty filename!");
setCurrentInput(Input);
setCompilerInstance(&CI);
+ StringRef InputFile = Input.getFile();
bool HasBegunSourceFile = false;
if (!BeginInvocation(CI))
goto failure;
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (Input.Kind == IK_AST) {
+ if (Input.getKind() == IK_AST) {
assert(!usesPreprocessorOnly() &&
"Attempt to pass AST file to preprocessor only action!");
assert(hasASTFileSupport() &&
@@ -176,7 +180,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::string Error;
- ASTUnit *AST = ASTUnit::LoadFromASTFile(Input.File, Diags,
+ ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
CI.getFileSystemOpts());
if (!AST)
goto failure;
@@ -191,11 +195,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setASTContext(&AST->getASTContext());
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
/// Create the AST consumer.
- CI.setASTConsumer(CreateWrappedASTConsumer(CI, Input.File));
+ CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
if (!CI.hasASTConsumer())
goto failure;
@@ -209,7 +213,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createSourceManager(CI.getFileManager());
// IR files bypass the rest of initialization.
- if (Input.Kind == IK_LLVM_IR) {
+ if (Input.getKind() == IK_LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -218,12 +222,51 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
return true;
}
+ // If the implicit PCH include is actually a directory, rather than
+ // a single file, search for a suitable PCH file in that directory.
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ FileManager &FileMgr = CI.getFileManager();
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
+ if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(PCHDir->getName(), DirNative);
+ bool Found = false;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // Check whether this is an acceptable AST file.
+ if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
+ CI.getLangOpts(),
+ CI.getTargetOpts(),
+ CI.getPreprocessorOpts())) {
+ for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) {
+ if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) {
+ PPOpts.Includes[I] = Dir->path();
+ PPOpts.ImplicitPCHInclude = Dir->path();
+ Found = true;
+ break;
+ }
+ }
+
+ assert(Found && "Implicit PCH include not in includes list?");
+ break;
+ }
+ }
+
+ if (!Found) {
+ CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
+ return true;
+ }
+ }
+ }
+
// Set up the preprocessor.
CI.createPreprocessor();
@@ -233,7 +276,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, Input.File))
+ if (!BeginSourceFileAction(CI, InputFile))
goto failure;
/// Create the AST context and consumer unless this is a preprocessor only
@@ -242,12 +285,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createASTContext();
OwningPtr<ASTConsumer> Consumer(
- CreateWrappedASTConsumer(CI, Input.File));
+ CreateWrappedASTConsumer(CI, InputFile));
if (!Consumer)
goto failure;
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
-
+ CI.getPreprocessor().setPPMutationListener(
+ Consumer->GetPPMutationListener());
+
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
OwningPtr<ExternalASTSource> source;
@@ -270,7 +315,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createPCHExternalASTSource(
CI.getPreprocessorOpts().ImplicitPCHInclude,
CI.getPreprocessorOpts().DisablePCHValidation,
- CI.getPreprocessorOpts().DisableStatCache,
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
DeserialListener);
if (!CI.getASTContext().getExternalSource())
@@ -314,6 +358,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
+ CI.clearOutputFiles(/*EraseFiles=*/true);
setCurrentInput(FrontendInputFile());
setCompilerInstance(0);
return false;
@@ -325,10 +370,7 @@ bool FrontendAction::Execute() {
// Initialize the main file entry. This needs to be delayed until after PCH
// has loaded.
if (!isCurrentFileAST()) {
- if (!CI.InitializeSourceManager(getCurrentFile(),
- getCurrentInput().IsSystem
- ? SrcMgr::C_System
- : SrcMgr::C_User))
+ if (!CI.InitializeSourceManager(getCurrentInput()))
return false;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 24960cf6a0c9..47063f78b5d9 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -131,8 +131,31 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
Sysroot, OS);
}
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+ Includes.append(RHS.begin(), RHS.end());
+ return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts) {
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += HeaderName;
+ Includes += "\"\n";
+}
+
+static void addHeaderInclude(const FileEntry *Header,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts) {
+ addHeaderInclude(Header->getName(), Includes, LangOpts);
+}
+
/// \brief Collect the set of header includes needed to construct the given
-/// module.
+/// module and update the TopHeaders file set of the module.
///
/// \param Module The module we're collecting includes from.
///
@@ -142,30 +165,23 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
FileManager &FileMgr,
ModuleMap &ModMap,
clang::Module *Module,
- SmallString<256> &Includes) {
+ SmallVectorImpl<char> &Includes) {
// Don't collect any headers for unavailable modules.
if (!Module->isAvailable())
return;
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += Module->Headers[I]->getName();
- Includes += "\"\n";
+ const FileEntry *Header = Module->Headers[I];
+ Module->TopHeaders.insert(Header);
+ addHeaderInclude(Header, Includes, LangOpts);
}
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
+ Module->TopHeaders.insert(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += UmbrellaHeader->getName();
- Includes += "\"\n";
+ addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory.
@@ -184,17 +200,14 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
// If this header is marked 'unavailable' in this module, don't include
// it.
- if (const FileEntry *Header = FileMgr.getFile(Dir->path()))
+ if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
if (ModMap.isHeaderInUnavailableModule(Header))
continue;
+ Module->TopHeaders.insert(Header);
+ }
// Include this header umbrella header for submodules.
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
- Includes += Dir->path();
- Includes += "\"\n";
+ addHeaderInclude(Dir->path(), Includes, LangOpts);
}
}
@@ -250,77 +263,29 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
- // Do we have an umbrella header for this module?
- const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
-
+ FileManager &FileMgr = CI.getFileManager();
+
// Collect the set of #includes we need to build the module.
SmallString<256> HeaderContents;
- collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
+ if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
+ addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts());
+ collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents);
- if (UmbrellaHeader && HeaderContents.empty()) {
- // Simple case: we have an umbrella header and there are no additional
- // includes, we can just parse the umbrella header directly.
- setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(),
- getCurrentFileKind(),
- Module->IsSystem));
- return true;
- }
-
- FileManager &FileMgr = CI.getFileManager();
- SmallString<128> HeaderName;
- time_t ModTime;
- if (UmbrellaHeader) {
- // Read in the umbrella header.
- // FIXME: Go through the source manager; the umbrella header may have
- // been overridden.
- std::string ErrorStr;
- llvm::MemoryBuffer *UmbrellaContents
- = FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr);
- if (!UmbrellaContents) {
- CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
- << UmbrellaHeader->getName() << ErrorStr;
- return false;
- }
-
- // Combine the contents of the umbrella header with the automatically-
- // generated includes.
- SmallString<256> OldContents = HeaderContents;
- HeaderContents = UmbrellaContents->getBuffer();
- HeaderContents += "\n\n";
- HeaderContents += "/* Module includes */\n";
- HeaderContents += OldContents;
-
- // Pretend that we're parsing the umbrella header.
- HeaderName = UmbrellaHeader->getName();
- ModTime = UmbrellaHeader->getModificationTime();
-
- delete UmbrellaContents;
- } else {
- // Pick an innocuous-sounding name for the umbrella header.
- HeaderName = Module->Name + ".h";
- if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
- /*CacheFailure=*/false)) {
- // Try again!
- HeaderName = Module->Name + "-module.h";
- if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
- /*CacheFailure=*/false)) {
- // Pick something ridiculous and go with it.
- HeaderName = Module->Name + "-module.hmod";
- }
- }
- ModTime = time(0);
- }
-
- // Remap the contents of the header name we're using to our synthesized
- // buffer.
- const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
+
+ StringRef InputName = Module::getModuleInputBufferName();
+
+ // We consistently construct a buffer as input to build the module.
+ // This means the main file for modules will always be a virtual one.
+ // FIXME: Maybe allow using a memory buffer as input directly instead of
+ // messing with virtual files.
+ const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName,
HeaderContents.size(),
- ModTime);
+ time(0));
llvm::MemoryBuffer *HeaderContentsBuf
= llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
- setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(),
+ setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(),
Module->IsSystem));
return true;
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 8178f7a9362a..4fddd112df7e 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -14,7 +14,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -320,7 +320,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
P.appendComponent("../../../include"); // <sysroot>/include
AddPath(P.str(), System, true, false, false);
AddPath("/mingw/include", System, true, false, false);
+#if defined(_WIN32)
AddPath("c:/mingw/include", System, true, false, false);
+#endif
}
break;
@@ -396,12 +398,14 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
// mingw.org C++ include paths
AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
+#if defined(_WIN32)
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");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
+#endif
break;
case llvm::Triple::DragonFly:
AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 1440da6e3755..4bbd033f1c2e 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -17,11 +17,12 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -83,6 +84,19 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
}
+/// \brief Add an implicit \#include using the original file used to generate
+/// a PCH file.
+static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP,
+ StringRef ImplicitIncludePCH) {
+ std::string OriginalFile =
+ ASTReader::getOriginalSourceFile(ImplicitIncludePCH, PP.getFileManager(),
+ PP.getDiagnostics());
+ if (OriginalFile.empty())
+ return;
+
+ AddImplicitInclude(Builder, OriginalFile, PP.getFileManager());
+}
+
/// PickFP - This is used to pick a value based on the FP semantics of the
/// specified FP model.
template <typename T>
@@ -102,51 +116,51 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
}
static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
- const llvm::fltSemantics *Sem) {
+ const llvm::fltSemantics *Sem, StringRef Ext) {
const char *DenormMin, *Epsilon, *Max, *Min;
- DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
- "3.64519953188247460253e-4951L",
- "4.94065645841246544176568792868221e-324L",
- "6.47517511943802511092443895822764655e-4966L");
+ DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324",
+ "3.64519953188247460253e-4951",
+ "4.94065645841246544176568792868221e-324",
+ "6.47517511943802511092443895822764655e-4966");
int Digits = PickFP(Sem, 6, 15, 18, 31, 33);
- Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16",
- "1.08420217248550443401e-19L",
- "4.94065645841246544176568792868221e-324L",
- "1.92592994438723585305597794258492732e-34L");
+ Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16",
+ "1.08420217248550443401e-19",
+ "4.94065645841246544176568792868221e-324",
+ "1.92592994438723585305597794258492732e-34");
int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381);
int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384);
- Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308",
- "3.36210314311209350626e-4932L",
- "2.00416836000897277799610805135016e-292L",
- "3.36210314311209350626267781732175260e-4932L");
- Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308",
- "1.18973149535723176502e+4932L",
- "1.79769313486231580793728971405301e+308L",
- "1.18973149535723176508575932662800702e+4932L");
+ Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308",
+ "3.36210314311209350626e-4932",
+ "2.00416836000897277799610805135016e-292",
+ "3.36210314311209350626267781732175260e-4932");
+ Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308",
+ "1.18973149535723176502e+4932",
+ "1.79769313486231580793728971405301e+308",
+ "1.18973149535723176508575932662800702e+4932");
SmallString<32> DefPrefix;
DefPrefix = "__";
DefPrefix += Prefix;
DefPrefix += "_";
- Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
+ Builder.defineMacro(DefPrefix + "DENORM_MIN__", Twine(DenormMin)+Ext);
Builder.defineMacro(DefPrefix + "HAS_DENORM__");
Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits));
- Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)+Ext);
Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits));
Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp));
Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp));
- Builder.defineMacro(DefPrefix + "MAX__", Twine(Max));
+ Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)+Ext);
Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")");
Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")");
- Builder.defineMacro(DefPrefix + "MIN__", Twine(Min));
+ Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)+Ext);
}
@@ -247,7 +261,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
<< "};\n"
<< "\n";
- if (LangOpts.ObjCRuntimeHasWeak) {
+ if (LangOpts.ObjCARCWeak) {
Out << "template<typename _Tp>\n"
<< "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n"
<< " enum { __value = 0 };\n"
@@ -288,6 +302,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
+ // FIXME: LangOpts.CPlusPlus1y
+
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
// C++ translation unit.
@@ -325,8 +341,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__clang_patchlevel__", "0");
#endif
Builder.defineMacro("__clang_version__",
- "\"" CLANG_VERSION_STRING " ("
- + getClangFullRepositoryVersion() + ")\"");
+ "\"" CLANG_VERSION_STRING " "
+ + getClangFullRepositoryVersion() + "\"");
#undef TOSTR
#undef TOSTR2
if (!LangOpts.MicrosoftMode) {
@@ -420,19 +436,17 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
- // Work around some issues with Visual C++ headerws.
- if (LangOpts.CPlusPlus) {
- // Since we define wchar_t in C++ mode.
+ // Work around some issues with Visual C++ headers.
+ if (LangOpts.WChar) {
+ // wchar_t supported as a keyword.
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
+ }
+ if (LangOpts.CPlusPlus) {
// FIXME: Support Microsoft's __identifier extension in the lexer.
Builder.append("#define __identifier(x) x");
Builder.append("class type_info;");
}
-
- if (LangOpts.CPlusPlus0x) {
- Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1");
- }
}
if (LangOpts.Optimize)
@@ -511,9 +525,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
- DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat());
- DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat());
- DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat());
+ DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
+ DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
+ DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
// Define a __POINTER_WIDTH__ macro for stdint.h.
Builder.defineMacro("__POINTER_WIDTH__",
@@ -763,6 +777,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
const std::string &Path = InitOpts.Includes[i];
if (Path == InitOpts.ImplicitPTHInclude)
AddImplicitIncludePTH(Builder, PP, Path);
+ else if (Path == InitOpts.ImplicitPCHInclude)
+ AddImplicitIncludePCH(Builder, PP, Path);
else
AddImplicitInclude(Builder, Path, PP.getFileManager());
}
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 3fee95749986..3a04f1859bda 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/LogDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
@@ -16,9 +17,9 @@
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
- const DiagnosticOptions &diags,
+ DiagnosticOptions *diags,
bool _OwnsOutputStream)
- : OS(os), LangOpts(0), DiagOpts(&diags),
+ : OS(os), LangOpts(0), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -172,6 +173,6 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DiagnosticConsumer *
LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
- return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+ return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false);
}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 5311ed52cd29..30707dc0c008 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -570,8 +570,12 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
do PP.Lex(Tok);
while (Tok.isNot(tok::eof));
- SmallVector<id_macro_pair, 128>
- MacrosByID(PP.macro_begin(), PP.macro_end());
+ SmallVector<id_macro_pair, 128> MacrosByID;
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I) {
+ if (I->first->hasMacroDefinition())
+ MacrosByID.push_back(id_macro_pair(I->first, I->second));
+ }
llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index a20f30d6be83..5f8fc1ecfc60 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/DenseSet.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
@@ -50,13 +51,10 @@ class SDiagsWriter;
class SDiagsRenderer : public DiagnosticNoteRenderer {
SDiagsWriter &Writer;
- RecordData &Record;
public:
- SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
- const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
- : DiagnosticNoteRenderer(LangOpts, DiagOpts),
- Writer(Writer), Record(Record){}
+ SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts)
+ : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
virtual ~SDiagsRenderer() {}
@@ -73,15 +71,16 @@ protected:
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
const SourceManager &SM) {}
-
- void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM);
-
+
+ virtual void emitNote(SourceLocation Loc, StringRef Message,
+ const SourceManager *SM);
+
virtual void emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM);
-
+
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level);
virtual void endDiagnostic(DiagOrStoredDiag D,
@@ -91,13 +90,12 @@ protected:
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
public:
- explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
- : LangOpts(0), DiagOpts(diags),
- Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
- {
+ explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags)
+ : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os),
+ EmittedAnyDiagBlocks(false) {
EmitPreamble();
}
-
+
~SDiagsWriter() {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
@@ -124,7 +122,26 @@ private:
/// \brief Emit the META data block.
void EmitMetaBlock();
-
+
+ /// \brief Start a DIAG block.
+ void EnterDiagBlock();
+
+ /// \brief End a DIAG block.
+ void ExitDiagBlock();
+
+ /// \brief Emit a DIAG record.
+ void EmitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ const SourceManager *SM,
+ DiagOrStoredDiag D);
+
+ /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
+ void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM);
+
/// \brief Emit a record for a CharSourceRange.
void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
@@ -159,7 +176,7 @@ private:
enum { Version = 1 };
const LangOptions *LangOpts;
- const DiagnosticOptions &DiagOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// \brief The byte buffer for the serialized content.
SmallString<1024> Buffer;
@@ -190,17 +207,18 @@ private:
/// \brief Map for uniquing strings.
DiagFlagsTy DiagFlags;
-
- /// \brief Flag indicating whether or not we are in the process of
- /// emitting a non-note diagnostic.
- bool inNonNoteDiagnostic;
+
+ /// \brief Whether we have already started emission of any DIAG blocks. Once
+ /// this becomes \c true, we never close a DIAG block until we know that we're
+ /// starting another one or we're done.
+ bool EmittedAnyDiagBlocks;
};
} // end anonymous namespace
namespace clang {
namespace serialized_diags {
DiagnosticConsumer *create(llvm::raw_ostream *OS,
- const DiagnosticOptions &diags) {
+ DiagnosticOptions *diags) {
return new SDiagsWriter(OS, diags);
}
} // end namespace serialized_diags
@@ -474,31 +492,69 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
+ // Enter the block for a non-note diagnostic immediately, rather than waiting
+ // for beginDiagnostic, in case associated notes are emitted before we get
+ // there.
if (DiagLevel != DiagnosticsEngine::Note) {
- if (inNonNoteDiagnostic) {
- // We have encountered a non-note diagnostic. Finish up the previous
- // diagnostic block before starting a new one.
- Stream.ExitBlock();
- }
- inNonNoteDiagnostic = true;
+ if (EmittedAnyDiagBlocks)
+ ExitDiagBlock();
+
+ EnterDiagBlock();
+ EmittedAnyDiagBlocks = true;
}
// Compute the diagnostic text.
- diagBuf.clear();
+ diagBuf.clear();
Info.FormatDiagnostic(diagBuf);
- const SourceManager *
- SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0;
- SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts);
+ if (Info.getLocation().isInvalid()) {
+ // Special-case diagnostics with no location. We may not have entered a
+ // source file in this case, so we can't use the normal DiagnosticsRenderer
+ // machinery.
+ EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
+ diagBuf, 0, &Info);
+ return;
+ }
+
+ assert(Info.hasSourceManager() && LangOpts &&
+ "Unexpected diagnostic with valid location outside of a source file");
+ SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
diagBuf.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()),
- SM,
+ &Info.getSourceManager(),
&Info);
}
+void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ const SourceManager *SM,
+ DiagOrStoredDiag D) {
+ // Emit the RECORD_DIAG record.
+ Record.clear();
+ Record.push_back(RECORD_DIAG);
+ Record.push_back(Level);
+ AddLocToRecord(Loc, SM, PLoc, Record);
+
+ if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
+ // Emit the category string lazily and get the category ID.
+ unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
+ Record.push_back(getEmitCategory(DiagID));
+ // Emit the diagnostic flag string lazily and get the mapped ID.
+ Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
+ } else {
+ Record.push_back(getEmitCategory());
+ Record.push_back(getEmitDiagnosticFlag(Level));
+ }
+
+ Record.push_back(Message.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
+}
+
void
SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
@@ -507,94 +563,80 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
ArrayRef<clang::CharSourceRange> Ranges,
const SourceManager *SM,
DiagOrStoredDiag D) {
- // Emit the RECORD_DIAG record.
- Writer.Record.clear();
- Writer.Record.push_back(RECORD_DIAG);
- Writer.Record.push_back(Level);
- Writer.AddLocToRecord(Loc, SM, PLoc, Record);
+ Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
+}
- if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
- // Emit the category string lazily and get the category ID.
- unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
- Writer.Record.push_back(Writer.getEmitCategory(DiagID));
- // Emit the diagnostic flag string lazily and get the mapped ID.
- Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
- }
- else {
- Writer.Record.push_back(Writer.getEmitCategory());
- Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
- }
+void SDiagsWriter::EnterDiagBlock() {
+ Stream.EnterSubblock(BLOCK_DIAG, 4);
+}
- Writer.Record.push_back(Message.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
- Writer.Record, Message);
+void SDiagsWriter::ExitDiagBlock() {
+ Stream.ExitBlock();
}
void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {
- Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
+ if (Level == DiagnosticsEngine::Note)
+ Writer.EnterDiagBlock();
}
void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {
- if (D && Level != DiagnosticsEngine::Note)
- return;
- Writer.Stream.ExitBlock();
+ // Only end note diagnostics here, because we can't be sure when we've seen
+ // the last note associated with a non-note diagnostic.
+ if (Level == DiagnosticsEngine::Note)
+ Writer.ExitDiagBlock();
}
-void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange> &Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
// Emit Source Ranges.
- for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
- it != ei; ++it) {
- if (it->isValid())
- Writer.EmitCharSourceRange(*it, SM);
- }
-
+ for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I)
+ if (I->isValid())
+ EmitCharSourceRange(*I, SM);
+
// Emit FixIts.
- for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
- it != et; ++it) {
- const FixItHint &fix = *it;
- if (fix.isNull())
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ const FixItHint &Fix = *I;
+ if (Fix.isNull())
continue;
- Writer.Record.clear();
- Writer.Record.push_back(RECORD_FIXIT);
- Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
- Writer.Record.push_back(fix.CodeToInsert.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
- fix.CodeToInsert);
+ Record.clear();
+ Record.push_back(RECORD_FIXIT);
+ AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
+ Record.push_back(Fix.CodeToInsert.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
+ Fix.CodeToInsert);
}
}
+void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
+ Writer.EmitCodeContext(Ranges, Hints, SM);
+}
+
void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
const SourceManager *SM) {
- Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
- RecordData Record;
- Record.push_back(RECORD_DIAG);
- Record.push_back(DiagnosticsEngine::Note);
- Writer.AddLocToRecord(Loc, Record, SM);
- Record.push_back(Writer.getEmitCategory());
- Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
- Record.push_back(Message.size());
- Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
- Record, Message);
- Writer.Stream.ExitBlock();
+ Writer.EnterDiagBlock();
+ PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
+ Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
+ Message, SM, DiagOrStoredDiag());
+ Writer.ExitDiagBlock();
}
void SDiagsWriter::finish() {
- if (inNonNoteDiagnostic) {
- // Finish off any diagnostics we were in the process of emitting.
- Stream.ExitBlock();
- inNonNoteDiagnostic = false;
- }
+ // Finish off any diagnostic we were in the process of emitting.
+ if (EmittedAnyDiagBlocks)
+ ExitDiagBlock();
// Write the generated bitstream to "Out".
OS->write((char *)&Buffer.front(), Buffer.size());
OS->flush();
-
+
OS.reset(0);
}
-
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 9bb3e1dce8c7..35dabad60657 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -11,7 +11,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/ConvertUTF.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -43,19 +43,22 @@ static const enum raw_ostream::Colors savedColor =
/// \brief Add highlights to differences in template strings.
static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
bool &Normal, bool Bold) {
- for (unsigned i = 0, e = Str.size(); i < e; ++i)
- if (Str[i] != ToggleHighlight) {
- OS << Str[i];
- } else {
- if (Normal)
- OS.changeColor(templateColor, true);
- else {
- OS.resetColor();
- if (Bold)
- OS.changeColor(savedColor, true);
- }
- Normal = !Normal;
+ while (1) {
+ size_t Pos = Str.find(ToggleHighlight);
+ OS << Str.slice(0, Pos);
+ if (Pos == StringRef::npos)
+ break;
+
+ Str = Str.substr(Pos + 1);
+ if (Normal)
+ OS.changeColor(templateColor, true);
+ else {
+ OS.resetColor();
+ if (Bold)
+ OS.changeColor(savedColor, true);
}
+ Normal = !Normal;
+ }
}
/// \brief Number of spaces to indent when word-wrapping.
@@ -110,28 +113,15 @@ printableTextForNextCharacter(StringRef SourceLine, size_t *i,
return std::make_pair(expandedTab, true);
}
- // FIXME: this data is copied from the private implementation of ConvertUTF.h
- static const char trailingBytesForUTF8[256] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
- };
-
unsigned char const *begin, *end;
begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i));
- end = begin + SourceLine.size();
+ end = begin + (SourceLine.size() - *i);
if (isLegalUTF8Sequence(begin, end)) {
UTF32 c;
UTF32 *cptr = &c;
unsigned char const *original_begin = begin;
- char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]];
- unsigned char const *cp_end = begin+trailingBytes+1;
+ unsigned char const *cp_end = begin+getNumBytesForUTF8(SourceLine[*i]);
ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1,
strictConversion);
@@ -274,14 +264,44 @@ struct SourceColumnMap {
}
int columns() const { return m_byteToColumn.back(); }
int bytes() const { return m_columnToByte.back(); }
+
+ /// \brief Map a byte to the column which it is at the start of, or return -1
+ /// if it is not at the start of a column (for a UTF-8 trailing byte).
int byteToColumn(int n) const {
assert(0<=n && n<static_cast<int>(m_byteToColumn.size()));
return m_byteToColumn[n];
}
+
+ /// \brief Map a byte to the first column which contains it.
+ int byteToContainingColumn(int N) const {
+ assert(0 <= N && N < static_cast<int>(m_byteToColumn.size()));
+ while (m_byteToColumn[N] == -1)
+ --N;
+ return m_byteToColumn[N];
+ }
+
+ /// \brief Map a column to the byte which starts the column, or return -1 if
+ /// the column the second or subsequent column of an expanded tab or similar
+ /// multi-column entity.
int columnToByte(int n) const {
assert(0<=n && n<static_cast<int>(m_columnToByte.size()));
return m_columnToByte[n];
}
+
+ /// \brief Map from a byte index to the next byte which starts a column.
+ int startOfNextColumn(int N) const {
+ assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1));
+ while (byteToColumn(++N) == -1) {}
+ return N;
+ }
+
+ /// \brief Map from a byte index to the previous byte which starts a column.
+ int startOfPreviousColumn(int N) const {
+ assert(0 < N && N < static_cast<int>(m_columnToByte.size()));
+ while (byteToColumn(--N) == -1) {}
+ return N;
+ }
+
StringRef getSourceLine() const {
return m_SourceLine;
}
@@ -398,25 +418,24 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
bool ExpandedRegion = false;
if (SourceStart>0) {
- unsigned NewStart = SourceStart-1;
+ unsigned NewStart = map.startOfPreviousColumn(SourceStart);
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
+ // FIXME: Detect non-ASCII whitespace characters too.
while (NewStart &&
- (map.byteToColumn(NewStart)==-1 ||
- isspace(static_cast<unsigned char>(SourceLine[NewStart]))))
- --NewStart;
+ isspace(static_cast<unsigned char>(SourceLine[NewStart])))
+ NewStart = map.startOfPreviousColumn(NewStart);
// Skip over this bit of "interesting" text.
- while (NewStart &&
- (map.byteToColumn(NewStart)!=-1 &&
- !isspace(static_cast<unsigned char>(SourceLine[NewStart]))))
- --NewStart;
-
- // Move up to the non-whitespace character we just saw.
- if (NewStart)
- ++NewStart;
+ while (NewStart) {
+ unsigned Prev = map.startOfPreviousColumn(NewStart);
+ if (isspace(static_cast<unsigned char>(SourceLine[Prev])))
+ break;
+ NewStart = Prev;
+ }
+ assert(map.byteToColumn(NewStart) != -1);
unsigned NewColumns = map.byteToColumn(SourceEnd) -
map.byteToColumn(NewStart);
if (NewColumns <= TargetColumns) {
@@ -426,21 +445,21 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
}
if (SourceEnd<SourceLine.size()) {
- unsigned NewEnd = SourceEnd+1;
+ unsigned NewEnd = map.startOfNextColumn(SourceEnd);
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
- while (NewEnd<SourceLine.size() &&
- (map.byteToColumn(NewEnd)==-1 ||
- isspace(static_cast<unsigned char>(SourceLine[NewEnd]))))
- ++NewEnd;
+ // FIXME: Detect non-ASCII whitespace characters too.
+ while (NewEnd < SourceLine.size() &&
+ isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ NewEnd = map.startOfNextColumn(NewEnd);
// Skip over this bit of "interesting" text.
- while (NewEnd<SourceLine.size() &&
- (map.byteToColumn(NewEnd)!=-1 &&
- !isspace(static_cast<unsigned char>(SourceLine[NewEnd]))))
- ++NewEnd;
+ while (NewEnd < SourceLine.size() &&
+ !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ NewEnd = map.startOfNextColumn(NewEnd);
+ assert(map.byteToColumn(NewEnd) != -1);
unsigned NewColumns = map.byteToColumn(NewEnd) -
map.byteToColumn(SourceStart);
if (NewColumns <= TargetColumns) {
@@ -475,7 +494,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// The line needs some trunctiona, and we'd prefer to keep the front
// if possible, so remove the back
- if (BackColumnsRemoved)
+ if (BackColumnsRemoved > strlen(back_ellipse))
SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
// If that's enough then we're done
@@ -483,7 +502,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
return;
// Otherwise remove the front as well
- if (FrontColumnsRemoved) {
+ if (FrontColumnsRemoved > strlen(front_ellipse)) {
SourceLine.replace(0, SourceStart, front_ellipse);
CaretLine.replace(0, CaretStart, front_space);
if (!FixItInsertionLine.empty())
@@ -651,7 +670,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str,
TextDiagnostic::TextDiagnostic(raw_ostream &OS,
const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
+ DiagnosticOptions *DiagOpts)
: DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {}
TextDiagnostic::~TextDiagnostic() {}
@@ -670,13 +689,13 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
if (Loc.isValid())
emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
- printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
printDiagnosticMessage(OS, Level, Message,
OS.tell() - StartOfLocationInfo,
- DiagOpts.MessageLength, DiagOpts.ShowColors);
+ DiagOpts->MessageLength, DiagOpts->ShowColors);
}
/*static*/ void
@@ -770,36 +789,36 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
}
unsigned LineNo = PLoc.getLine();
- if (!DiagOpts.ShowLocation)
+ if (!DiagOpts->ShowLocation)
return;
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
OS << PLoc.getFilename();
- switch (DiagOpts.Format) {
+ switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
}
- if (DiagOpts.ShowColumn)
+ if (DiagOpts->ShowColumn)
// Compute the column number.
if (unsigned ColNo = PLoc.getColumn()) {
- if (DiagOpts.Format == DiagnosticOptions::Msvc) {
+ if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) {
OS << ',';
ColNo--;
} else
OS << ':';
OS << ColNo;
}
- switch (DiagOpts.Format) {
+ switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang:
case DiagnosticOptions::Vi: OS << ':'; break;
case DiagnosticOptions::Msvc: OS << ") : "; break;
}
- if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
+ if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
FileID CaretFileID =
SM.getFileID(SM.getExpansionLoc(Loc));
bool PrintedRange = false;
@@ -858,7 +877,7 @@ void TextDiagnostic::emitBasicNote(StringRef Message) {
void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc,
const SourceManager &SM) {
- if (DiagOpts.ShowLocation)
+ if (DiagOpts->ShowLocation)
OS << "In file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":\n";
else
@@ -886,7 +905,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// was part of a different warning or error diagnostic, or if the
// diagnostic has ranges. We don't want to emit the same caret
// multiple times if one loc has multiple diagnostics.
- if (!DiagOpts.ShowCarets)
+ if (!DiagOpts->ShowCarets)
return;
if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
(LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
@@ -924,7 +943,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// length as the line of source code.
std::string CaretLine(LineEnd-LineStart, ' ');
- const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
+ const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
// Highlight all of the characters covered by Ranges with ~ characters.
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
@@ -933,7 +952,7 @@ void TextDiagnostic::emitSnippetAndCaret(
highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM);
// Next, insert the caret itself.
- ColNo = sourceColMap.byteToColumn(ColNo-1);
+ ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
if (CaretLine.size()<ColNo+1)
CaretLine.resize(ColNo+1, ' ');
CaretLine[ColNo] = '^';
@@ -944,7 +963,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// If the source line is too long for our terminal, select only the
// "interesting" source region within that line.
- unsigned Columns = DiagOpts.MessageLength;
+ unsigned Columns = DiagOpts->MessageLength;
if (Columns)
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
Columns, sourceColMap);
@@ -953,7 +972,7 @@ void TextDiagnostic::emitSnippetAndCaret(
// to produce easily machine parsable output. Add a space before the
// source line and the caret to make it trivial to tell the main diagnostic
// line from what the user is intended to see.
- if (DiagOpts.ShowSourceRanges) {
+ if (DiagOpts->ShowSourceRanges) {
SourceLine = ' ' + SourceLine;
CaretLine = ' ' + CaretLine;
}
@@ -965,20 +984,20 @@ void TextDiagnostic::emitSnippetAndCaret(
// Emit what we have computed.
emitSnippet(SourceLine);
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.changeColor(caretColor, true);
OS << CaretLine << '\n';
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
if (!FixItInsertionLine.empty()) {
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
// Print fixit line in color
OS.changeColor(fixitColor, false);
- if (DiagOpts.ShowSourceRanges)
+ if (DiagOpts->ShowSourceRanges)
OS << ' ';
OS << FixItInsertionLine << '\n';
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
}
@@ -997,15 +1016,15 @@ void TextDiagnostic::emitSnippet(StringRef line) {
while (i<line.size()) {
std::pair<SmallString<16>,bool> res
- = printableTextForNextCharacter(line, &i, DiagOpts.TabStop);
+ = printableTextForNextCharacter(line, &i, DiagOpts->TabStop);
bool was_printable = res.second;
- if (DiagOpts.ShowColors && was_printable == print_reversed) {
+ if (DiagOpts->ShowColors && was_printable == print_reversed) {
if (print_reversed)
OS.reverseColor();
OS << to_print;
to_print.clear();
- if (DiagOpts.ShowColors)
+ if (DiagOpts->ShowColors)
OS.resetColor();
}
@@ -1013,10 +1032,10 @@ void TextDiagnostic::emitSnippet(StringRef line) {
to_print += res.first.str();
}
- if (print_reversed && DiagOpts.ShowColors)
+ if (print_reversed && DiagOpts->ShowColors)
OS.reverseColor();
OS << to_print;
- if (print_reversed && DiagOpts.ShowColors)
+ if (print_reversed && DiagOpts->ShowColors)
OS.resetColor();
OS << '\n';
@@ -1030,16 +1049,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
const SourceManager &SM) {
if (!R.isValid()) return;
- SourceLocation Begin = SM.getExpansionLoc(R.getBegin());
- SourceLocation End = SM.getExpansionLoc(R.getEnd());
-
- // If the End location and the start location are the same and are a macro
- // location, then the range was something that came from a macro expansion
- // or _Pragma. If this is an object-like macro, the best we can do is to
- // highlight the range. If this is a function-like macro, we'd also like to
- // highlight the arguments.
- if (Begin == End && R.getEnd().isMacroID())
- End = SM.getExpansionRange(R.getEnd()).second;
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
@@ -1080,7 +1091,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
while (StartColNo < map.getSourceLine().size() &&
(map.getSourceLine()[StartColNo] == ' ' ||
map.getSourceLine()[StartColNo] == '\t'))
- ++StartColNo;
+ StartColNo = map.startOfNextColumn(StartColNo);
// Pick the last non-whitespace column.
if (EndColNo > map.getSourceLine().size())
@@ -1088,7 +1099,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
while (EndColNo-1 &&
(map.getSourceLine()[EndColNo-1] == ' ' ||
map.getSourceLine()[EndColNo-1] == '\t'))
- --EndColNo;
+ EndColNo = map.startOfPreviousColumn(EndColNo);
// If the start/end passed each other, then we are trying to highlight a
// range that just exists in whitespace, which must be some sort of other
@@ -1100,8 +1111,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
// Fill the range with ~'s.
- StartColNo = map.byteToColumn(StartColNo);
- EndColNo = map.byteToColumn(EndColNo);
+ StartColNo = map.byteToContainingColumn(StartColNo);
+ EndColNo = map.byteToContainingColumn(EndColNo);
assert(StartColNo <= EndColNo && "Invalid range!");
if (CaretLine.size() < EndColNo)
@@ -1116,7 +1127,7 @@ std::string TextDiagnostic::buildFixItInsertionLine(
const SourceManager &SM) {
std::string FixItInsertionLine;
- if (Hints.empty() || !DiagOpts.ShowFixits)
+ if (Hints.empty() || !DiagOpts->ShowFixits)
return FixItInsertionLine;
unsigned PrevHintEndCol = 0;
@@ -1139,7 +1150,7 @@ std::string TextDiagnostic::buildFixItInsertionLine(
// The hint must start inside the source or right at the end
assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
- unsigned HintCol = map.byteToColumn(HintByteOffset);
+ unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
// If we inserted a long previous hint, push this one forwards, and add
// an extra space to show that this is not part of the previous
@@ -1176,14 +1187,14 @@ std::string TextDiagnostic::buildFixItInsertionLine(
}
}
- expandTabs(FixItInsertionLine, DiagOpts.TabStop);
+ expandTabs(FixItInsertionLine, DiagOpts->TabStop);
return FixItInsertionLine;
}
void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
- if (!DiagOpts.ShowParseableFixits)
+ if (!DiagOpts->ShowParseableFixits)
return;
// We follow FixItRewriter's example in not (yet) handling
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 382e1567c7f4..aa7a61a60f9e 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -25,9 +25,9 @@
using namespace clang;
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
- const DiagnosticOptions &diags,
+ DiagnosticOptions *diags,
bool _OwnsOutputStream)
- : OS(os), DiagOpts(&diags),
+ : OS(os), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -39,7 +39,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
// Build the TextDiagnostic utility.
- TextDiag.reset(new TextDiagnostic(OS, LO, *DiagOpts));
+ TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts));
}
void TextDiagnosticPrinter::EndSourceFile() {
@@ -158,5 +158,5 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DiagnosticConsumer *
TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
- return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false);
+ return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false);
}
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a9378a117d6b..1750946af497 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -31,14 +31,17 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
: Diags(_Diags),
PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()),
Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0),
- ActiveSourceFiles(0)
+ LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives)
{
Diags.takeClient();
+ if (Diags.hasSourceManager())
+ setSourceManager(Diags.getSourceManager());
}
VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
+ SrcManager = 0;
CheckDiagnostics();
Diags.takeClient();
if (OwnsPrimaryClient)
@@ -48,21 +51,20 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
#ifndef NDEBUG
namespace {
class VerifyFileTracker : public PPCallbacks {
- typedef VerifyDiagnosticConsumer::FilesParsedForDirectivesSet ListType;
- ListType &FilesList;
+ VerifyDiagnosticConsumer &Verify;
SourceManager &SM;
public:
- VerifyFileTracker(ListType &FilesList, SourceManager &SM)
- : FilesList(FilesList), SM(SM) { }
+ VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
+ : Verify(Verify), SM(SM) { }
/// \brief Hook into the preprocessor and update the list of parsed
/// files when the preprocessor indicates a new file is entered.
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) {
- if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(Loc)))
- FilesList.insert(E);
+ Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
+ VerifyDiagnosticConsumer::IsParsed);
}
};
} // End anonymous namespace.
@@ -76,10 +78,12 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
if (++ActiveSourceFiles == 1) {
if (PP) {
CurrentPreprocessor = PP;
+ this->LangOpts = &LangOpts;
+ setSourceManager(PP->getSourceManager());
const_cast<Preprocessor*>(PP)->addCommentHandler(this);
#ifndef NDEBUG
- VerifyFileTracker *V = new VerifyFileTracker(FilesParsedForDirectives,
- PP->getSourceManager());
+ // Debug build tracks parsed files.
+ VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager);
const_cast<Preprocessor*>(PP)->addPPCallbacks(V);
#endif
}
@@ -101,18 +105,40 @@ void VerifyDiagnosticConsumer::EndSourceFile() {
// Check diagnostics once last file completed.
CheckDiagnostics();
CurrentPreprocessor = 0;
+ LangOpts = 0;
}
}
void VerifyDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
+ if (Info.hasSourceManager())
+ setSourceManager(Info.getSourceManager());
+
#ifndef NDEBUG
- if (Info.hasSourceManager()) {
- FileID FID = Info.getSourceManager().getFileID(Info.getLocation());
- if (!FID.isInvalid())
- FilesWithDiagnostics.insert(FID);
+ // Debug build tracks unparsed files for possible
+ // unparsed expected-* directives.
+ if (SrcManager) {
+ SourceLocation Loc = Info.getLocation();
+ if (Loc.isValid()) {
+ ParsedStatus PS = IsUnparsed;
+
+ Loc = SrcManager->getExpansionLoc(Loc);
+ FileID FID = SrcManager->getFileID(Loc);
+
+ const FileEntry *FE = SrcManager->getFileEntryForID(FID);
+ if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
+ // If the file is a modules header file it shall not be parsed
+ // for expected-* directives.
+ HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
+ if (HS.findModuleForHeader(FE))
+ PS = IsUnparsedNoDirectives;
+ }
+
+ UpdateParsedFileStatus(*SrcManager, FID, PS);
+ }
}
#endif
+
// Send the diagnostic to the buffer, we will check it once we reach the end
// of the source file (or are destructed).
Buffer->HandleDiagnostic(DiagLevel, Info);
@@ -200,10 +226,22 @@ public:
// Return true if string literal is found.
// When true, P marks begin-position of S in content.
- bool Search(StringRef S) {
- P = std::search(C, End, S.begin(), S.end());
- PEnd = P + S.size();
- return P != End;
+ bool Search(StringRef S, bool EnsureStartOfWord = false) {
+ do {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.size();
+ if (P == End)
+ break;
+ if (!EnsureStartOfWord
+ // Check if string literal starts a new word.
+ || P == Begin || isspace(P[-1])
+ // Or it could be preceeded by the start of a comment.
+ || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
+ && P[-2] == '/'))
+ return true;
+ // Otherwise, skip and search again.
+ } while (Advance());
+ return false;
}
// Advance 1-past previous next/search.
@@ -240,12 +278,13 @@ private:
///
/// Returns true if any valid directives were found.
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
- SourceLocation Pos, DiagnosticsEngine &Diags) {
+ SourceLocation Pos, DiagnosticsEngine &Diags,
+ VerifyDiagnosticConsumer::DirectiveStatus &Status) {
// A single comment may contain multiple directives.
bool FoundDirective = false;
for (ParseHelper PH(S); !PH.Done();) {
// Search for token: expected
- if (!PH.Search("expected"))
+ if (!PH.Search("expected", true))
break;
PH.Advance();
@@ -262,10 +301,24 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
DL = ED ? &ED->Warnings : NULL;
else if (PH.Next("note"))
DL = ED ? &ED->Notes : NULL;
- else
+ else if (PH.Next("no-diagnostics")) {
+ if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
+ Diags.Report(Pos, diag::err_verify_invalid_no_diags)
+ << /*IsExpectedNoDiagnostics=*/true;
+ else
+ Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
+ continue;
+ } else
continue;
PH.Advance();
+ if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
+ Diags.Report(Pos, diag::err_verify_invalid_no_diags)
+ << /*IsExpectedNoDiagnostics=*/false;
+ continue;
+ }
+ Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
+
// If a directive has been found but we're not interested
// in storing the directive information, return now.
if (!DL)
@@ -412,7 +465,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
// Fold any "\<EOL>" sequences
size_t loc = C.find('\\');
if (loc == StringRef::npos) {
- ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics());
+ ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status);
return false;
}
@@ -442,7 +495,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
}
if (!C2.empty())
- ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics());
+ ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status);
return false;
}
@@ -452,34 +505,36 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
/// Preprocessor, directives inside skipped #if blocks will still be found.
///
/// \return true if any directives were found.
-static bool findDirectives(const Preprocessor &PP, FileID FID) {
+static bool findDirectives(SourceManager &SM, FileID FID,
+ const LangOptions &LangOpts) {
// Create a raw lexer to pull all the comments out of FID.
if (FID.isInvalid())
return false;
- SourceManager& SM = PP.getSourceManager();
// Create a lexer to lex all the tokens of the main file in raw mode.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
- Lexer RawLex(FID, FromFile, SM, PP.getLangOpts());
+ Lexer RawLex(FID, FromFile, SM, LangOpts);
// Return comments as tokens, this is how we find expected diagnostics.
RawLex.SetCommentRetentionState(true);
Token Tok;
Tok.setKind(tok::comment);
- bool Found = false;
+ VerifyDiagnosticConsumer::DirectiveStatus Status =
+ VerifyDiagnosticConsumer::HasNoDirectives;
while (Tok.isNot(tok::eof)) {
RawLex.Lex(Tok);
if (!Tok.is(tok::comment)) continue;
- std::string Comment = PP.getSpelling(Tok);
+ std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
if (Comment.empty()) continue;
- // Find all expected errors/warnings/notes.
- Found |= ParseDirective(Comment, 0, SM, Tok.getLocation(),
- PP.getDiagnostics());
+ // Find first directive.
+ if (ParseDirective(Comment, 0, SM, Tok.getLocation(),
+ SM.getDiagnostics(), Status))
+ return true;
}
- return Found;
+ return false;
}
#endif // !NDEBUG
@@ -601,41 +656,95 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
return NumProblems;
}
+void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
+ FileID FID,
+ ParsedStatus PS) {
+ // Check SourceManager hasn't changed.
+ setSourceManager(SM);
+
+#ifndef NDEBUG
+ if (FID.isInvalid())
+ return;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+
+ if (PS == IsParsed) {
+ // Move the FileID from the unparsed set to the parsed set.
+ UnparsedFiles.erase(FID);
+ ParsedFiles.insert(std::make_pair(FID, FE));
+ } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
+ // Add the FileID to the unparsed set if we haven't seen it before.
+
+ // Check for directives.
+ bool FoundDirectives;
+ if (PS == IsUnparsedNoDirectives)
+ FoundDirectives = false;
+ else
+ FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
+
+ // Add the FileID to the unparsed set.
+ UnparsedFiles.insert(std::make_pair(FID,
+ UnparsedFileStatus(FE, FoundDirectives)));
+ }
+#endif
+}
+
void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Ensure any diagnostics go to the primary client.
bool OwnsCurClient = Diags.ownsClient();
DiagnosticConsumer *CurClient = Diags.takeClient();
Diags.setClient(PrimaryClient, false);
- // If we have a preprocessor, scan the source for expected diagnostic
- // markers. If not then any diagnostics are unexpected.
- if (CurrentPreprocessor) {
- SourceManager &SM = CurrentPreprocessor->getSourceManager();
-
#ifndef NDEBUG
- // In a debug build, scan through any files that may have been missed
- // during parsing and issue a fatal error if directives are contained
- // within these files. If a fatal error occurs, this suggests that
- // this file is being parsed separately from the main file.
- HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
- for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(),
- End = FilesWithDiagnostics.end();
- I != End; ++I) {
- const FileEntry *E = SM.getFileEntryForID(*I);
- // Don't check files already parsed or those handled as modules.
- if (E && (FilesParsedForDirectives.count(E)
- || HS.findModuleForHeader(E)))
+ // In a debug build, scan through any files that may have been missed
+ // during parsing and issue a fatal error if directives are contained
+ // within these files. If a fatal error occurs, this suggests that
+ // this file is being parsed separately from the main file, in which
+ // case consider moving the directives to the correct place, if this
+ // is applicable.
+ if (UnparsedFiles.size() > 0) {
+ // Generate a cache of parsed FileEntry pointers for alias lookups.
+ llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
+ for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
+ End = ParsedFiles.end(); I != End; ++I) {
+ if (const FileEntry *FE = I->second)
+ ParsedFileCache.insert(FE);
+ }
+
+ // Iterate through list of unparsed files.
+ for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
+ End = UnparsedFiles.end(); I != End; ++I) {
+ const UnparsedFileStatus &Status = I->second;
+ const FileEntry *FE = Status.getFile();
+
+ // Skip files that have been parsed via an alias.
+ if (FE && ParsedFileCache.count(FE))
continue;
- if (findDirectives(*CurrentPreprocessor, *I))
+ // Report a fatal error if this file contained directives.
+ if (Status.foundDirectives()) {
llvm::report_fatal_error(Twine("-verify directives found after rather"
" than during normal parsing of ",
- StringRef(E ? E->getName() : "(unknown)")));
+ StringRef(FE ? FE->getName() : "(unknown)")));
+ }
+ }
+
+ // UnparsedFiles has been processed now, so clear it.
+ UnparsedFiles.clear();
+ }
+#endif // !NDEBUG
+
+ if (SrcManager) {
+ // Produce an error if no expected-* directives could be found in the
+ // source file(s) processed.
+ if (Status == HasNoDirectives) {
+ Diags.Report(diag::err_verify_no_directives).setForceEmit();
+ ++NumErrors;
+ Status = HasNoDirectivesReported;
}
-#endif
// Check that the expected diagnostics occurred.
- NumErrors += CheckResults(Diags, SM, *Buffer, ED);
+ NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
} else {
NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(),
Buffer->err_end(), "error") +
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index b7d4a3b92538..f789b7f3053f 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -24,7 +24,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include <cstring>
#include <utility>
@@ -51,8 +51,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
- Diags.setShowOverloads(
- static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads));
+ Diags.setShowOverloads(Opts.getShowOverloads());
Diags.setElideType(Opts.ElideType);
Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index fe9d5896e728..176511b0e4c8 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -11,7 +11,8 @@ add_dependencies(clangFrontendTool
target_link_libraries(clangFrontendTool
clangDriver
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangCodeGen
clangStaticAnalyzerFrontend
clangStaticAnalyzerCheckers
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index bd50083bf1c9..c7c55b021145 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -16,6 +16,7 @@
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -23,7 +24,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
-#include "clang/Rewrite/FrontendActions.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
using namespace clang;
@@ -137,7 +138,9 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
if (Clang->getFrontendOpts().ShowHelp) {
OwningPtr<driver::OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
- "LLVM 'Clang' Compiler: http://clang.llvm.org");
+ "LLVM 'Clang' Compiler: http://clang.llvm.org",
+ /*Include=*/driver::options::CC1Option,
+ /*Exclude=*/0);
return 0;
}
@@ -175,7 +178,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -analyzer-checker-help.
// This should happen AFTER plugins have been loaded!
- if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
+ if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
return 0;
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 6e9cc68540b6..25e4d903bb78 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -6,6 +6,7 @@ set(files
bmiintrin.h
bmi2intrin.h
emmintrin.h
+ f16cintrin.h
float.h
fma4intrin.h
fmaintrin.h
@@ -19,6 +20,7 @@ set(files
nmmintrin.h
pmmintrin.h
popcntintrin.h
+ rtmintrin.h
smmintrin.h
stdalign.h
stdarg.h
@@ -29,6 +31,8 @@ set(files
tmmintrin.h
varargs.h
wmmintrin.h
+ __wmmintrin_aes.h
+ __wmmintrin_pclmul.h
x86intrin.h
xmmintrin.h
xopintrin.h
diff --git a/lib/Headers/__wmmintrin_aes.h b/lib/Headers/__wmmintrin_aes.h
new file mode 100644
index 000000000000..2bfa027e07b1
--- /dev/null
+++ b/lib/Headers/__wmmintrin_aes.h
@@ -0,0 +1,67 @@
+/*===---- __wmmintrin_aes.h - AES 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 _WMMINTRIN_AES_H
+#define _WMMINTRIN_AES_H
+
+#include <emmintrin.h>
+
+#if !defined (__AES__)
+# error "AES instructions not enabled"
+#else
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenc_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenc128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdec_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdec128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdeclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdeclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesimc_si128(__m128i __V)
+{
+ return (__m128i)__builtin_ia32_aesimc128(__V);
+}
+
+#define _mm_aeskeygenassist_si128(C, R) \
+ __builtin_ia32_aeskeygenassist128((C), (R))
+
+#endif
+
+#endif /* _WMMINTRIN_AES_H */
diff --git a/lib/Headers/__wmmintrin_pclmul.h b/lib/Headers/__wmmintrin_pclmul.h
new file mode 100644
index 000000000000..8d1f1b7c0868
--- /dev/null
+++ b/lib/Headers/__wmmintrin_pclmul.h
@@ -0,0 +1,34 @@
+/*===---- __wmmintrin_pclmul.h - AES 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 _WMMINTRIN_PCLMUL_H
+#define _WMMINTRIN_PCLMUL_H
+
+#if !defined (__PCLMUL__)
+# error "PCLMUL instruction is not enabled"
+#else
+#define _mm_clmulepi64_si128(__X, __Y, __I) \
+ ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \
+ (__v2di)(__m128i)(__Y), (char)(__I)))
+#endif
+
+#endif /* _WMMINTRIN_PCLMUL_H */
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index a225378c3062..2bf53fb43b9b 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -4363,14 +4363,14 @@ vec_perm(vector float a, vector float b, vector unsigned char c)
/* vec_vperm */
-vector signed char __ATTRS_o_ai
+static vector signed char __ATTRS_o_ai
vec_vperm(vector signed char a, vector signed char b, vector unsigned char c)
{
return (vector signed char)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector unsigned char __ATTRS_o_ai
+static vector unsigned char __ATTRS_o_ai
vec_vperm(vector unsigned char a,
vector unsigned char b,
vector unsigned char c)
@@ -4379,21 +4379,21 @@ vec_vperm(vector unsigned char a,
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool char __ATTRS_o_ai
+static vector bool char __ATTRS_o_ai
vec_vperm(vector bool char a, vector bool char b, vector unsigned char c)
{
return (vector bool char)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector short __ATTRS_o_ai
+static vector short __ATTRS_o_ai
vec_vperm(vector short a, vector short b, vector unsigned char c)
{
return (vector short)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector unsigned short __ATTRS_o_ai
+static vector unsigned short __ATTRS_o_ai
vec_vperm(vector unsigned short a,
vector unsigned short b,
vector unsigned char c)
@@ -4402,41 +4402,41 @@ vec_vperm(vector unsigned short a,
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool short __ATTRS_o_ai
+static vector bool short __ATTRS_o_ai
vec_vperm(vector bool short a, vector bool short b, vector unsigned char c)
{
return (vector bool short)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector pixel __ATTRS_o_ai
+static vector pixel __ATTRS_o_ai
vec_vperm(vector pixel a, vector pixel b, vector unsigned char c)
{
return (vector pixel)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector int __ATTRS_o_ai
+static vector int __ATTRS_o_ai
vec_vperm(vector int a, vector int b, vector unsigned char c)
{
return (vector int)__builtin_altivec_vperm_4si(a, b, c);
}
-vector unsigned int __ATTRS_o_ai
+static vector unsigned int __ATTRS_o_ai
vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
{
return (vector unsigned int)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector bool int __ATTRS_o_ai
+static vector bool int __ATTRS_o_ai
vec_vperm(vector bool int a, vector bool int b, vector unsigned char c)
{
return (vector bool int)
__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
}
-vector float __ATTRS_o_ai
+static vector float __ATTRS_o_ai
vec_vperm(vector float a, vector float b, vector unsigned char c)
{
return (vector float)
@@ -4445,7 +4445,7 @@ vec_vperm(vector float a, vector float b, vector unsigned char c)
/* vec_re */
-vector float __attribute__((__always_inline__))
+static vector float __attribute__((__always_inline__))
vec_re(vector float a)
{
return __builtin_altivec_vrefp(a);
@@ -4453,7 +4453,7 @@ vec_re(vector float a)
/* vec_vrefp */
-vector float __attribute__((__always_inline__))
+static vector float __attribute__((__always_inline__))
vec_vrefp(vector float a)
{
return __builtin_altivec_vrefp(a);
diff --git a/lib/Headers/bmi2intrin.h b/lib/Headers/bmi2intrin.h
index c60b0c439315..a05cfad3d027 100644
--- a/lib/Headers/bmi2intrin.h
+++ b/lib/Headers/bmi2intrin.h
@@ -70,6 +70,25 @@ _pext_u64(unsigned long long __X, unsigned long long __Y)
return __builtin_ia32_pext_di(__X, __Y);
}
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_mulx_u64 (unsigned long long __X, unsigned long long __Y,
+ unsigned long long *__P)
+{
+ unsigned __int128 __res = (unsigned __int128) __X * __Y;
+ *__P = (unsigned long long) (__res >> 64);
+ return (unsigned long long) __res;
+}
+
+#else /* !__x86_64__ */
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_mulx_u32 (unsigned int __X, unsigned int __Y, unsigned int *__P)
+{
+ unsigned long long __res = (unsigned long long) __X * __Y;
+ *__P = (unsigned int) (__res >> 32);
+ return (unsigned int) __res;
+}
+
#endif /* !__x86_64__ */
#endif /* __BMI2INTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 05c293f6bd96..33df7c2d19f0 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -28,6 +28,6 @@
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));
+ __asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level));
return 1;
}
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
new file mode 100644
index 000000000000..2c96952446d6
--- /dev/null
+++ b/lib/Headers/f16cintrin.h
@@ -0,0 +1,58 @@
+/*===---- f16cintrin.h - F16C 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.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H
+#error "Never use <f16cintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __F16C__
+# error "F16C instruction is not enabled"
+#endif /* __F16C__ */
+
+#ifndef __F16CINTRIN_H
+#define __F16CINTRIN_H
+
+typedef float __v8sf __attribute__ ((__vector_size__ (32)));
+typedef float __m256 __attribute__ ((__vector_size__ (32)));
+
+#define _mm_cvtps_ph(a, imm) __extension__ ({ \
+ __m128 __a = (a); \
+ (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)__a, (imm)); })
+
+#define _mm256_cvtps_ph(a, imm) __extension__ ({ \
+ __m256 __a = (a); \
+ (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); })
+
+static __inline __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_cvtph_ps(__m128i a)
+{
+ return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)a);
+}
+
+static __inline __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtph_ps(__m128i a)
+{
+ return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)a);
+}
+
+#endif /* __F16CINTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index 15b65f3fd8c6..cd733bfc71d3 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -98,4 +98,8 @@ _rdrand64_step(unsigned long long *__p)
#endif
#endif /* __RDRND__ */
+#ifdef __RTM__
+#include <rtmintrin.h>
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
index 418ba5009094..b24bccc12056 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.map
@@ -25,6 +25,11 @@ module _Builtin_intrinsics [system] {
header "mmintrin.h"
}
+ explicit module f16c {
+ requires f16c
+ header "f16cintrin.h"
+ }
+
explicit module sse {
requires sse
export mmx
@@ -62,6 +67,12 @@ module _Builtin_intrinsics [system] {
header "nmmintrin.h"
}
+ explicit module sse4a {
+ requires sse4a
+ export sse3
+ header "ammintrin.h"
+ }
+
explicit module avx {
requires avx
export sse4_2
@@ -84,6 +95,11 @@ module _Builtin_intrinsics [system] {
header "bmi2intrin.h"
}
+ explicit module fma {
+ requires fma
+ header "fmaintrin.h"
+ }
+
explicit module fma4 {
requires fma4
export sse3
@@ -104,5 +120,26 @@ module _Builtin_intrinsics [system] {
requires mm3dnow
header "mm3dnow.h"
}
+
+ explicit module xop {
+ requires xop
+ export fma4
+ header "xopintrin.h"
+ }
+
+ explicit module aes_pclmul {
+ requires aes, pclmul
+ header "wmmintrin.h"
+ }
+
+ explicit module aes {
+ requires aes
+ header "__wmmintrin_aes.h"
+ }
+
+ explicit module pclmul {
+ requires pclmul
+ header "__wmmintrin_pclmul.h"
+ }
}
}
diff --git a/lib/Headers/rtmintrin.h b/lib/Headers/rtmintrin.h
new file mode 100644
index 000000000000..bdc2b994264f
--- /dev/null
+++ b/lib/Headers/rtmintrin.h
@@ -0,0 +1,49 @@
+/*===---- rtmintrin.h - RTM 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 <rtmintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#define _XBEGIN_STARTED (~0u)
+#define _XABORT_EXPLICIT (1 << 0)
+#define _XABORT_RETRY (1 << 1)
+#define _XABORT_CONFLICT (1 << 2)
+#define _XABORT_CAPACITY (1 << 3)
+#define _XABORT_DEBUG (1 << 4)
+#define _XABORT_NESTED (1 << 5)
+#define _XABORT_CODE(x) (((x) >> 24) & 0xFF)
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_xbegin(void)
+{
+ return __builtin_ia32_xbegin();
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_xend(void)
+{
+ __builtin_ia32_xend();
+}
+
+#define _xabort(imm) __builtin_ia32_xabort((imm))
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index a0659203b15c..6520b8316f3d 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -100,7 +100,7 @@ typedef enum {
_UVRSR_FAILED = 2
} _Unwind_VRS_Result;
-_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *context,
_Unwind_VRS_RegClass regclass,
uint32_t regno,
_Unwind_VRS_DataRepresentation representation,
diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h
index dca896fd65d8..369e3c208e53 100644
--- a/lib/Headers/wmmintrin.h
+++ b/lib/Headers/wmmintrin.h
@@ -31,48 +31,11 @@
#else
#ifdef __AES__
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesenc_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesenc128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesenclast_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesenclast128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesdec_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesdec128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesdeclast_si128(__m128i __V, __m128i __R)
-{
- return (__m128i)__builtin_ia32_aesdeclast128(__V, __R);
-}
-
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_aesimc_si128(__m128i __V)
-{
- return (__m128i)__builtin_ia32_aesimc128(__V);
-}
-
-#define _mm_aeskeygenassist_si128(C, R) \
- __builtin_ia32_aeskeygenassist128((C), (R))
-
+#include <__wmmintrin_aes.h>
#endif /* __AES__ */
#ifdef __PCLMUL__
-
-#define _mm_clmulepi64_si128(__X, __Y, __I) \
- ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \
- (__v2di)(__m128i)(__Y), (char)(__I)))
-
+#include <__wmmintrin_pclmul.h>
#endif /* __PCLMUL__ */
#endif /* __AES__ || __PCLMUL__ */
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 556cd011f05d..68ce106be308 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -58,6 +58,10 @@
#include <xopintrin.h>
#endif
+#ifdef __F16C__
+#include <f16cintrin.h>
+#endif
+
// FIXME: LWP
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e616157b047c..e2480ec7a0e3 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -95,7 +95,8 @@ _mm_div_ps(__m128 a, __m128 b)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_ss(__m128 a)
{
- return __builtin_ia32_sqrtss(a);
+ __m128 c = __builtin_ia32_sqrtss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -107,7 +108,8 @@ _mm_sqrt_ps(__m128 a)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rcp_ss(__m128 a)
{
- return __builtin_ia32_rcpss(a);
+ __m128 c = __builtin_ia32_rcpss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
@@ -119,7 +121,8 @@ _mm_rcp_ps(__m128 a)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rsqrt_ss(__m128 a)
{
- return __builtin_ia32_rsqrtss(a);
+ __m128 c = __builtin_ia32_rsqrtss(a);
+ return (__m128) { c[0], a[1], a[2], a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index bbfc1df76fdd..7dc0491392cc 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -144,7 +144,7 @@ HMapBucket HeaderMap::getBucket(unsigned BucketNo) const {
sizeof(HMapHeader));
const HMapBucket *BucketPtr = BucketArray+BucketNo;
- if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
+ if ((const char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) {
Result.Prefix = 0;
Result.Suffix = 0;
return Result; // Invalid buffer, corrupt hmap.
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index bb3a67378ad5..67000b682982 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/Diagnostic.h"
@@ -38,10 +39,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+ FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
- : FileMgr(FM), Diags(Diags), FrameworkMap(64),
+ : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
{
AngledDirIdx = 0;
@@ -905,7 +907,20 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
SubmodulePath.push_back(Name);
// Walk the directory structure to find any enclosing frameworks.
+#ifdef LLVM_ON_UNIX
+ // Note: as an egregious but useful hack we use the real path here, because
+ // 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.
+ char RealDirName[PATH_MAX];
+ StringRef DirName;
+ if (realpath(Dir->getName(), RealDirName))
+ DirName = RealDirName;
+ else
+ DirName = Dir->getName();
+#else
StringRef DirName = Dir->getName();
+#endif
do {
// Get the parent directory name.
DirName = llvm::sys::path::parent_path(DirName);
@@ -924,7 +939,33 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
TopFrameworkDir = Dir;
}
} while (true);
-
+
+ // Determine whether we're allowed to infer a module map.
+ bool canInfer = false;
+ if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) {
+ // Figure out the parent path.
+ StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName());
+ if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
+ // If there's a module map file in the parent directory, it can
+ // explicitly allow us to infer framework modules.
+ switch (loadModuleMapFile(ParentDir)) {
+ case LMM_AlreadyLoaded:
+ case LMM_NewlyLoaded: {
+ StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName());
+ canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem);
+ break;
+ }
+ case LMM_InvalidModuleMap:
+ case LMM_NoDirectory:
+ break;
+ }
+ }
+ }
+
+ // If we're not allowed to infer a module map, we're done.
+ if (!canInfer)
+ return 0;
+
// Try to infer a module map from the top-level framework directory.
Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
TopFrameworkDir,
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 5212dd86e7a1..a5ba7dbe0a93 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -513,10 +513,13 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
const unsigned StartOffset = 1;
- SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset);
- Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(),
+ SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset);
+ Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
-
+
+ // StartLoc will differ from FileLoc if there is a BOM that was skipped.
+ SourceLocation StartLoc = TheLexer.getSourceLocation();
+
bool InPreprocessorDirective = false;
Token TheTok;
Token IfStartTok;
@@ -1534,7 +1537,7 @@ FinishIdentifier:
/// isHexaLiteral - Return true if Start points to a hex constant.
/// in microsoft mode (where this is supposed to be several different tokens).
-static bool isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
+bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
unsigned Size;
char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts);
if (C1 != '0')
@@ -1813,17 +1816,18 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
while (C != '\'') {
// Skip escaped characters.
- if (C == '\\') {
- // Skip the escaped character.
- // FIXME: UCN's
- getAndAdvanceChar(CurPtr, Result);
- } else if (C == '\n' || C == '\r' || // Newline.
- (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (C == '\\')
+ C = getAndAdvanceChar(CurPtr, Result);
+
+ if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
- } else if (C == 0) {
+ }
+
+ if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
@@ -1895,21 +1899,21 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
return false;
}
-// SkipBCPLComment - We have just read the // characters from input. Skip until
-// we find the newline character thats terminate the comment. Then update
-/// BufferPtr and return.
+/// We have just read the // characters from input. Skip until we find the
+/// newline character thats terminate the comment. Then update BufferPtr and
+/// return.
///
/// If we're in KeepCommentMode or any CommentHandler has inserted
/// some tokens, this will store the first token and return true.
-bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
- // If BCPL comments aren't explicitly enabled for this language, emit an
+bool Lexer::SkipLineComment(Token &Result, const char *CurPtr) {
+ // If Line comments aren't explicitly enabled for this language, emit an
// extension warning.
- if (!LangOpts.BCPLComment && !isLexingRawMode()) {
- Diag(BufferPtr, diag::ext_bcpl_comment);
+ if (!LangOpts.LineComment && !isLexingRawMode()) {
+ Diag(BufferPtr, diag::ext_line_comment);
// Mark them enabled so we only emit one warning for this translation
// unit.
- LangOpts.BCPLComment = true;
+ LangOpts.LineComment = true;
}
// Scan over the body of the comment. The common case, when scanning, is that
@@ -1973,7 +1977,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
}
if (!isLexingRawMode())
- Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment);
+ Diag(OldPtr-1, diag::ext_multi_line_line_comment);
break;
}
}
@@ -2002,7 +2006,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
// If we are returning comments as tokens, return this comment as a token.
if (inKeepCommentMode())
- return SaveBCPLComment(Result, CurPtr);
+ return SaveLineComment(Result, CurPtr);
// If we are inside a preprocessor directive and we see the end of line,
// return immediately, so that the lexer can return this as an EOD token.
@@ -2026,9 +2030,9 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
return false;
}
-/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in
-/// an appropriate way and return it.
-bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
+/// If in save-comment mode, package up this Line comment in an appropriate
+/// way and return it.
+bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) {
// If we're not in a preprocessor directive, just return the // comment
// directly.
FormTokenWithChars(Result, CurPtr, tok::comment);
@@ -2036,19 +2040,19 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
if (!ParsingPreprocessorDirective || LexingRawMode)
return true;
- // If this BCPL-style comment is in a macro definition, transmogrify it into
+ // If this Line-style comment is in a macro definition, transmogrify it into
// a C-style block comment.
bool Invalid = false;
std::string Spelling = PP->getSpelling(Result, &Invalid);
if (Invalid)
return true;
- assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
+ assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?");
Spelling[1] = '*'; // Change prefix to "/*".
Spelling += "*/"; // add suffix.
Result.setKind(tok::comment);
- PP->CreateString(&Spelling[0], Spelling.size(), Result,
+ PP->CreateString(Spelling, Result,
Result.getLocation(), Result.getLocation());
return true;
}
@@ -2179,7 +2183,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
#ifdef __SSE2__
__m128i Slashes = _mm_set1_epi8('/');
while (CurPtr+16 <= BufferEnd) {
- int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes));
+ int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
+ Slashes));
if (cmp != 0) {
// 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
@@ -2669,8 +2674,8 @@ 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.BCPLComment && !LangOpts.TraditionalCPP) {
- if (SkipBCPLComment(Result, CurPtr+2))
+ LangOpts.LineComment && !LangOpts.TraditionalCPP) {
+ if (SkipLineComment(Result, CurPtr+2))
return; // There is a token to return.
goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
@@ -2955,19 +2960,19 @@ LexNextToken:
case '/':
// 6.4.9: Comments
Char = getCharAndSize(CurPtr, SizeTmp);
- if (Char == '/') { // BCPL comment.
- // Even if BCPL comments are disabled (e.g. in C89 mode), we generally
+ if (Char == '/') { // Line comment.
+ // Even if Line comments are disabled (e.g. in C89 mode), we generally
// want to lex this as a comment. There is one problem with this though,
// that in one particular corner case, this can change the behavior of the
// resultant program. For example, In "foo //**/ bar", C89 would lex
- // this as "foo / bar" and langauges with BCPL comments would lex it as
+ // this as "foo / bar" and langauges with Line comments would lex it as
// "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 in -traditional-cpp mode.
- if ((LangOpts.BCPLComment ||
+ if ((LangOpts.LineComment ||
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
!LangOpts.TraditionalCPP) {
- if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
// It is common for the tokens immediately after a // comment to be
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 9e3c7786a732..e30612e57c5b 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -49,12 +49,46 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
}
}
+static CharSourceRange MakeCharSourceRange(const LangOptions &Features,
+ FullSourceLoc TokLoc,
+ const char *TokBegin,
+ const char *TokRangeBegin,
+ const char *TokRangeEnd) {
+ SourceLocation Begin =
+ Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin,
+ TokLoc.getManager(), Features);
+ SourceLocation End =
+ Lexer::AdvanceToTokenCharacter(Begin, TokRangeEnd - TokRangeBegin,
+ TokLoc.getManager(), Features);
+ return CharSourceRange::getCharRange(Begin, End);
+}
+
+/// \brief Produce a diagnostic highlighting some portion of a literal.
+///
+/// Emits the diagnostic \p DiagID, highlighting the range of characters from
+/// \p TokRangeBegin (inclusive) to \p TokRangeEnd (exclusive), which must be
+/// a substring of a spelling buffer for the token beginning at \p TokBegin.
+static DiagnosticBuilder Diag(DiagnosticsEngine *Diags,
+ const LangOptions &Features, FullSourceLoc TokLoc,
+ const char *TokBegin, const char *TokRangeBegin,
+ const char *TokRangeEnd, unsigned DiagID) {
+ SourceLocation Begin =
+ Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin,
+ TokLoc.getManager(), Features);
+ return Diags->Report(Begin, DiagID) <<
+ MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd);
+}
+
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
/// either a character or a string literal.
-static unsigned ProcessCharEscape(const char *&ThisTokBuf,
+static unsigned ProcessCharEscape(const char *ThisTokBegin,
+ const char *&ThisTokBuf,
const char *ThisTokEnd, bool &HadError,
FullSourceLoc Loc, unsigned CharWidth,
- DiagnosticsEngine *Diags) {
+ DiagnosticsEngine *Diags,
+ const LangOptions &Features) {
+ const char *EscapeBegin = ThisTokBuf;
+
// Skip the '\' char.
++ThisTokBuf;
@@ -75,12 +109,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
break;
case 'e':
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape) << "e";
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape) << "e";
ResultChar = 27;
break;
case 'E':
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape) << "E";
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape) << "E";
ResultChar = 27;
break;
case 'f':
@@ -102,7 +138,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
ResultChar = 0;
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
if (Diags)
- Diags->Report(Loc, diag::err_hex_escape_no_digits);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::err_hex_escape_no_digits);
HadError = 1;
break;
}
@@ -126,7 +163,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
// Check for overflow.
if (Overflow && Diags) // Too many digits to fit in
- Diags->Report(Loc, diag::warn_hex_escape_too_large);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::warn_hex_escape_too_large);
break;
}
case '0': case '1': case '2': case '3':
@@ -148,7 +186,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
// Check for overflow. Reject '\777', but not L'\777'.
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
if (Diags)
- Diags->Report(Loc, diag::warn_octal_escape_too_large);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::warn_octal_escape_too_large);
ResultChar &= ~0U >> (32-CharWidth);
}
break;
@@ -158,19 +197,22 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
case '(': case '{': case '[': case '%':
// GCC accepts these as extensions. We warn about them as such though.
if (Diags)
- Diags->Report(Loc, diag::ext_nonstandard_escape)
- << std::string()+(char)ResultChar;
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_nonstandard_escape)
+ << std::string(1, ResultChar);
break;
default:
if (Diags == 0)
break;
-
+
if (isgraph(ResultChar))
- Diags->Report(Loc, diag::ext_unknown_escape)
- << std::string()+(char)ResultChar;
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_unknown_escape)
+ << std::string(1, ResultChar);
else
- Diags->Report(Loc, diag::ext_unknown_escape)
- << "x"+llvm::utohexstr(ResultChar);
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::ext_unknown_escape)
+ << "x" + llvm::utohexstr(ResultChar);
break;
}
@@ -185,9 +227,6 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
FullSourceLoc Loc, DiagnosticsEngine *Diags,
const LangOptions &Features,
bool in_char_string_literal = false) {
- if (!Features.CPlusPlus && !Features.C99 && Diags)
- Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89);
-
const char *UcnBegin = ThisTokBuf;
// Skip the '\u' char's.
@@ -195,7 +234,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
if (Diags)
- Diags->Report(Loc, diag::err_ucn_escape_no_digits);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_no_digits);
return false;
}
UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
@@ -208,12 +248,9 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
}
// If we didn't consume the proper number of digits, there is a problem.
if (UcnLenSave) {
- if (Diags) {
- SourceLocation L =
- Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
- Loc.getManager(), Features);
- Diags->Report(L, diag::err_ucn_escape_incomplete);
- }
+ if (Diags)
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_incomplete);
return false;
}
@@ -221,7 +258,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints
UcnVal > 0x10FFFF) { // maximum legal UTF32 value
if (Diags)
- Diags->Report(Loc, diag::err_ucn_escape_invalid);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::err_ucn_escape_invalid);
return false;
}
@@ -231,22 +269,25 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal);
if (Diags) {
- SourceLocation UcnBeginLoc =
- Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
- Loc.getManager(), Features);
char BasicSCSChar = UcnVal;
if (UcnVal >= 0x20 && UcnVal < 0x7f)
- Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_escape_basic_scs :
- diag::warn_cxx98_compat_literal_ucn_escape_basic_scs)
- << StringRef(&BasicSCSChar, 1);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ IsError ? diag::err_ucn_escape_basic_scs :
+ diag::warn_cxx98_compat_literal_ucn_escape_basic_scs)
+ << StringRef(&BasicSCSChar, 1);
else
- Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_control_character :
- diag::warn_cxx98_compat_literal_ucn_control_character);
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ IsError ? diag::err_ucn_control_character :
+ diag::warn_cxx98_compat_literal_ucn_control_character);
}
if (IsError)
return false;
}
+ if (!Features.CPlusPlus && !Features.C99 && Diags)
+ Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
+ diag::warn_ucn_not_valid_in_c89);
+
return true;
}
@@ -365,10 +406,10 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Finally, we write the bytes into ResultBuf.
ResultBuf += bytesToWrite;
switch (bytesToWrite) { // note: everything falls through.
- case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
+ case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
}
// Update the buffer.
ResultBuf += bytesToWrite;
@@ -417,19 +458,19 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
/// floating-constant: [C99 6.4.4.2]
/// TODO: add rules...
///
-NumericLiteralParser::
-NumericLiteralParser(const char *begin, const char *end,
- SourceLocation TokLoc, Preprocessor &pp)
- : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) {
+NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
+ SourceLocation TokLoc,
+ Preprocessor &PP)
+ : PP(PP), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) {
// This routine assumes that the range begin/end matches the regex for integer
// and FP constants (specifically, the 'pp-number' regex), and assumes that
// the byte at "*end" is both valid and not part of the regex. Because of
// this, it doesn't have to check for 'overscan' in various places.
- assert(!isalnum(*end) && *end != '.' && *end != '_' &&
+ assert(!isalnum(*ThisTokEnd) && *ThisTokEnd != '.' && *ThisTokEnd != '_' &&
"Lexer didn't maximally munch?");
- s = DigitsBegin = begin;
+ s = DigitsBegin = ThisTokBegin;
saw_exponent = false;
saw_period = false;
saw_ud_suffix = false;
@@ -451,7 +492,7 @@ NumericLiteralParser(const char *begin, const char *end,
if (s == ThisTokEnd) {
// Done.
} else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_invalid_decimal_digit) << StringRef(s, 1);
hadError = true;
return;
@@ -469,7 +510,7 @@ NumericLiteralParser(const char *begin, const char *end,
if (first_non_digit != s) {
s = first_non_digit;
} else {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent - ThisTokBegin),
diag::err_exponent_has_no_digits);
hadError = true;
return;
@@ -565,7 +606,7 @@ NumericLiteralParser(const char *begin, const char *end,
case 'j':
case 'J':
if (isImaginary) break; // Cannot be repeated.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::ext_imaginary_constant);
isImaginary = true;
continue; // Success.
@@ -583,7 +624,7 @@ NumericLiteralParser(const char *begin, const char *end,
}
// Report an error if there are any.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
isFPConstant ? diag::err_invalid_suffix_float_constant :
diag::err_invalid_suffix_integer_constant)
<< StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
@@ -619,7 +660,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
if (noSignificand) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), \
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_hexconstant_requires_digits);
hadError = true;
return;
@@ -722,6 +763,20 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
}
+static bool alwaysFitsInto64Bits(unsigned Radix, unsigned NumDigits) {
+ switch (Radix) {
+ case 2:
+ return NumDigits <= 64;
+ case 8:
+ return NumDigits <= 64 / 3; // Digits are groups of 3 bits.
+ case 10:
+ return NumDigits <= 19; // floor(log10(2^64))
+ case 16:
+ return NumDigits <= 64 / 4; // Digits are groups of 4 bits.
+ default:
+ llvm_unreachable("impossible Radix");
+ }
+}
/// GetIntegerValue - Convert this numeric literal value to an APInt that
/// matches Val's input width. If there is an overflow, set Val to the low bits
@@ -733,13 +788,11 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
// integer. This avoids the expensive overflow checking below, and
// handles the common cases that matter (small decimal integers and
// hex/octal values which don't overflow).
- unsigned MaxBitsPerDigit = 1;
- while ((1U << MaxBitsPerDigit) < radix)
- MaxBitsPerDigit += 1;
- if ((SuffixBegin - DigitsBegin) * MaxBitsPerDigit <= 64) {
+ const unsigned NumDigits = SuffixBegin - DigitsBegin;
+ if (alwaysFitsInto64Bits(radix, NumDigits)) {
uint64_t N = 0;
- for (s = DigitsBegin; s != SuffixBegin; ++s)
- N = N*radix + HexDigitValue(*s);
+ for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr)
+ N = N * radix + HexDigitValue(*Ptr);
// This will truncate the value to Val's input width. Simply check
// for overflow by comparing.
@@ -748,15 +801,15 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
}
Val = 0;
- s = DigitsBegin;
+ const char *Ptr = DigitsBegin;
llvm::APInt RadixVal(Val.getBitWidth(), radix);
llvm::APInt CharVal(Val.getBitWidth(), 0);
llvm::APInt OldVal = Val;
bool OverflowOccurred = false;
- while (s < SuffixBegin) {
- unsigned C = HexDigitValue(*s++);
+ while (Ptr < SuffixBegin) {
+ unsigned C = HexDigitValue(*Ptr++);
// If this letter is out of bound for this radix, reject it.
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
@@ -943,7 +996,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
HadError = true;
} else if (*buffer_begin > largest_character_for_kind) {
HadError = true;
- PP.Diag(Loc,diag::err_character_too_large);
+ PP.Diag(Loc, diag::err_character_too_large);
}
++buffer_begin;
@@ -951,9 +1004,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
}
unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
uint64_t result =
- ProcessCharEscape(begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics());
+ ProcessCharEscape(TokBegin, begin, end, HadError,
+ FullSourceLoc(Loc,PP.getSourceManager()),
+ CharWidth, &PP.getDiagnostics(), PP.getLangOpts());
*buffer_begin++ = result;
}
@@ -1110,7 +1163,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
Kind = StringToks[i].getKind();
} else {
if (Diags)
- Diags->Report(FullSourceLoc(StringToks[i].getLocation(), SM),
+ Diags->Report(StringToks[i].getLocation(),
diag::err_unsupported_string_concat);
hadError = true;
}
@@ -1218,9 +1271,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
assert(ThisTokEnd >= ThisTokBuf && "malformed raw string literal");
// Copy the string over
- if (CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)))
- if (DiagnoseBadString(StringToks[i]))
- hadError = true;
+ if (CopyStringFragment(StringToks[i], ThisTokBegin,
+ StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)))
+ hadError = true;
} else {
if (ThisTokBuf[0] != '"') {
// The file may have come from PCH and then changed after loading the
@@ -1251,9 +1304,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
} while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
// Copy the character span over.
- if (CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart)))
- if (DiagnoseBadString(StringToks[i]))
- hadError = true;
+ if (CopyStringFragment(StringToks[i], ThisTokBegin,
+ StringRef(InStart, ThisTokBuf - InStart)))
+ hadError = true;
continue;
}
// Is this a Universal Character Name escape?
@@ -1266,9 +1319,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
}
// Otherwise, this is a non-UCN escape character. Process it.
unsigned ResultChar =
- ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError,
+ ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
FullSourceLoc(StringToks[i].getLocation(), SM),
- CharByteWidth*8, Diags);
+ CharByteWidth*8, Diags, Features);
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -1308,8 +1361,8 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Verify that pascal strings aren't too large.
if (GetStringLength() > 256) {
- if (Diags)
- Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM),
+ if (Diags)
+ Diags->Report(StringToks[0].getLocation(),
diag::err_pascal_string_too_long)
<< SourceRange(StringToks[0].getLocation(),
StringToks[NumStringToks-1].getLocation());
@@ -1319,9 +1372,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
} else if (Diags) {
// Complain if this string literal has too many characters.
unsigned MaxChars = Features.CPlusPlus? 65536 : Features.C99 ? 4095 : 509;
-
+
if (GetNumStringChars() > MaxChars)
- Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM),
+ Diags->Report(StringToks[0].getLocation(),
diag::ext_string_too_long)
<< GetNumStringChars() << MaxChars
<< (Features.CPlusPlus ? 2 : Features.C99 ? 1 : 0)
@@ -1330,21 +1383,61 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
}
}
-/// copyStringFragment - This function copies from Start to End into ResultPtr.
-/// Performs widening for multi-byte characters.
-bool StringLiteralParser::CopyStringFragment(StringRef Fragment) {
- return !ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr);
+static const char *resyncUTF8(const char *Err, const char *End) {
+ if (Err == End)
+ return End;
+ End = Err + std::min<unsigned>(getNumBytesForUTF8(*Err), End-Err);
+ while (++Err != End && (*Err & 0xC0) == 0x80)
+ ;
+ return Err;
}
-bool StringLiteralParser::DiagnoseBadString(const Token &Tok) {
+/// \brief This function copies from Fragment, which is a sequence of bytes
+/// within Tok's contents (which begin at TokBegin) into ResultPtr.
+/// Performs widening for multi-byte characters.
+bool StringLiteralParser::CopyStringFragment(const Token &Tok,
+ const char *TokBegin,
+ StringRef Fragment) {
+ const UTF8 *ErrorPtrTmp;
+ if (ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr, ErrorPtrTmp))
+ return false;
+
// If we see bad encoding for unprefixed string literals, warn and
// simply copy the byte values, for compatibility with gcc and older
// versions of clang.
bool NoErrorOnBadEncoding = isAscii();
- unsigned Msg = NoErrorOnBadEncoding ? diag::warn_bad_string_encoding :
- diag::err_bad_string_encoding;
- if (Diags)
- Diags->Report(FullSourceLoc(Tok.getLocation(), SM), Msg);
+ if (NoErrorOnBadEncoding) {
+ memcpy(ResultPtr, Fragment.data(), Fragment.size());
+ ResultPtr += Fragment.size();
+ }
+
+ if (Diags) {
+ const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp);
+
+ FullSourceLoc SourceLoc(Tok.getLocation(), SM);
+ const DiagnosticBuilder &Builder =
+ Diag(Diags, Features, SourceLoc, TokBegin,
+ ErrorPtr, resyncUTF8(ErrorPtr, Fragment.end()),
+ NoErrorOnBadEncoding ? diag::warn_bad_string_encoding
+ : diag::err_bad_string_encoding);
+
+ const char *NextStart = resyncUTF8(ErrorPtr, Fragment.end());
+ StringRef NextFragment(NextStart, Fragment.end()-NextStart);
+
+ // Decode into a dummy buffer.
+ SmallString<512> Dummy;
+ Dummy.reserve(Fragment.size() * CharByteWidth);
+ char *Ptr = Dummy.data();
+
+ while (!Builder.hasMaxRanges() &&
+ !ConvertUTF8toWide(CharByteWidth, NextFragment, Ptr, ErrorPtrTmp)) {
+ const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp);
+ NextStart = resyncUTF8(ErrorPtr, Fragment.end());
+ Builder << MakeCharSourceRange(Features, SourceLoc, TokBegin,
+ ErrorPtr, NextStart);
+ NextFragment = StringRef(NextStart, Fragment.end()-NextStart);
+ }
+ }
return !NoErrorOnBadEncoding;
}
@@ -1422,9 +1515,9 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
}
ByteNo -= Len;
} else {
- ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
+ ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError,
FullSourceLoc(Tok.getLocation(), SM),
- CharByteWidth*8, Diags);
+ CharByteWidth*8, Diags, Features);
--ByteNo;
}
assert(!HadError && "This method isn't valid on erroneous strings");
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index e2b251a4499d..ed8873d08612 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -291,7 +291,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
}
}
- PP.CreateString(&Result[0], Result.size(), Tok,
+ PP.CreateString(Result, Tok,
ExpansionLocStart, ExpansionLocEnd);
return Tok;
}
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 3d0c9a1c2b51..904f04e4f836 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -15,47 +15,65 @@
#include "clang/Lex/Preprocessor.h"
using namespace clang;
-MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
- IsFunctionLike = false;
- IsC99Varargs = false;
- IsGNUVarargs = false;
- IsBuiltinMacro = false;
- IsFromAST = false;
- ChangedAfterLoad = false;
- IsDisabled = false;
- IsUsed = false;
- IsAllowRedefinitionsWithoutWarning = false;
- IsWarnIfUnused = false;
- IsDefinitionLengthCached = false;
- IsPublic = true;
-
- ArgumentList = 0;
- NumArguments = 0;
+MacroInfo::MacroInfo(SourceLocation DefLoc)
+ : Location(DefLoc),
+ PreviousDefinition(0),
+ ArgumentList(0),
+ NumArguments(0),
+ IsDefinitionLengthCached(false),
+ IsFunctionLike(false),
+ IsC99Varargs(false),
+ IsGNUVarargs(false),
+ IsBuiltinMacro(false),
+ IsFromAST(false),
+ ChangedAfterLoad(false),
+ IsDisabled(false),
+ IsUsed(false),
+ IsAllowRedefinitionsWithoutWarning(false),
+ IsWarnIfUnused(false),
+ IsPublic(true),
+ IsHidden(false),
+ IsAmbiguous(false) {
}
-MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
- Location = MI.Location;
- EndLocation = MI.EndLocation;
- ReplacementTokens = MI.ReplacementTokens;
- IsFunctionLike = MI.IsFunctionLike;
- IsC99Varargs = MI.IsC99Varargs;
- IsGNUVarargs = MI.IsGNUVarargs;
- IsBuiltinMacro = MI.IsBuiltinMacro;
- IsFromAST = MI.IsFromAST;
- ChangedAfterLoad = MI.ChangedAfterLoad;
- IsDisabled = MI.IsDisabled;
- IsUsed = MI.IsUsed;
- IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
- IsWarnIfUnused = MI.IsWarnIfUnused;
- IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
- DefinitionLength = MI.DefinitionLength;
- IsPublic = MI.IsPublic;
-
- ArgumentList = 0;
- NumArguments = 0;
+MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator)
+ : Location(MI.Location),
+ EndLocation(MI.EndLocation),
+ UndefLocation(MI.UndefLocation),
+ PreviousDefinition(0),
+ ArgumentList(0),
+ NumArguments(0),
+ ReplacementTokens(MI.ReplacementTokens),
+ DefinitionLength(MI.DefinitionLength),
+ IsDefinitionLengthCached(MI.IsDefinitionLengthCached),
+ IsFunctionLike(MI.IsFunctionLike),
+ IsC99Varargs(MI.IsC99Varargs),
+ IsGNUVarargs(MI.IsGNUVarargs),
+ IsBuiltinMacro(MI.IsBuiltinMacro),
+ IsFromAST(MI.IsFromAST),
+ ChangedAfterLoad(MI.ChangedAfterLoad),
+ IsDisabled(MI.IsDisabled),
+ IsUsed(MI.IsUsed),
+ IsAllowRedefinitionsWithoutWarning(MI.IsAllowRedefinitionsWithoutWarning),
+ IsWarnIfUnused(MI.IsWarnIfUnused),
+ IsPublic(MI.IsPublic),
+ IsHidden(MI.IsHidden),
+ IsAmbiguous(MI.IsAmbiguous) {
setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
}
+const MacroInfo *MacroInfo::findDefinitionAtLoc(SourceLocation L,
+ SourceManager &SM) const {
+ assert(L.isValid() && "SourceLocation is invalid.");
+ for (const MacroInfo *MI = this; MI; MI = MI->PreviousDefinition) {
+ if (MI->Location.isInvalid() || // For macros defined on the command line.
+ SM.isBeforeInTranslationUnit(MI->Location, L))
+ return (MI->UndefLocation.isInvalid() ||
+ SM.isBeforeInTranslationUnit(L, MI->UndefLocation)) ? MI : NULL;
+ }
+ return NULL;
+}
+
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
assert(!IsDefinitionLengthCached);
IsDefinitionLengthCached = true;
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 5304311ef619..8a936fa8e145 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -26,6 +27,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include <stdlib.h>
using namespace clang;
Module::ExportDecl
@@ -75,7 +77,7 @@ ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
{
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
- new DiagnosticsEngine(DiagIDs));
+ new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true);
SourceMgr = new SourceManager(*Diags, FileMgr);
}
@@ -96,16 +98,62 @@ void ModuleMap::setTarget(const TargetInfo &Target) {
this->Target = &Target;
}
+/// \brief "Sanitize" a filename so that it can be used as an identifier.
+static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
+ SmallVectorImpl<char> &Buffer) {
+ if (Name.empty())
+ return Name;
+
+ // Check whether the filename is already an identifier; this is the common
+ // case.
+ bool isIdentifier = true;
+ for (unsigned I = 0, N = Name.size(); I != N; ++I) {
+ if (isalpha(Name[I]) || Name[I] == '_' || (isdigit(Name[I]) && I > 0))
+ continue;
+
+ isIdentifier = false;
+ break;
+ }
+
+ if (!isIdentifier) {
+ // If we don't already have something with the form of an identifier,
+ // create a buffer with the sanitized name.
+ Buffer.clear();
+ if (isdigit(Name[0]))
+ Buffer.push_back('_');
+ Buffer.reserve(Buffer.size() + Name.size());
+ for (unsigned I = 0, N = Name.size(); I != N; ++I) {
+ if (isalnum(Name[I]) || isspace(Name[I]))
+ Buffer.push_back(Name[I]);
+ else
+ Buffer.push_back('_');
+ }
+
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ while (llvm::StringSwitch<bool>(Name)
+#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true)
+#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true)
+#include "clang/Basic/TokenKinds.def"
+ .Default(false)) {
+ if (Name.data() != Buffer.data())
+ Buffer.append(Name.begin(), Name.end());
+ Buffer.push_back('_');
+ Name = StringRef(Buffer.data(), Buffer.size());
+ }
+
+ return Name;
+}
+
Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
- llvm::DenseMap<const FileEntry *, Module *>::iterator Known
- = Headers.find(File);
+ HeadersMap::iterator Known = Headers.find(File);
if (Known != Headers.end()) {
- // If a header corresponds to an unavailable module, don't report
- // that it maps to anything.
- if (!Known->second->isAvailable())
+ // If a header is not available, don't report that it maps to anything.
+ if (!Known->second.isAvailable())
return 0;
- return Known->second;
+ return Known->second.getModule();
}
const DirectoryEntry *Dir = File->getDir();
@@ -134,7 +182,10 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
@@ -148,9 +199,12 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(File->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(File->getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
+ Result->TopHeaders.insert(File);
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
@@ -163,7 +217,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
UmbrellaDirs[SkippedDirs[I]] = Result;
}
- Headers[File] = Result;
+ Headers[File] = KnownHeader(Result, /*Excluded=*/false);
// If a header corresponds to an unavailable module, don't report
// that it maps to anything.
@@ -188,10 +242,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
- llvm::DenseMap<const FileEntry *, Module *>::iterator Known
- = Headers.find(Header);
+ HeadersMap::iterator Known = Headers.find(Header);
if (Known != Headers.end())
- return !Known->second->isAvailable();
+ return !Known->second.isAvailable();
const DirectoryEntry *Dir = Header->getDir();
llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -216,7 +269,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
if (UmbrellaModule->InferSubmodules) {
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
- StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -225,7 +281,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
}
// Infer a submodule with the same name as this header file.
- StringRef Name = llvm::sys::path::stem(Header->getName());
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Header->getName()),
+ NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -287,8 +346,32 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
return std::make_pair(Result, true);
}
+bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
+ StringRef Name, bool &IsSystem) {
+ // Check whether we have already looked into the parent directory
+ // for a module map.
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ inferred = InferredDirectories.find(ParentDir);
+ if (inferred == InferredDirectories.end())
+ return false;
+
+ if (!inferred->second.InferModules)
+ return false;
+
+ // We're allowed to infer for this directory, but make sure it's okay
+ // to infer this particular module.
+ bool canInfer = std::find(inferred->second.ExcludedModules.begin(),
+ inferred->second.ExcludedModules.end(),
+ Name) == inferred->second.ExcludedModules.end();
+
+ if (canInfer && inferred->second.InferSystemModules)
+ IsSystem = true;
+
+ return canInfer;
+}
+
Module *
-ModuleMap::inferFrameworkModule(StringRef ModuleName,
+ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir,
bool IsSystem,
Module *Parent) {
@@ -297,7 +380,54 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
return Mod;
FileManager &FileMgr = SourceMgr->getFileManager();
-
+
+ // If the framework has a parent path from which we're allowed to infer
+ // a framework module, do so.
+ if (!Parent) {
+ bool canInfer = false;
+ if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) {
+ // Figure out the parent path.
+ StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName());
+ if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
+ // Check whether we have already looked into the parent directory
+ // for a module map.
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ inferred = InferredDirectories.find(ParentDir);
+ if (inferred == InferredDirectories.end()) {
+ // We haven't looked here before. Load a module map, if there is
+ // one.
+ SmallString<128> ModMapPath = Parent;
+ llvm::sys::path::append(ModMapPath, "module.map");
+ if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
+ parseModuleMapFile(ModMapFile);
+ inferred = InferredDirectories.find(ParentDir);
+ }
+
+ if (inferred == InferredDirectories.end())
+ inferred = InferredDirectories.insert(
+ std::make_pair(ParentDir, InferredDirectory())).first;
+ }
+
+ if (inferred->second.InferModules) {
+ // We're allowed to infer for this directory, but make sure it's okay
+ // to infer this particular module.
+ StringRef Name = llvm::sys::path::filename(FrameworkDir->getName());
+ canInfer = std::find(inferred->second.ExcludedModules.begin(),
+ inferred->second.ExcludedModules.end(),
+ Name) == inferred->second.ExcludedModules.end();
+
+ if (inferred->second.InferSystemModules)
+ IsSystem = true;
+ }
+ }
+ }
+
+ // If we're not allowed to infer a framework module, don't.
+ if (!canInfer)
+ return 0;
+ }
+
+
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
llvm::sys::path::append(UmbrellaName, "Headers");
@@ -320,7 +450,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
- Headers[UmbrellaHeader] = Result;
+ Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false);
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
@@ -343,12 +473,42 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
-
+
if (const DirectoryEntry *SubframeworkDir
= FileMgr.getDirectory(Dir->path())) {
+ // Note: as an egregious but useful hack, we use the real path here and
+ // check whether it is actually a subdirectory of the parent directory.
+ // This will not be the case if the 'subframework' is actually a symlink
+ // out to a top-level framework.
+#ifdef LLVM_ON_UNIX
+ char RealSubframeworkDirName[PATH_MAX];
+ if (realpath(Dir->path().c_str(), RealSubframeworkDirName)) {
+ StringRef SubframeworkDirName = RealSubframeworkDirName;
+
+ bool FoundParent = false;
+ do {
+ // Get the parent directory name.
+ SubframeworkDirName
+ = llvm::sys::path::parent_path(SubframeworkDirName);
+ if (SubframeworkDirName.empty())
+ break;
+
+ if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
+ FoundParent = true;
+ break;
+ }
+ } while (true);
+
+ if (!FoundParent)
+ continue;
+ }
+#endif
+
// FIXME: Do we want to warn about subframeworks without umbrella headers?
- inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir,
- IsSystem, Result);
+ SmallString<32> NameBuf;
+ inferFrameworkModule(sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(Dir->path()), NameBuf),
+ SubframeworkDir, IsSystem, Result);
}
}
@@ -356,7 +516,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
- Headers[UmbrellaHeader] = Mod;
+ Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false);
Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
@@ -366,9 +526,13 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
UmbrellaDirs[UmbrellaDir] = Mod;
}
-void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
- Mod->Headers.push_back(Header);
- Headers[Header] = Mod;
+void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
+ bool Excluded) {
+ if (Excluded)
+ Mod->ExcludedHeaders.push_back(Header);
+ else
+ Mod->Headers.push_back(Header);
+ Headers[Header] = KnownHeader(Mod, Excluded);
}
const FileEntry *
@@ -388,12 +552,10 @@ void ModuleMap::dump() {
M->getValue()->print(llvm::errs(), 2);
llvm::errs() << "Headers:";
- for (llvm::DenseMap<const FileEntry *, Module *>::iterator
- H = Headers.begin(),
- HEnd = Headers.end();
+ for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
llvm::errs() << " \"" << H->first->getName() << "\" -> "
- << H->second->getFullModuleName() << "\n";
+ << H->second.getModule()->getFullModuleName() << "\n";
}
}
@@ -454,6 +616,7 @@ namespace clang {
EndOfFile,
HeaderKeyword,
Identifier,
+ ExcludeKeyword,
ExplicitKeyword,
ExportKeyword,
FrameworkKeyword,
@@ -490,10 +653,24 @@ namespace clang {
return StringRef(StringData, StringLength);
}
};
+
+ /// \brief The set of attributes that can be attached to a module.
+ struct Attributes {
+ Attributes() : IsSystem() { }
+
+ /// \brief Whether this is a system module.
+ unsigned IsSystem : 1;
+ };
+
class ModuleMapParser {
Lexer &L;
SourceManager &SourceMgr;
+
+ /// \brief Default target information, used only for string literal
+ /// parsing.
+ const TargetInfo *Target;
+
DiagnosticsEngine &Diags;
ModuleMap &Map;
@@ -505,11 +682,7 @@ namespace clang {
/// \brief Whether an error occurred.
bool HadError;
-
- /// \brief Default target information, used only for string literal
- /// parsing.
- OwningPtr<TargetInfo> Target;
-
+
/// \brief Stores string data for the various string literals referenced
/// during parsing.
llvm::BumpPtrAllocator StringData;
@@ -532,27 +705,25 @@ namespace clang {
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseRequiresDecl();
- void parseHeaderDecl(SourceLocation UmbrellaLoc);
+ void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
- void parseInferredSubmoduleDecl(bool Explicit);
-
+ void parseInferredModuleDecl(bool Framework, bool Explicit);
+ bool parseOptionalAttributes(Attributes &Attrs);
+
const DirectoryEntry *getOverriddenHeaderSearchDir();
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
+ const TargetInfo *Target,
DiagnosticsEngine &Diags,
ModuleMap &Map,
const DirectoryEntry *Directory,
const DirectoryEntry *BuiltinIncludeDir)
- : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
+ : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
HadError(false), ActiveModule(0)
{
- TargetOptions TargetOpts;
- TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
- Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
-
Tok.clear();
consumeToken();
}
@@ -575,6 +746,7 @@ retry:
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
.Case("header", MMToken::HeaderKeyword)
+ .Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
@@ -743,13 +915,6 @@ namespace {
/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
/// { module-member* }
///
-/// attributes:
-/// attribute attributes
-/// attribute
-///
-/// attribute:
-/// [ identifier ]
-///
/// module-member:
/// requires-declaration
/// header-declaration
@@ -791,7 +956,7 @@ void ModuleMapParser::parseModuleDecl() {
// If we have a wildcard for the module name, this is an inferred submodule.
// Parse it.
if (Tok.is(MMToken::Star))
- return parseInferredSubmoduleDecl(Explicit);
+ return parseInferredModuleDecl(Framework, Explicit);
// Parse the module name.
ModuleId Id;
@@ -799,7 +964,7 @@ void ModuleMapParser::parseModuleDecl() {
HadError = true;
return;
}
-
+
if (ActiveModule) {
if (Id.size() > 1) {
Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
@@ -842,47 +1007,8 @@ void ModuleMapParser::parseModuleDecl() {
SourceLocation ModuleNameLoc = Id.back().second;
// Parse the optional attribute list.
- bool IsSystem = false;
- while (Tok.is(MMToken::LSquare)) {
- // Consume the '['.
- SourceLocation LSquareLoc = consumeToken();
-
- // Check whether we have an attribute name here.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
- skipUntil(MMToken::RSquare);
- if (Tok.is(MMToken::RSquare))
- consumeToken();
- continue;
- }
-
- // Decode the attribute name.
- AttributeKind Attribute
- = llvm::StringSwitch<AttributeKind>(Tok.getString())
- .Case("system", AT_system)
- .Default(AT_unknown);
- switch (Attribute) {
- case AT_unknown:
- Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
- << Tok.getString();
- break;
-
- case AT_system:
- IsSystem = true;
- break;
- }
- consumeToken();
-
- // Consume the ']'.
- if (!Tok.is(MMToken::RSquare)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
- Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
- skipUntil(MMToken::RSquare);
- }
-
- if (Tok.is(MMToken::RSquare))
- consumeToken();
- }
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
@@ -925,7 +1051,7 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
- if (IsSystem)
+ if (Attrs.IsSystem)
ActiveModule->IsSystem = true;
bool Done = false;
@@ -953,14 +1079,25 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
- parseHeaderDecl(UmbrellaLoc);
+ parseHeaderDecl(UmbrellaLoc, SourceLocation());
else
parseUmbrellaDirDecl(UmbrellaLoc);
break;
}
+ case MMToken::ExcludeKeyword: {
+ SourceLocation ExcludeLoc = consumeToken();
+ if (Tok.is(MMToken::HeaderKeyword)) {
+ parseHeaderDecl(SourceLocation(), ExcludeLoc);
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "exclude";
+ }
+ break;
+ }
+
case MMToken::HeaderKeyword:
- parseHeaderDecl(SourceLocation());
+ parseHeaderDecl(SourceLocation(), SourceLocation());
break;
default:
@@ -1062,12 +1199,15 @@ static bool isBuiltinHeader(StringRef FileName) {
///
/// header-declaration:
/// 'umbrella'[opt] 'header' string-literal
-void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
+/// 'exclude'[opt] 'header' string-literal
+void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
+ SourceLocation ExcludeLoc) {
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)
@@ -1145,15 +1285,15 @@ 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 (const Module *OwningModule = Map.Headers[File]) {
+ if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
- << FileName << OwningModule->getFullModuleName();
+ << FileName << OwningModule.getModule()->getFullModuleName();
HadError = true;
} else if (Umbrella) {
const DirectoryEntry *UmbrellaDir = File->getDir();
- if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
+ if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
- << OwningModule->getFullModuleName();
+ << UmbrellaModule->getFullModuleName();
HadError = true;
} else {
// Record this umbrella header.
@@ -1161,11 +1301,11 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
}
} else {
// Record this header.
- Map.addHeader(ActiveModule, File);
+ Map.addHeader(ActiveModule, File, Exclude);
// If there is a builtin counterpart to this file, add it now.
if (BuiltinFile)
- Map.addHeader(ActiveModule, BuiltinFile);
+ Map.addHeader(ActiveModule, BuiltinFile, Exclude);
}
} else {
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
@@ -1274,32 +1414,52 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
+/// \brief Parse an inferried module declaration (wildcard modules).
+///
+/// module-declaration:
+/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
+/// { inferred-module-member* }
+///
+/// inferred-module-member:
+/// 'export' '*'
+/// 'exclude' identifier
+void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
assert(Tok.is(MMToken::Star));
SourceLocation StarLoc = consumeToken();
bool Failed = false;
-
+
// Inferred modules must be submodules.
- if (!ActiveModule) {
+ if (!ActiveModule && !Framework) {
Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
Failed = true;
}
-
- // Inferred modules must have umbrella directories.
- if (!Failed && !ActiveModule->getUmbrellaDir()) {
- Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
- Failed = true;
- }
-
- // Check for redefinition of an inferred module.
- if (!Failed && ActiveModule->InferSubmodules) {
- Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
- if (ActiveModule->InferredSubmoduleLoc.isValid())
- Diags.Report(ActiveModule->InferredSubmoduleLoc,
- diag::note_mmap_prev_definition);
- Failed = true;
+
+ if (ActiveModule) {
+ // Inferred modules must have umbrella directories.
+ if (!Failed && !ActiveModule->getUmbrellaDir()) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
+ Failed = true;
+ }
+
+ // Check for redefinition of an inferred module.
+ if (!Failed && ActiveModule->InferSubmodules) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
+ if (ActiveModule->InferredSubmoduleLoc.isValid())
+ Diags.Report(ActiveModule->InferredSubmoduleLoc,
+ diag::note_mmap_prev_definition);
+ Failed = true;
+ }
+
+ // Check for the 'framework' keyword, which is not permitted here.
+ if (Framework) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule);
+ Framework = false;
+ }
+ } else if (Explicit) {
+ Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework);
+ Explicit = false;
}
-
+
// If there were any problems with this inferred submodule, skip its body.
if (Failed) {
if (Tok.is(MMToken::LBrace)) {
@@ -1311,12 +1471,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
HadError = true;
return;
}
-
- // Note that we have an inferred submodule.
- ActiveModule->InferSubmodules = true;
- ActiveModule->InferredSubmoduleLoc = StarLoc;
- ActiveModule->InferExplicitSubmodules = Explicit;
-
+
+ // Parse optional attributes.
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
+
+ if (ActiveModule) {
+ // Note that we have an inferred submodule.
+ ActiveModule->InferSubmodules = true;
+ ActiveModule->InferredSubmoduleLoc = StarLoc;
+ ActiveModule->InferExplicitSubmodules = Explicit;
+ } else {
+ // We'll be inferring framework modules for this directory.
+ Map.InferredDirectories[Directory].InferModules = true;
+ Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem;
+ }
+
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
@@ -1333,8 +1503,35 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
case MMToken::RBrace:
Done = true;
break;
-
- case MMToken::ExportKeyword: {
+
+ case MMToken::ExcludeKeyword: {
+ if (ActiveModule) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
+ consumeToken();
+ break;
+ }
+
+ consumeToken();
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
+ break;
+ }
+
+ Map.InferredDirectories[Directory].ExcludedModules
+ .push_back(Tok.getString());
+ consumeToken();
+ break;
+ }
+
+ case MMToken::ExportKeyword:
+ if (!ActiveModule) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
+ consumeToken();
+ break;
+ }
+
consumeToken();
if (Tok.is(MMToken::Star))
ActiveModule->InferExportWildcard = true;
@@ -1343,14 +1540,14 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
diag::err_mmap_expected_export_wildcard);
consumeToken();
break;
- }
-
+
case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword:
case MMToken::UmbrellaKeyword:
default:
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_wildcard_member);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != 0);
consumeToken();
break;
}
@@ -1365,6 +1562,66 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
}
}
+/// \brief Parse optional attributes.
+///
+/// attributes:
+/// attribute attributes
+/// attribute
+///
+/// attribute:
+/// [ identifier ]
+///
+/// \param Attrs Will be filled in with the parsed attributes.
+///
+/// \returns true if an error occurred, false otherwise.
+bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
+ bool HadError = false;
+
+ while (Tok.is(MMToken::LSquare)) {
+ // Consume the '['.
+ SourceLocation LSquareLoc = consumeToken();
+
+ // Check whether we have an attribute name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
+ skipUntil(MMToken::RSquare);
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ HadError = true;
+ }
+
+ // Decode the attribute name.
+ AttributeKind Attribute
+ = llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("system", AT_system)
+ .Default(AT_unknown);
+ switch (Attribute) {
+ case AT_unknown:
+ Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
+ << Tok.getString();
+ break;
+
+ case AT_system:
+ Attrs.IsSystem = true;
+ break;
+ }
+ consumeToken();
+
+ // Consume the ']'.
+ if (!Tok.is(MMToken::RSquare)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
+ Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
+ skipUntil(MMToken::RSquare);
+ HadError = true;
+ }
+
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ }
+
+ return HadError;
+}
+
/// \brief If there is a specific header search directory due the presence
/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
@@ -1398,6 +1655,7 @@ bool ModuleMapParser::parseModuleMapFile() {
break;
case MMToken::Comma:
+ case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
@@ -1428,7 +1686,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
Diags->getClient()->BeginSourceFile(MMapLangOpts);
- ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(),
+ ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(),
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 74b9cbc881ac..b7c1846e82be 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1296,7 +1296,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
case tok::string_literal:
Filename = getSpelling(FilenameTok, FilenameBuffer);
End = FilenameTok.getLocation();
- CharEnd = End.getLocWithOffset(Filename.size());
+ CharEnd = End.getLocWithOffset(FilenameTok.getLength());
break;
case tok::less:
@@ -1306,7 +1306,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (ConcatenateIncludeName(FilenameBuffer, End))
return; // Found <eod> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
- CharEnd = getLocForEndOfToken(End);
+ CharEnd = End.getLocWithOffset(1);
break;
default:
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
@@ -1314,6 +1314,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
return;
}
+ CharSourceRange FilenameRange
+ = CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd);
StringRef OriginalFilename = Filename;
bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
@@ -1384,9 +1386,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
- // Notify the callback object that we've seen an inclusion directive.
- Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
- End, SearchPath, RelativePath);
+ if (!SuggestedModule) {
+ // Notify the callback object that we've seen an inclusion directive.
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath,
+ /*ImportedModule=*/0);
+ }
}
if (File == 0) {
@@ -1480,10 +1486,28 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Module *Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
+ assert((Imported == 0 || Imported == SuggestedModule) &&
+ "the imported module is different than the suggested one");
// If this header isn't part of the module we're building, we're done.
- if (!BuildingImportedModule && Imported)
+ if (!BuildingImportedModule && Imported) {
+ if (Callbacks) {
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath, Imported);
+ }
return;
+ }
+ }
+
+ if (Callbacks && SuggestedModule) {
+ // We didn't notify the callback object that we've seen an inclusion
+ // directive before. Now that we are parsing the include normally and not
+ // turning it to a module import, notify the callback object.
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
+ FilenameRange, File,
+ SearchPath, RelativePath,
+ /*ImportedModule=*/0);
}
// The #included file will be considered to be a system header if either it is
@@ -1849,7 +1873,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
MI->setDefinitionEndLoc(LastTok.getLocation());
// Finally, if this identifier already had a macro defined for it, verify that
- // the macro bodies are identical and free the old definition.
+ // the macro bodies are identical, and issue diagnostics if they are not.
if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) {
// It is very common for system headers to have tons of macro redefinitions
// and for warnings to be disabled in system headers. If this is the case,
@@ -1870,7 +1894,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
}
if (OtherMI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc());
- ReleaseMacroInfo(OtherMI);
}
setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
@@ -1921,9 +1944,20 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
- // Free macro definition.
- ReleaseMacroInfo(MI);
- setMacroInfo(MacroNameTok.getIdentifierInfo(), 0);
+ UndefineMacro(MacroNameTok.getIdentifierInfo(), MI,
+ MacroNameTok.getLocation());
+}
+
+void Preprocessor::UndefineMacro(IdentifierInfo *II, MacroInfo *MI,
+ SourceLocation UndefLoc) {
+ MI->setUndefLoc(UndefLoc);
+ if (MI->isFromAST()) {
+ MI->setChangedAfterLoad();
+ if (Listener)
+ Listener->UndefinedMacro(MI);
+ }
+
+ clearMacroInfo(II);
}
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 7cac63eb0f53..d5a88db470d8 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -178,7 +178,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// preprocessor keywords and it wasn't macro expanded, it turns
// into a simple 0, unless it is the C++ keyword "true", in which case it
// turns into "1".
- if (ValueLive)
+ if (ValueLive &&
+ II->getTokenID() != tok::kw_true &&
+ II->getTokenID() != tok::kw_false)
PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
Result.Val = II->getTokenID() == tok::kw_true;
Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
@@ -204,8 +206,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (NumberInvalid)
return true; // a diagnostic was already reported
- NumericLiteralParser Literal(Spelling.begin(), Spelling.end(),
- PeekTok.getLocation(), PP);
+ NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP);
if (Literal.hadError)
return true; // a diagnostic was already reported.
@@ -219,10 +220,15 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (Literal.hasUDSuffix())
PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1;
- // long long is a C99 feature.
- if (!PP.getLangOpts().C99 && Literal.isLongLong)
- PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!PP.getLangOpts().C99 && Literal.isLongLong) {
+ if (PP.getLangOpts().CPlusPlus)
+ PP.Diag(PeekTok,
+ PP.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ PP.Diag(PeekTok, diag::ext_c99_longlong);
+ }
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index e824320cf732..d827f58a485f 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -157,15 +157,15 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
/// EnterMacro - Add a Macro to the top of the include stack and start lexing
/// tokens from it instead of the current buffer.
void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
- MacroArgs *Args) {
+ MacroInfo *Macro, MacroArgs *Args) {
PushIncludeMacroStack();
CurDirLookup = 0;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Args, *this));
+ CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Macro, Args, *this));
} else {
CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Tok, ILEnd, Args);
+ CurTokenLexer->Init(Tok, ILEnd, Macro, Args);
}
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ebdb6446d167..eee4342e27ca 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -27,39 +27,138 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include <cstdio>
#include <ctime>
using namespace clang;
-MacroInfo *Preprocessor::getInfoForMacro(IdentifierInfo *II) const {
- assert(II->hasMacroDefinition() && "Identifier is not a macro!");
-
- llvm::DenseMap<IdentifierInfo*, MacroInfo*>::const_iterator Pos
- = Macros.find(II);
- if (Pos == Macros.end()) {
- // Load this macro from the external source.
- getExternalSource()->LoadMacroDefinition(II);
- Pos = Macros.find(II);
- }
+MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
+ assert(II->hadMacroDefinition() && "Identifier has not been not a macro!");
+
+ macro_iterator Pos = Macros.find(II);
assert(Pos != Macros.end() && "Identifier macro info is missing!");
return Pos->second;
}
/// setMacroInfo - Specify a macro for this identifier.
///
-void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- bool LoadedFromAST) {
- if (MI) {
- Macros[II] = MI;
- II->setHasMacroDefinition(true);
- if (II->isFromAST() && !LoadedFromAST)
- II->setChangedSinceDeserialization();
- } else if (II->hasMacroDefinition()) {
- Macros.erase(II);
- II->setHasMacroDefinition(false);
- if (II->isFromAST() && !LoadedFromAST)
- II->setChangedSinceDeserialization();
+void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
+ assert(MI && "MacroInfo should be non-zero!");
+ assert(MI->getUndefLoc().isInvalid() &&
+ "Undefined macros cannot be registered");
+
+ MacroInfo *&StoredMI = Macros[II];
+ MI->setPreviousDefinition(StoredMI);
+ StoredMI = MI;
+ II->setHasMacroDefinition(MI->getUndefLoc().isInvalid());
+ if (II->isFromAST())
+ II->setChangedSinceDeserialization();
+}
+
+void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI,
+ MacroInfo *Hint) {
+ assert(MI && "Missing macro?");
+ assert(MI->isFromAST() && "Macro is not from an AST?");
+ assert(!MI->getPreviousDefinition() && "Macro already in chain?");
+
+ MacroInfo *&StoredMI = Macros[II];
+
+ // Easy case: this is the first macro definition for this macro.
+ if (!StoredMI) {
+ StoredMI = MI;
+
+ if (MI->isDefined())
+ II->setHasMacroDefinition(true);
+ return;
+ }
+
+ // If this macro is a definition and this identifier has been neither
+ // defined nor undef'd in the current translation unit, add this macro
+ // to the end of the chain of definitions.
+ if (MI->isDefined() && StoredMI->isFromAST()) {
+ // Simple case: if this is the first actual definition, just put it at
+ // th beginning.
+ if (!StoredMI->isDefined()) {
+ MI->setPreviousDefinition(StoredMI);
+ StoredMI = MI;
+
+ II->setHasMacroDefinition(true);
+ return;
+ }
+
+ // Find the end of the definition chain.
+ MacroInfo *Prev;
+ MacroInfo *PrevPrev = StoredMI;
+ bool Ambiguous = StoredMI->isAmbiguous();
+ bool MatchedOther = false;
+ do {
+ Prev = PrevPrev;
+
+ // If the macros are not identical, we have an ambiguity.
+ if (!Prev->isIdenticalTo(*MI, *this)) {
+ if (!Ambiguous) {
+ Ambiguous = true;
+ StoredMI->setAmbiguous(true);
+ }
+ } else {
+ MatchedOther = true;
+ }
+ } while ((PrevPrev = Prev->getPreviousDefinition()) &&
+ PrevPrev->isDefined());
+
+ // If there are ambiguous definitions, and we didn't match any other
+ // definition, then mark us as ambiguous.
+ if (Ambiguous && !MatchedOther)
+ MI->setAmbiguous(true);
+
+ // Wire this macro information into the chain.
+ MI->setPreviousDefinition(Prev->getPreviousDefinition());
+ Prev->setPreviousDefinition(MI);
+ return;
+ }
+
+ // The macro is not a definition; put it at the end of the list.
+ MacroInfo *Prev = Hint? Hint : StoredMI;
+ while (Prev->getPreviousDefinition())
+ Prev = Prev->getPreviousDefinition();
+ Prev->setPreviousDefinition(MI);
+}
+
+void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II,
+ MacroInfo *MI) {
+ assert(MI->isFromAST() && "Macro must be from the AST");
+
+ MacroInfo *&StoredMI = Macros[II];
+ if (StoredMI == MI) {
+ // Easy case: this is the first macro anyway.
+ II->setHasMacroDefinition(MI->isDefined());
+ return;
}
+
+ // Go find the macro and pull it out of the list.
+ // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden
+ // would be quadratic, but it's extremely rare.
+ MacroInfo *Prev = StoredMI;
+ while (Prev->getPreviousDefinition() != MI)
+ Prev = Prev->getPreviousDefinition();
+ Prev->setPreviousDefinition(MI->getPreviousDefinition());
+ MI->setPreviousDefinition(0);
+
+ // Add the macro back to the list.
+ addLoadedMacroInfo(II, MI);
+
+ II->setHasMacroDefinition(StoredMI->isDefined());
+ if (II->isFromAST())
+ II->setChangedSinceDeserialization();
+}
+
+/// \brief Undefine a macro for this identifier.
+void Preprocessor::clearMacroInfo(IdentifierInfo *II) {
+ assert(II->hasMacroDefinition() && "Macro is not defined!");
+ assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!");
+ II->setHasMacroDefinition(false);
+ if (II->isFromAST())
+ II->setChangedSinceDeserialization();
}
/// RegisterBuiltinMacro - Register the specified identifier in the identifier
@@ -100,6 +199,20 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
+ // Modules.
+ if (LangOpts.Modules) {
+ Ident__building_module = RegisterBuiltinMacro(*this, "__building_module");
+
+ // __MODULE__
+ if (!LangOpts.CurrentModule.empty())
+ Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__");
+ else
+ Ident__MODULE__ = 0;
+ } else {
+ Ident__building_module = 0;
+ Ident__MODULE__ = 0;
+ }
+
// Microsoft Extensions.
if (LangOpts.MicrosoftExt)
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
@@ -263,7 +376,23 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
}
}
-
+
+ // If the macro definition is ambiguous, complain.
+ if (MI->isAmbiguous()) {
+ Diag(Identifier, diag::warn_pp_ambiguous_macro)
+ << Identifier.getIdentifierInfo();
+ Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen)
+ << Identifier.getIdentifierInfo();
+ for (MacroInfo *PrevMI = MI->getPreviousDefinition();
+ PrevMI && PrevMI->isDefined();
+ PrevMI = PrevMI->getPreviousDefinition()) {
+ if (PrevMI->isAmbiguous()) {
+ Diag(PrevMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other)
+ << Identifier.getIdentifierInfo();
+ }
+ }
+ }
+
// If we started lexing a macro, enter the macro expansion body.
// If this macro expands to no tokens, don't bother to push it onto the
@@ -337,7 +466,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
// Start expanding the macro.
- EnterMacro(Identifier, ExpansionEnd, Args);
+ 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.
@@ -581,27 +710,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
- char TmpBuffer[32];
-#ifdef LLVM_ON_WIN32
- sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday,
- TM->tm_year+1900);
-#else
- snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday,
- TM->tm_year+1900);
-#endif
-
- Token TmpTok;
- TmpTok.startToken();
- PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
- DATELoc = TmpTok.getLocation();
-
-#ifdef LLVM_ON_WIN32
- sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec);
-#else
- snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec);
-#endif
- PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok);
- TIMELoc = TmpTok.getLocation();
+ {
+ SmallString<32> TmpBuffer;
+ llvm::raw_svector_ostream TmpStream(TmpBuffer);
+ TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon],
+ TM->tm_mday, TM->tm_year + 1900);
+ Token TmpTok;
+ TmpTok.startToken();
+ PP.CreateString(TmpStream.str(), TmpTok);
+ DATELoc = TmpTok.getLocation();
+ }
+
+ {
+ SmallString<32> TmpBuffer;
+ llvm::raw_svector_ostream TmpStream(TmpBuffer);
+ TmpStream << llvm::format("\"%02d:%02d:%02d\"",
+ TM->tm_hour, TM->tm_min, TM->tm_sec);
+ Token TmpTok;
+ TmpTok.startToken();
+ PP.CreateString(TmpStream.str(), TmpTok);
+ TIMELoc = TmpTok.getLocation();
+ }
}
@@ -616,7 +745,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
Feature = Feature.substr(2, Feature.size() - 4);
return llvm::StringSwitch<bool>(Feature)
- .Case("address_sanitizer", LangOpts.AddressSanitizer)
+ .Case("address_sanitizer", LangOpts.SanitizeAddress)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_availability_with_message", true)
@@ -641,8 +770,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
- .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
- LangOpts.ObjCRuntimeHasWeak)
+ .Case("objc_arc_weak", LangOpts.ObjCARCWeak)
.Case("objc_default_synthesize_properties", LangOpts.ObjC2)
.Case("objc_fixed_enum", LangOpts.ObjC2)
.Case("objc_instancetype", LangOpts.ObjC2)
@@ -716,22 +844,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// "struct __is_empty" parsing hack hasn't been needed in this
// translation unit. If it has, __is_empty reverts to a normal
// identifier and __has_feature(is_empty) evaluates false.
- .Case("is_empty",
- LangOpts.CPlusPlus &&
- PP.getIdentifierInfo("__is_empty")->getTokenID()
- != tok::identifier)
+ .Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_final", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
.Case("is_standard_layout", LangOpts.CPlusPlus)
- // __is_pod is available only if the horrible
- // "struct __is_pod" parsing hack hasn't been needed in this
- // translation unit. If it has, __is_pod reverts to a normal
- // identifier and __has_feature(is_pod) evaluates false.
- .Case("is_pod",
- LangOpts.CPlusPlus &&
- PP.getIdentifierInfo("__is_pod")->getTokenID()
- != tok::identifier)
+ .Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
@@ -807,22 +925,30 @@ static bool HasAttribute(const IdentifierInfo *II) {
static bool EvaluateHasIncludeCommon(Token &Tok,
IdentifierInfo *II, Preprocessor &PP,
const DirectoryLookup *LookupFrom) {
- SourceLocation LParenLoc;
+ // Save the location of the current token. If a '(' is later found, use
+ // that location. If no, use the end of this location instead.
+ SourceLocation LParenLoc = Tok.getLocation();
// Get '('.
PP.LexNonComment(Tok);
// Ensure we have a '('.
if (Tok.isNot(tok::l_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
- return false;
- }
-
- // Save '(' location for possible missing ')' message.
- LParenLoc = Tok.getLocation();
+ // No '(', use end of last token.
+ LParenLoc = PP.getLocForEndOfToken(LParenLoc);
+ PP.Diag(LParenLoc, diag::err_pp_missing_lparen) << II->getName();
+ // If the next token looks like a filename or the start of one,
+ // assume it is and process it as such.
+ if (!Tok.is(tok::angle_string_literal) && !Tok.is(tok::string_literal) &&
+ !Tok.is(tok::less))
+ return false;
+ } else {
+ // Save '(' location for possible missing ')' message.
+ LParenLoc = Tok.getLocation();
- // Get the file name.
- PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ // Get the file name.
+ PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ }
// Reserve a buffer to get the spelling.
SmallString<128> FilenameBuffer;
@@ -847,8 +973,11 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// This could be a <foo/bar.h> file coming from a macro expansion. In this
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
- if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc))
+ if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) {
+ // Let the caller know a <eod> was found by changing the Token kind.
+ Tok.setKind(tok::eod);
return false; // Found <eod> but no ">"? Diagnostic already emitted.
+ }
Filename = FilenameBuffer.str();
break;
default:
@@ -856,12 +985,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
return false;
}
+ SourceLocation FilenameLoc = Tok.getLocation();
+
// Get ')'.
PP.LexNonComment(Tok);
// Ensure we have a trailing ).
if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
+ PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_missing_rparen)
+ << II->getName();
PP.Diag(LParenLoc, diag::note_matching) << "(";
return false;
}
@@ -909,6 +1041,47 @@ static bool EvaluateHasIncludeNext(Token &Tok,
return EvaluateHasIncludeCommon(Tok, II, PP, Lookup);
}
+/// \brief Process __building_module(identifier) expression.
+/// \returns true if we are building the named module, false otherwise.
+static bool EvaluateBuildingModule(Token &Tok,
+ IdentifierInfo *II, Preprocessor &PP) {
+ // Get '('.
+ PP.LexNonComment(Tok);
+
+ // Ensure we have a '('.
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
+ return false;
+ }
+
+ // Save '(' location for possible missing ')' message.
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ // Get the module name.
+ PP.LexNonComment(Tok);
+
+ // Ensure that we have an identifier.
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module);
+ return false;
+ }
+
+ bool Result
+ = Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule;
+
+ // Get ')'.
+ PP.LexNonComment(Tok);
+
+ // Ensure we have a trailing ).
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
+ PP.Diag(LParenLoc, diag::note_matching) << "(";
+ return false;
+ }
+
+ return Result;
+}
+
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
/// as a builtin macro, handle it and return the next token as 'Tok'.
void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
@@ -1093,7 +1266,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
else
Value = EvaluateHasIncludeNext(Tok, II, *this);
OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ if (Tok.is(tok::r_paren))
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_warning) {
// The argument should be a parenthesized string literal.
// The argument to these builtins should be a parenthesized identifier.
@@ -1164,11 +1338,22 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
OS << (int)Value;
Tok.setKind(tok::numeric_constant);
+ } else if (II == Ident__building_module) {
+ // The argument to this builtin should be an identifier. The
+ // builtin evaluates to 1 when that identifier names the module we are
+ // currently building.
+ OS << (int)EvaluateBuildingModule(Tok, II, *this);
+ Tok.setKind(tok::numeric_constant);
+ } else if (II == Ident__MODULE__) {
+ // The current module as an identifier.
+ OS << getLangOpts().CurrentModule;
+ IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule);
+ Tok.setIdentifierInfo(ModuleII);
+ Tok.setKind(ModuleII->getTokenID());
} else {
llvm_unreachable("Unknown identifier!");
}
- CreateString(OS.str().data(), OS.str().size(), Tok,
- Tok.getLocation(), Tok.getLocation());
+ CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation());
}
void Preprocessor::markMacroAsUsed(MacroInfo *MI) {
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 67738e907516..b1671721b630 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -198,12 +198,11 @@ bool PTHLexer::SkipBlock() {
assert(LastHashTokPtr && "No known '#' token.");
const unsigned char* HashEntryI = 0;
- uint32_t Offset;
uint32_t TableIdx;
do {
// Read the token offset from the side-table.
- Offset = ReadLE32(CurPPCondPtr);
+ uint32_t Offset = ReadLE32(CurPPCondPtr);
// Read the target table index from the side-table.
TableIdx = ReadLE32(CurPPCondPtr);
@@ -223,13 +222,11 @@ bool PTHLexer::SkipBlock() {
PPCond + TableIdx*(sizeof(uint32_t)*2);
assert(NextPPCondPtr >= CurPPCondPtr);
// Read where we should jump to.
- uint32_t TmpOffset = ReadLE32(NextPPCondPtr);
- const unsigned char* HashEntryJ = TokBuf + TmpOffset;
+ const unsigned char* HashEntryJ = TokBuf + ReadLE32(NextPPCondPtr);
if (HashEntryJ <= LastHashTokPtr) {
// Jump directly to the next entry in the side table.
HashEntryI = HashEntryJ;
- Offset = TmpOffset;
TableIdx = ReadLE32(NextPPCondPtr);
CurPPCondPtr = NextPPCondPtr;
}
@@ -448,8 +445,8 @@ PTHManager *PTHManager::Create(const std::string &file,
// Get the buffer ranges and check if there are at least three 32-bit
// words at the end of the file.
- const unsigned char *BufBeg = (unsigned char*)File->getBufferStart();
- const unsigned char *BufEnd = (unsigned char*)File->getBufferEnd();
+ const unsigned char *BufBeg = (const unsigned char*)File->getBufferStart();
+ const unsigned char *BufEnd = (const unsigned char*)File->getBufferEnd();
// Check the prologue of the file.
if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) ||
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index c9cc4adf4019..e7e6c3705376 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -43,7 +43,6 @@ void EmptyPragmaHandler::HandlePragma(Preprocessor &PP,
// PragmaNamespace Implementation.
//===----------------------------------------------------------------------===//
-
PragmaNamespace::~PragmaNamespace() {
for (llvm::StringMap<PragmaHandler*>::iterator
I = Handlers.begin(), E = Handlers.end(); I != E; ++I)
@@ -251,7 +250,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// where we can lex it.
Token TmpTok;
TmpTok.startToken();
- CreateString(&StrVal[0], StrVal.size(), TmpTok);
+ CreateString(StrVal, TmpTok);
SourceLocation TokLoc = TmpTok.getLocation();
// Make and enter a lexer object so that we lex and expand the tokens just
@@ -683,7 +682,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
Token MacroTok;
MacroTok.startToken();
MacroTok.setKind(tok::raw_identifier);
- CreateString(&StrVal[1], StrVal.size() - 2, MacroTok);
+ CreateString(StringRef(&StrVal[1], StrVal.size() - 2), MacroTok);
// Get the IdentifierInfo of MacroToPushTok.
return LookUpIdentifierInfo(MacroTok);
@@ -733,19 +732,22 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> >::iterator iter =
PragmaPushMacroInfo.find(IdentInfo);
if (iter != PragmaPushMacroInfo.end()) {
- // Release the MacroInfo currently associated with IdentInfo.
- MacroInfo *CurrentMI = getMacroInfo(IdentInfo);
- if (CurrentMI) {
+ // Forget the MacroInfo currently associated with IdentInfo.
+ if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) {
if (CurrentMI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc());
- ReleaseMacroInfo(CurrentMI);
+ UndefineMacro(IdentInfo, CurrentMI, MessageLoc);
}
// Get the MacroInfo we want to reinstall.
MacroInfo *MacroToReInstall = iter->second.back();
- // Reinstall the previously pushed macro.
- setMacroInfo(IdentInfo, MacroToReInstall);
+ if (MacroToReInstall) {
+ // Reinstall the previously pushed macro.
+ setMacroInfo(IdentInfo, MacroToReInstall);
+ } else if (IdentInfo->hasMacroDefinition()) {
+ clearMacroInfo(IdentInfo);
+ }
// Pop PragmaPushMacroInfo stack.
iter->second.pop_back();
@@ -1009,7 +1011,7 @@ struct PragmaDebugHandler : public PragmaHandler {
if (II->isStr("assert")) {
llvm_unreachable("This is an assertion!");
} else if (II->isStr("crash")) {
- *(volatile int*) 0x11 = 0;
+ LLVM_BUILTIN_TRAP;
} else if (II->isStr("parser_crash")) {
Token Crasher;
Crasher.setKind(tok::annot_pragma_parser_crash);
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index dfdeba3f9cd9..01f3665e76bd 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -25,10 +25,11 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind,
StringRef FileName,
- bool InQuotes, const FileEntry *File,
+ bool InQuotes, bool ImportedModule,
+ const FileEntry *File,
SourceRange Range)
: PreprocessingDirective(InclusionDirectiveKind, Range),
- InQuotes(InQuotes), Kind(Kind), File(File)
+ InQuotes(InQuotes), Kind(Kind), ImportedModule(ImportedModule), File(File)
{
char *Memory
= (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
@@ -59,8 +60,7 @@ PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
iterator(this, CachedRangeQuery.Result.second));
}
- std::pair<PPEntityID, PPEntityID>
- Res = getPreprocessedEntitiesInRangeSlow(Range);
+ std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range);
CachedRangeQuery.Range = Range;
CachedRangeQuery.Result = Res;
@@ -95,12 +95,12 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
if (FID.isInvalid())
return false;
- PPEntityID PPID = PPEI.Position;
- if (PPID < 0) {
- assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ int Pos = PPEI.Position;
+ if (Pos < 0) {
+ assert(unsigned(-Pos-1) < LoadedPreprocessedEntities.size() &&
"Out-of bounds loaded preprocessed entity");
assert(ExternalSource && "No external source to load from");
- unsigned LoadedIndex = LoadedPreprocessedEntities.size()+PPID;
+ unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr);
@@ -118,15 +118,15 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
FID, SourceMgr);
}
- assert(unsigned(PPID) < PreprocessedEntities.size() &&
+ assert(unsigned(Pos) < PreprocessedEntities.size() &&
"Out-of bounds local preprocessed entity");
- return isPreprocessedEntityIfInFileID(PreprocessedEntities[PPID],
+ return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
FID, SourceMgr);
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
/// that source range \arg R encompasses.
-std::pair<PreprocessingRecord::PPEntityID, PreprocessingRecord::PPEntityID>
+std::pair<int, int>
PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {
assert(Range.isValid());
assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
@@ -319,14 +319,19 @@ void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
/// \brief Retrieve the preprocessed entity at the given ID.
PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
- if (PPID < 0) {
- assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ if (PPID.ID < 0) {
+ unsigned Index = -PPID.ID - 1;
+ assert(Index < LoadedPreprocessedEntities.size() &&
"Out-of bounds loaded preprocessed entity");
- return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID);
+ return getLoadedPreprocessedEntity(Index);
}
- assert(unsigned(PPID) < PreprocessedEntities.size() &&
+
+ if (PPID.ID == 0)
+ return 0;
+ unsigned Index = PPID.ID - 1;
+ assert(Index < PreprocessedEntities.size() &&
"Out-of bounds local preprocessed entity");
- return PreprocessedEntities[PPID];
+ return PreprocessedEntities[Index];
}
/// \brief Retrieve the loaded preprocessed entity at the given index.
@@ -389,10 +394,11 @@ void PreprocessingRecord::InclusionDirective(
const clang::Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- clang::SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
@@ -415,9 +421,19 @@ void PreprocessingRecord::InclusionDirective(
default:
llvm_unreachable("Unknown include directive kind");
}
-
+
+ SourceLocation EndLoc;
+ if (!IsAngled) {
+ EndLoc = FilenameRange.getBegin();
+ } else {
+ EndLoc = FilenameRange.getEnd();
+ if (FilenameRange.isCharRange())
+ EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
+ // a token range.
+ }
clang::InclusionDirective *ID
- = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
+ = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
+ (bool)Imported,
File, SourceRange(HashLoc, EndLoc));
addPreprocessedEntity(ID);
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 614530cf387f..3b070ce049db 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,6 +26,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "MacroArgs.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
@@ -49,21 +50,25 @@ using namespace clang;
//===----------------------------------------------------------------------===//
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
-Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+PPMutationListener::~PPMutationListener() { }
+
+Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+ DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target, SourceManager &SM,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders,
bool DelayInitialization,
bool IncrProcessing)
- : Diags(&diags), LangOpts(opts), Target(target),FileMgr(Headers.getFileMgr()),
+ : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
+ FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
ExternalSource(0), Identifiers(opts, IILookup),
IncrementalProcessing(IncrProcessing), CodeComplete(0),
CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
SkipMainFilePreamble(0, true), CurPPLexer(0),
- CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), MacroArgCache(0),
- Record(0), MIChainHead(0), MICache(0)
+ CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0),
+ MacroArgCache(0), Record(0), MIChainHead(0), MICache(0)
{
OwnsHeaderSearch = OwnsHeaders;
@@ -285,6 +290,39 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
return Macros.end();
}
+/// \brief Compares macro tokens with a specified token value sequence.
+static bool MacroDefinitionEquals(const MacroInfo *MI,
+ llvm::ArrayRef<TokenValue> Tokens) {
+ return Tokens.size() == MI->getNumTokens() &&
+ std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin());
+}
+
+StringRef Preprocessor::getLastMacroWithSpelling(
+ SourceLocation Loc,
+ ArrayRef<TokenValue> Tokens) const {
+ SourceLocation BestLocation;
+ StringRef BestSpelling;
+ for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end();
+ I != E; ++I) {
+ if (!I->second->isObjectLike())
+ continue;
+ const MacroInfo *MI = I->second->findDefinitionAtLoc(Loc, SourceMgr);
+ if (!MI)
+ continue;
+ if (!MacroDefinitionEquals(MI, Tokens))
+ continue;
+ SourceLocation Location = I->second->getDefinitionLoc();
+ // Choose the macro defined latest.
+ if (BestLocation.isInvalid() ||
+ (Location.isValid() &&
+ SourceMgr.isBeforeInTranslationUnit(BestLocation, Location))) {
+ BestLocation = Location;
+ BestSpelling = I->first->getName();
+ }
+ }
+ return BestSpelling;
+}
+
void Preprocessor::recomputeCurLexerKind() {
if (CurLexer)
CurLexerKind = CLK_Lexer;
@@ -378,17 +416,17 @@ StringRef Preprocessor::getSpelling(const Token &Tok,
/// CreateString - Plop the specified string into a scratch buffer and return a
/// location for it. If specified, the source location provides a source
/// location for the token.
-void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
+void Preprocessor::CreateString(StringRef Str, Token &Tok,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd) {
- Tok.setLength(Len);
+ Tok.setLength(Str.size());
const char *DestPtr;
- SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr);
+ SourceLocation Loc = ScratchBuf->getToken(Str.data(), Str.size(), DestPtr);
if (ExpansionLocStart.isValid())
Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart,
- ExpansionLocEnd, Len);
+ ExpansionLocEnd, Str.size());
Tok.setLocation(Loc);
// If this is a raw identifier or a literal token, set the pointer data.
@@ -641,10 +679,14 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
// If we have a non-empty module path, load the named module.
- if (!ModuleImportPath.empty())
- (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath,
- Module::MacrosVisible,
- /*IsIncludeDirective=*/false);
+ if (!ModuleImportPath.empty()) {
+ Module *Imported = TheModuleLoader.loadModule(ModuleImportLoc,
+ ModuleImportPath,
+ Module::MacrosVisible,
+ /*IsIncludeDirective=*/false);
+ if (Callbacks)
+ Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
+ }
}
void Preprocessor::addCommentHandler(CommentHandler *Handler) {
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index ade40dad77d9..59b747814a51 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -23,12 +23,13 @@ using namespace clang;
/// Create a TokenLexer for the specified macro with the specified actual
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
-void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) {
+void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
+ MacroArgs *Actuals) {
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
- Macro = PP.getMacroInfo(Tok.getIdentifierInfo());
+ Macro = MI;
ActualArgs = Actuals;
CurToken = 0;
@@ -118,6 +119,55 @@ void TokenLexer::destroy() {
if (ActualArgs) ActualArgs->destroy(PP);
}
+/// 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,
+ bool &NextTokGetsSpace,
+ bool HasPasteOperator,
+ MacroInfo *Macro, unsigned MacroArgNo,
+ Preprocessor &PP) {
+ // Is the macro argument __VA_ARGS__?
+ if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
+ return false;
+
+ // In Microsoft-compatibility mode, a comma is removed in the expansion
+ // of " ... , __VA_ARGS__ " if __VA_ARGS__ is empty. This extension is
+ // not supported by gcc.
+ if (!HasPasteOperator && !PP.getLangOpts().MicrosoftMode)
+ return false;
+
+ // GCC removes the comma in the expansion of " ... , ## __VA_ARGS__ " if
+ // __VA_ARGS__ is empty, but not in strict C99 mode where there are no
+ // named arguments, where it remains. In all other modes, including C99
+ // with GNU extensions, it is removed regardless of named arguments.
+ // Microsoft also appears to support this extension, unofficially.
+ if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
+ && Macro->getNumArgs() < 2)
+ return false;
+
+ // Is a comma available to be removed?
+ if (ResultToks.empty() || !ResultToks.back().is(tok::comma))
+ return false;
+
+ // Issue an extension diagnostic for the paste operator.
+ if (HasPasteOperator)
+ PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
+
+ // Remove the comma.
+ ResultToks.pop_back();
+
+ // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
+ // then removal of the comma should produce a placemarker token (in C99
+ // terms) which we model by popping off the previous ##, giving us a plain
+ // "X" when __VA_ARGS__ is empty.
+ if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
+ ResultToks.pop_back();
+
+ // Never add a space, even if the comma, ##, or arg had a space.
+ NextTokGetsSpace = false;
+ return true;
+}
+
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
@@ -198,6 +248,14 @@ void TokenLexer::ExpandFunctionArguments() {
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
+ // In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
+ // are no trailing commas if __VA_ARGS__ is empty.
+ if (!PasteBefore && ActualArgs->isVarargsElidedUse() &&
+ MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ /*HasPasteOperator=*/false,
+ Macro, ArgNo, PP))
+ continue;
+
// If it is not the LHS/RHS of a ## operator, we must pre-expand the
// argument and substitute the expanded tokens into the result. This is
// C99 6.10.3.1p1.
@@ -320,23 +378,13 @@ void TokenLexer::ExpandFunctionArguments() {
// 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
- // the ## was a comma, remove the comma.
- if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__
- ActualArgs->isVarargsElidedUse() && // Argument elided.
- !ResultToks.empty() && ResultToks.back().is(tok::comma)) {
- // Never add a space, even if the comma, ##, or arg had a space.
- NextTokGetsSpace = false;
- // Remove the paste operator, report use of the extension.
- PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
- ResultToks.pop_back();
-
- // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
- // then removal of the comma should produce a placemarker token (in C99
- // terms) which we model by popping off the previous ##, giving us a plain
- // "X" when __VA_ARGS__ is empty.
- if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
- ResultToks.pop_back();
- }
+ // the ## was a comma, remove the comma. This is a GCC extension which is
+ // disabled when using -std=c99.
+ if (ActualArgs->isVarargsElidedUse())
+ MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ /*HasPasteOperator=*/true,
+ Macro, ArgNo, PP);
+
continue;
}
@@ -494,7 +542,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Claim that the tmp token is a string_literal so that we can get the
// character pointer back from CreateString in getLiteralData().
ResultTokTmp.setKind(tok::string_literal);
- PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp);
+ PP.CreateString(Buffer, ResultTokTmp);
SourceLocation ResultTokLoc = ResultTokTmp.getLocation();
ResultTokStrPtr = ResultTokTmp.getLiteralData();
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index bd4f85952120..7d68e1f37e40 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -78,7 +78,6 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
S.getPreprocessor().EnterMainSourceFile();
P.Initialize();
- S.Initialize();
// C11 6.9p1 says translation units must have at least one top-level
// declaration. C++ doesn't have this restriction. We also don't want to
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index abce27c3f820..9c5c0597eee1 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -34,7 +34,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
Tok.is(tok::equal)) &&
"Current token not a '{', ':', '=', or 'try'!");
- MultiTemplateParamsArg TemplateParams(Actions,
+ MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
@@ -42,10 +42,10 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
- move(TemplateParams));
+ TemplateParams);
else {
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
- move(TemplateParams), 0,
+ TemplateParams, 0,
VS, ICIS_NoInit);
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index cb865cc9c2ba..f73907a7c409 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -143,7 +143,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Attributes in a class are parsed at the end of the class, along
// with other late-parsed declarations.
- if (!ClassStack.empty())
+ if (!ClassStack.empty() && !LateAttrs->parseSoon())
getCurrentClass().LateParsedDeclarations.push_back(LA);
// consume everything up to and including the matching right parens
@@ -154,7 +154,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
Eof.setLocation(Tok.getLocation());
LA->Toks.push_back(Eof);
} else {
- ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
}
} else {
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
@@ -173,11 +174,15 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
-/// Parse the arguments to a parameterized GNU attribute
+/// Parse the arguments to a parameterized GNU attribute or
+/// a C++11 attribute in "gnu" namespace.
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
@@ -236,7 +241,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
break;
}
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
if (!BuiltinType &&
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
@@ -277,10 +282,11 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation RParen = Tok.getLocation();
if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
AttributeList *attr =
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
- ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(),
- AttributeList::AS_GNU);
+ 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);
}
@@ -851,10 +857,6 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
Class.TagOrTemplate);
if (!Class.LateParsedDeclarations.empty()) {
- // Allow 'this' within late-parsed attributes.
- Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate,
- /*TypeQuals=*/0);
-
for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){
Class.LateParsedDeclarations[i]->ParseLexedAttributes();
}
@@ -869,6 +871,8 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
/// \brief Parse all attributes in LAs, and attach them to Decl D.
void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
bool EnterScope, bool OnDefinition) {
+ assert(LAs.parseSoon() &&
+ "Attribute list should be marked for immediate parsing.");
for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
if (D)
LAs[i]->addDecl(D);
@@ -904,34 +908,45 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
- if (LA.Decls.size() == 1) {
+ if (LA.Decls.size() > 0) {
Decl *D = LA.Decls[0];
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
- // If the Decl is templatized, add template parameters to scope.
- bool HasTemplateScope = EnterScope && D->isTemplateDecl();
- ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
- if (HasTemplateScope)
- Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
-
- // If the Decl is on a function, add function parameters to the scope.
- bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate();
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
- if (HasFunctionScope)
- Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
-
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
-
- if (HasFunctionScope) {
- Actions.ActOnExitFunctionContext();
- FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
- }
- if (HasTemplateScope) {
- TempScope.Exit();
+ // Allow 'this' within late-parsed attributes.
+ Sema::CXXThisScopeRAII ThisScope(Actions, RD,
+ /*TypeQuals=*/0,
+ ND && RD && ND->isCXXInstanceMember());
+
+ if (LA.Decls.size() == 1) {
+ // If the Decl is templatized, add template parameters to scope.
+ bool HasTemplateScope = EnterScope && D->isTemplateDecl();
+ ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
+
+ // If the Decl is on a function, add function parameters to the scope.
+ bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope);
+ if (HasFunScope)
+ Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
+
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
+
+ if (HasFunScope) {
+ Actions.ActOnExitFunctionContext();
+ FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
+ }
+ if (HasTemplateScope) {
+ TempScope.Exit();
+ }
+ } else {
+ // If there are multiple decls, then the decl cannot be within the
+ // function scope.
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
+ 0, SourceLocation(), AttributeList::AS_GNU);
}
- } else if (LA.Decls.size() > 0) {
- // If there are multiple decls, then the decl cannot be within the
- // function scope.
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
} else {
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
@@ -998,7 +1013,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
bool ArgExprsOk = true;
// now parse the list of expressions
@@ -1018,7 +1033,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
// Match the ')'.
if (ArgExprsOk && !T.consumeClose()) {
Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
- ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU);
+ ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU);
}
if (EndLoc)
*EndLoc = T.getCloseLocation();
@@ -1127,6 +1142,18 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
<< attrs.Range;
}
+void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
+ AttributeList *AttrList = attrs.getList();
+ while (AttrList) {
+ if (AttrList->isCXX0XAttribute()) {
+ Diag(AttrList->getLoc(), diag::warn_attribute_no_decl)
+ << AttrList->getName();
+ AttrList->setInvalid();
+ }
+ AttrList = AttrList->getNext();
+ }
+}
+
/// ParseDeclaration - Parse a full 'declaration', which consists of
/// declaration-specifiers, some number of declarators, and a semicolon.
/// 'Context' should be a Declarator::TheContext value. This returns the
@@ -1400,7 +1427,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Save late-parsed attributes for now; they need to be parsed in the
// appropriate function scope after the function Decl has been constructed.
- LateParsedAttrList LateParsedAttrs;
+ // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
+ LateParsedAttrList LateParsedAttrs(true);
if (D.isFunctionDeclarator())
MaybeParseGNUAttributes(D, &LateParsedAttrs);
@@ -1587,9 +1615,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
case ParsedTemplateInfo::Template:
case ParsedTemplateInfo::ExplicitSpecialization:
ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(),
- MultiTemplateParamsArg(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size()),
+ *TemplateInfo.TemplateParams,
D);
break;
@@ -1660,7 +1686,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector Exprs(Actions);
+ ExprVector Exprs;
CommaLocsTy CommaLocs;
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
@@ -1669,6 +1695,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
}
if (ParseExpressionList(Exprs, CommaLocs)) {
+ Actions.ActOnInitializerError(ThisDecl);
SkipUntil(tok::r_paren);
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
@@ -1689,7 +1716,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
T.getCloseLocation(),
- move_arg(Exprs));
+ Exprs);
Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
/*DirectInit=*/true, TypeContainsAuto);
}
@@ -1872,6 +1899,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break;
case DeclSpec::TST_struct:
TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break;
+ case DeclSpec::TST_interface:
+ TagName="__interface"; FixitTagName = "__interface ";
+ TagKind=tok::kw___interface;break;
case DeclSpec::TST_class:
TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break;
}
@@ -2069,13 +2099,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
return;
}
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
ArgExprs.push_back(ArgExpr.release());
// FIXME: This should not be GNU, but we since the attribute used is
// based on the spelling, and there is no true spelling for
// C++11 attributes, this isn't accepted.
Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
- 0, T.getOpenLocation(), ArgExprs.take(), 1,
+ 0, T.getOpenLocation(), ArgExprs.data(), 1,
AttributeList::AS_GNU);
}
@@ -2130,8 +2160,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DoneWithDeclSpec:
if (!AttrsLastTime)
ProhibitAttributes(attrs);
- else
+ else {
+ // Reject C++11 attributes that appertain to decl specifiers as
+ // we don't support any C++11 attributes that appertain to decl
+ // specifiers. This also conforms to what g++ 4.8 is doing.
+ ProhibitCXX11Attributes(attrs);
+
DS.takeAttributesFrom(attrs);
+ }
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
@@ -2271,6 +2307,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, T);
+ if (isInvalid)
+ break;
}
else
DS.SetTypeSpecError();
@@ -2476,12 +2514,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___forceinline: {
isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
- SourceLocation AttrNameLoc = ConsumeToken();
+ 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);
- continue;
+ break;
}
case tok::kw___ptr64:
@@ -2706,6 +2744,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
@@ -2723,15 +2762,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/true);
+ getLangOpts());
break;
// C++ typename-specifier:
@@ -3165,6 +3204,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// anything that's a simple-type-specifier followed by '(' as an
// expression. This suffices because function types are not valid
// underlying types anyway.
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Sema::ConstantEvaluated);
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
// If the next token starts an expression, we know we're parsing a
// bit-field. This is the common case.
@@ -3213,11 +3254,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2)
- Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
- << Range;
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus0x) {
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
+ } else if (!getLangOpts().ObjC2) {
+ if (getLangOpts().CPlusPlus)
+ Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type) << Range;
+ else
+ Diag(StartLoc, diag::ext_c_enum_fixed_underlying_type) << Range;
+ }
}
}
@@ -3526,6 +3570,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union:
// enum-specifier
case tok::kw_enum:
@@ -3597,6 +3642,7 @@ bool Parser::isTypeSpecifierQualifier() {
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
+ case tok::kw___interface:
case tok::kw_union:
// enum-specifier
case tok::kw_enum:
@@ -3735,6 +3781,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union:
+ case tok::kw___interface:
// enum-specifier
case tok::kw_enum:
@@ -3748,6 +3795,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_virtual:
case tok::kw_explicit:
+ // friend keyword.
+ case tok::kw_friend:
+
// static_assert-declaration
case tok::kw__Static_assert:
@@ -3756,11 +3806,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// GNU attributes.
case tok::kw___attribute:
- return true;
- // C++0x decltype.
+ // C++11 decltype and constexpr.
case tok::annot_decltype:
- return true;
+ case tok::kw_constexpr:
// C11 _Atomic()
case tok::kw__Atomic:
@@ -3925,15 +3974,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLangOpts(), /*IsTypeSpec*/false);
+ getLangOpts());
break;
// OpenCL qualifiers:
@@ -4344,7 +4393,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetIdentifier(0, Tok.getLocation());
} else {
if (Tok.getKind() == tok::annot_pragma_parser_crash)
- *(volatile int*) 0x11 = 0;
+ LLVM_BUILTIN_TRAP;
if (D.getContext() == Declarator::MemberContext)
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
@@ -4374,9 +4423,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// In such a case, check if we actually have a function declarator; if it
// is not, the declarator has been fully parsed.
bool IsAmbiguous = false;
- if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit() &&
- !isCXXFunctionDeclarator(&IsAmbiguous))
- break;
+ if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // The name of the declarator, if any, is tentatively declared within
+ // a possible direct initializer.
+ TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
+ bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
+ TentativelyDeclaredIdentifiers.pop_back();
+ if (!IsFunctionDecl)
+ break;
+ }
ParsedAttributes attrs(AttrFactory);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -4553,7 +4608,14 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Actions.ActOnStartFunctionDeclarator();
- SourceLocation EndLoc;
+ /* LocalEndLoc is the end location for the local FunctionTypeLoc.
+ EndLoc is the end location for the function declarator.
+ They differ for trailing return types. */
+ SourceLocation StartLoc, LocalEndLoc, EndLoc;
+ SourceLocation LParenLoc, RParenLoc;
+ LParenLoc = Tracker.getOpenLocation();
+ StartLoc = LParenLoc;
+
if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -4561,7 +4623,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ParseFunctionDeclaratorIdentifierList(D, ParamInfo);
Tracker.consumeClose();
- EndLoc = Tracker.getCloseLocation();
+ RParenLoc = Tracker.getCloseLocation();
+ LocalEndLoc = RParenLoc;
+ EndLoc = RParenLoc;
} else {
if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
@@ -4572,7 +4636,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// If we have the closing ')', eat it.
Tracker.consumeClose();
- EndLoc = Tracker.getCloseLocation();
+ RParenLoc = Tracker.getCloseLocation();
+ LocalEndLoc = RParenLoc;
+ EndLoc = RParenLoc;
if (getLangOpts().CPlusPlus) {
// FIXME: Accept these components in any order, and produce fixits to
@@ -4628,21 +4694,25 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
MaybeParseCXX0XAttributes(FnAttrs);
// Parse trailing-return-type[opt].
+ LocalEndLoc = EndLoc;
if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
+ if (D.getDeclSpec().getTypeSpecType() == TST_auto)
+ StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
+ LocalEndLoc = Tok.getLocation();
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range);
- if (Range.getEnd().isValid())
- EndLoc = Range.getEnd();
+ EndLoc = Range.getEnd();
}
}
}
// Remember that we parsed a function type, and remember the attributes.
D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto,
- /*isVariadic=*/EllipsisLoc.isValid(),
- IsAmbiguous, EllipsisLoc,
+ IsAmbiguous,
+ LParenLoc,
ParamInfo.data(), ParamInfo.size(),
+ EllipsisLoc, RParenLoc,
DS.getTypeQualifiers(),
RefQualifierIsLValueRef,
RefQualifierLoc, ConstQualifierLoc,
@@ -4654,8 +4724,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
- Tracker.getOpenLocation(),
- EndLoc, D,
+ StartLoc, LocalEndLoc, D,
TrailingReturnType),
FnAttrs, EndLoc);
@@ -5058,7 +5127,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const bool hasParens = Tok.is(tok::l_paren);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 3dc96cf0d294..4cb14e24f48f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -87,6 +88,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
if (Tok.is(tok::equal)) {
+ if (Ident == 0) {
+ Diag(Tok, diag::err_expected_ident);
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return 0;
+ }
if (!attrs.empty())
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
if (InlineLoc.isValid())
@@ -581,7 +588,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
if (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
- MultiTemplateParamsArg TemplateParamsArg(Actions,
+ MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
// FIXME: Propagate attributes.
@@ -616,12 +623,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
Diag(Tok, diag::err_expected_lparen);
+ SkipMalformedDecl();
return 0;
}
ExprResult AssertExpr(ParseConstantExpression());
if (AssertExpr.isInvalid()) {
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
@@ -630,13 +638,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal);
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
ExprResult AssertMessage(ParseStringLiteralExpression());
if (AssertMessage.isInvalid()) {
- SkipUntil(tok::semi);
+ SkipMalformedDecl();
return 0;
}
@@ -694,9 +702,22 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
0, /*IsDecltype=*/true);
Result = ParseExpression();
if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
DS.SetTypeSpecError();
- return StartLoc;
+ if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) {
+ EndLoc = ConsumeParen();
+ } else {
+ assert(Tok.is(tok::semi));
+ if (PP.isBacktrackEnabled()) {
+ // Backtrack to get the location of the last token before the semi.
+ PP.RevertCachedTokens(2);
+ ConsumeToken(); // the semi.
+ EndLoc = ConsumeAnyToken();
+ assert(Tok.is(tok::semi));
+ } else {
+ EndLoc = Tok.getLocation();
+ }
+ }
+ return EndLoc;
}
// Match the ')'
@@ -1034,6 +1055,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
+ else if (TagTokKind == tok::kw___interface)
+ TagType = DeclSpec::TST_interface;
else if (TagTokKind == tok::kw_class)
TagType = DeclSpec::TST_class;
else {
@@ -1151,7 +1174,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
<< (TagType == DeclSpec::TST_class? 0
: TagType == DeclSpec::TST_struct? 1
- : 2)
+ : TagType == DeclSpec::TST_interface? 2
+ : 3)
<< Name
<< SourceRange(LAngleLoc, RAngleLoc);
@@ -1243,8 +1267,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- TagType == DeclSpec::TST_class ? "class" :
- TagType == DeclSpec::TST_struct ? "struct" : "union");
+ DeclSpec::getSpecifierName(TagType));
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
}
@@ -1279,8 +1302,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
@@ -1362,7 +1384,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateArgsPtr,
TemplateId->RAngleLoc,
attrs.getList(),
- MultiTemplateParamsArg(Actions,
+ MultiTemplateParamsArg(
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
}
@@ -1389,7 +1411,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(),
TagType, StartLoc, SS,
Name, NameLoc, attrs.getList(),
- MultiTemplateParamsArg(Actions,
+ MultiTemplateParamsArg(
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
} else {
@@ -1470,8 +1492,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- TagType == DeclSpec::TST_class ? "class" :
- TagType == DeclSpec::TST_struct ? "struct" : "union");
+ DeclSpec::getSpecifierName(TagType));
// Push this token back into the preprocessor and change our current token
// to ';' so that the rest of the code recovers as though there were an
// ';' after the definition.
@@ -1667,7 +1688,8 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
/// virt-specifier-seq:
/// virt-specifier
/// virt-specifier-seq virt-specifier
-void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
+void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
+ bool IsInterface) {
while (true) {
VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
@@ -1681,10 +1703,15 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
<< PrevSpec
<< FixItHint::CreateRemoval(Tok.getLocation());
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword)
- << VirtSpecifiers::getSpecifierName(Specifier);
+ if (IsInterface && Specifier == VirtSpecifiers::VS_Final) {
+ Diag(Tok.getLocation(), diag::err_override_control_interface)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ } else {
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
+ }
ConsumeToken();
}
}
@@ -1869,7 +1896,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
&CommonLateParsedAttrs);
- MultiTemplateParamsArg TemplateParams(Actions,
+ MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
@@ -1905,7 +1932,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
+ ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -2026,7 +2053,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// FIXME: When g++ adds support for this, we'll need to check whether it
// goes before or after the GNU attributes and __asm__.
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
+ ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
InClassInitStyle HasInClassInit = ICIS_NoInit;
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
@@ -2052,11 +2079,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (DS.isFriendSpecified()) {
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
- move(TemplateParams));
+ TemplateParams);
} else {
ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
DeclaratorInfo,
- move(TemplateParams),
+ TemplateParams,
BitfieldSize.release(),
VS, HasInClassInit);
if (AccessAttrs)
@@ -2240,6 +2267,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
unsigned TagType, Decl *TagDecl) {
assert((TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_interface ||
TagType == DeclSpec::TST_union ||
TagType == DeclSpec::TST_class) && "Invalid TagType!");
@@ -2254,6 +2282,15 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (S->isClassScope()) {
// We're inside a class scope, so this is a nested class.
NonNestedClass = false;
+
+ // The Microsoft extension __interface does not permit nested classes.
+ if (getCurrentClass().IsInterface) {
+ Diag(RecordLoc, diag::err_invalid_member_in_interface)
+ << /*ErrorType=*/6
+ << (isa<NamedDecl>(TagDecl)
+ ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
+ : "<anonymous>");
+ }
break;
}
@@ -2274,7 +2311,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
- ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass);
+ ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
+ TagType == DeclSpec::TST_interface);
if (TagDecl)
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
@@ -2286,9 +2324,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
assert(isCXX0XFinalKeyword() && "not a class definition");
FinalLoc = ConsumeToken();
- Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_override_control_keyword :
- diag::ext_override_control_keyword) << "final";
+ if (TagType == DeclSpec::TST_interface) {
+ Diag(FinalLoc, diag::err_override_control_interface)
+ << "final";
+ } else {
+ Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword) << "final";
+ }
}
if (Tok.is(tok::colon)) {
@@ -2348,6 +2391,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_align)) {
+ HandlePragmaAlign();
+ continue;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2373,6 +2421,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
<< FixItHint::CreateInsertion(EndLoc, ":");
}
+ // The Microsoft extension __interface does not permit non-public
+ // access specifiers.
+ if (TagType == DeclSpec::TST_interface && CurAS != AS_public) {
+ Diag(ASLoc, diag::err_access_specifier_interface)
+ << (CurAS == AS_protected);
+ }
+
if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
AccessAttrs.getList())) {
// found another attribute than only annotations
@@ -2571,7 +2626,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
T.consumeOpen();
// Parse the optional expression-list.
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
SkipUntil(tok::r_paren);
@@ -2586,7 +2641,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
- T.getOpenLocation(), ArgExprs.take(),
+ T.getOpenLocation(), ArgExprs.data(),
ArgExprs.size(), T.getCloseLocation(),
EllipsisLoc);
}
@@ -2752,10 +2807,11 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
/// so push that class onto our stack of classes that is currently
/// being parsed.
Sema::ParsingClassState
-Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) {
+Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass,
+ bool IsInterface) {
assert((NonNestedClass || !ClassStack.empty()) &&
"Nested class without outer class");
- ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass));
+ ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface));
return Actions.PushParsingClass();
}
@@ -2773,9 +2829,6 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
/// This routine should be called when we have finished parsing the
/// definition of a class, but have not yet popped the Scope
/// associated with the class's definition.
-///
-/// \returns true if the class we've popped is a top-level class,
-/// false otherwise.
void Parser::PopParsingClass(Sema::ParsingClassState state) {
assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
@@ -2850,6 +2903,21 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
}
}
+static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
+ IdentifierInfo *ScopeName) {
+ switch (AttributeList::getKind(AttrName, ScopeName,
+ AttributeList::AS_CXX11)) {
+ case AttributeList::AT_CarriesDependency:
+ case AttributeList::AT_FallThrough:
+ case AttributeList::AT_NoReturn: {
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently
/// only parses standard attributes.
///
@@ -2934,46 +3002,38 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
}
}
+ bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName);
bool AttrParsed = false;
- switch (AttributeList::getKind(AttrName, ScopeName,
- AttributeList::AS_CXX11)) {
- // No arguments
- case AttributeList::AT_CarriesDependency:
- // FIXME: implement generic support of attributes with C++11 syntax
- // see Parse/ParseDecl.cpp: ParseGNUAttributes
- case AttributeList::AT_FallThrough:
- case AttributeList::AT_NoReturn: {
- if (Tok.is(tok::l_paren)) {
- Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
- << AttrName->getName();
- break;
+
+ // Parse attribute arguments
+ if (Tok.is(tok::l_paren)) {
+ if (ScopeName && ScopeName->getName() == "gnu") {
+ ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc,
+ ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+ AttrParsed = true;
+ } else {
+ if (StandardAttr)
+ Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
+ << AttrName->getName();
+
+ // FIXME: handle other formats of c++11 attribute arguments
+ ConsumeParen();
+ SkipUntil(tok::r_paren, false);
}
+ }
+ if (!AttrParsed)
attrs.addNew(AttrName,
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
AttrLoc),
ScopeName, ScopeLoc, 0,
SourceLocation(), 0, 0, AttributeList::AS_CXX11);
- AttrParsed = true;
- break;
- }
-
- // Silence warnings
- default: break;
- }
-
- // Skip the entire parameter clause, if any
- if (!AttrParsed && Tok.is(tok::l_paren)) {
- ConsumeParen();
- // SkipUntil maintains the balancedness of tokens.
- SkipUntil(tok::r_paren, false);
- }
if (Tok.is(tok::ellipsis)) {
- if (AttrParsed)
- Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
- << AttrName->getName();
ConsumeToken();
+
+ Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
+ << AttrName->getName();
}
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 8d4668b95481..c7be0d3ff2b9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -179,7 +179,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// \endverbatim
ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
ExprResult LHS(ParseAssignmentExpression(isTypeCast));
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// This routine is called when the '@' is seen and consumed.
@@ -190,7 +190,7 @@ ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
ExprResult
Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
ExprResult LHS(ParseObjCAtExpression(AtLoc));
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// This routine is called when a leading '__extension__' is seen and
@@ -210,7 +210,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__,
LHS.take());
- return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
/// \brief Parse an expr that doesn't include (top-level) commas.
@@ -227,7 +227,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
/*isAddressOfOperand=*/false,
isTypeCast);
- return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
+ return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
}
/// \brief Parse an assignment expression where part of an Objective-C message
@@ -265,6 +265,17 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
return Actions.ActOnConstantExpression(Res);
}
+bool Parser::isNotExpressionStart() {
+ tok::TokenKind K = Tok.getKind();
+ if (K == tok::l_brace || K == tok::r_brace ||
+ K == tok::kw_for || K == tok::kw_while ||
+ K == tok::kw_if || K == tok::kw_else ||
+ K == tok::kw_goto || K == tok::kw_try)
+ return true;
+ // If this is a decl-specifier, we can't be at the start of an expression.
+ return isKnownToBeDeclarationSpecifier();
+}
+
/// \brief Parse a binary expression that starts with \p LHS and has a
/// precedence of at least \p MinPrec.
ExprResult
@@ -279,12 +290,23 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// because we are called recursively, or because the token is not a binop),
// then we are done!
if (NextTokPrec < MinPrec)
- return move(LHS);
+ return LHS;
// Consume the operator, saving the operator token for error reporting.
Token OpToken = Tok;
ConsumeToken();
+ // Bail out when encountering a comma followed by a token which can't
+ // possibly be the start of an expression. For instance:
+ // int f() { return 1, }
+ // We can't do this before consuming the comma, because
+ // isNotExpressionStart() looks at the token stream.
+ if (OpToken.is(tok::comma) && isNotExpressionStart()) {
+ PP.EnterToken(Tok);
+ Tok = OpToken;
+ return LHS;
+ }
+
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
if (NextTokPrec == prec::Conditional) {
@@ -458,7 +480,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
isTypeCast);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
- return move(Res);
+ return Res;
}
namespace {
@@ -698,7 +720,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case CastExpr:
// We have parsed the cast-expression and no postfix-expr pieces are
// following.
- return move(Res);
+ return Res;
}
break;
@@ -741,6 +763,53 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// Avoid the unnecessary parse-time lookup in the common case
// where the syntax forbids a type.
const Token &Next = NextToken();
+
+ // If this identifier was reverted from a token ID, and the next token
+ // is a parenthesis, this is likely to be a use of a type trait. Check
+ // those tokens.
+ if (Next.is(tok::l_paren) &&
+ Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ // Build up the mapping of revertable type traits, for future use.
+ if (RevertableTypeTraits.empty()) {
+#define RTT_JOIN(X,Y) X##Y
+#define REVERTABLE_TYPE_TRAIT(Name) \
+ RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \
+ = RTT_JOIN(tok::kw_,Name)
+
+ REVERTABLE_TYPE_TRAIT(__is_arithmetic);
+ REVERTABLE_TYPE_TRAIT(__is_convertible);
+ REVERTABLE_TYPE_TRAIT(__is_empty);
+ REVERTABLE_TYPE_TRAIT(__is_floating_point);
+ REVERTABLE_TYPE_TRAIT(__is_function);
+ REVERTABLE_TYPE_TRAIT(__is_fundamental);
+ REVERTABLE_TYPE_TRAIT(__is_integral);
+ REVERTABLE_TYPE_TRAIT(__is_member_function_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_member_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_pod);
+ REVERTABLE_TYPE_TRAIT(__is_pointer);
+ REVERTABLE_TYPE_TRAIT(__is_same);
+ REVERTABLE_TYPE_TRAIT(__is_scalar);
+ REVERTABLE_TYPE_TRAIT(__is_signed);
+ REVERTABLE_TYPE_TRAIT(__is_unsigned);
+ 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 (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
Next.is(tok::less) ||
@@ -758,7 +827,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// '.'.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
-
+
// Support 'Class.property' and 'super.property' notation.
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
(Actions.getTypeName(II, ILoc, getCurScope()) ||
@@ -888,7 +957,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(!getLangOpts().CPlusPlus);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::amp: { // unary-expression: '&' cast-expression
// Special treatment because of member pointers
@@ -896,7 +965,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false, true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::star: // unary-expression: '*' cast-expression
@@ -910,7 +979,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
@@ -920,7 +989,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
- return move(Res);
+ return Res;
}
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
if (!getLangOpts().C11)
@@ -946,7 +1015,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Tok.getLocation());
Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD);
ConsumeToken();
- return move(Res);
+ return Res;
}
case tok::kw_const_cast:
case tok::kw_dynamic_cast:
@@ -1132,13 +1201,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (!Result.isInvalid())
Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(),
Result.take(), T.getCloseLocation());
- return move(Result);
+ return Result;
}
case tok::kw___is_abstract: // [GNU] unary-type-trait
case tok::kw___is_class:
case tok::kw___is_empty:
case tok::kw___is_enum:
+ case tok::kw___is_interface_class:
case tok::kw___is_literal:
case tok::kw___is_arithmetic:
case tok::kw___is_integral:
@@ -1270,7 +1340,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
switch (Tok.getKind()) {
case tok::code_completion:
if (InMessageExpression)
- return move(LHS);
+ return LHS;
Actions.CodeCompletePostfixExpression(getCurScope(), LHS);
cutOffParsing();
@@ -1290,7 +1360,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// Fall through; this isn't a message send.
default: // Not a postfix-expression suffix.
- return move(LHS);
+ return LHS;
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
// If we have a array postfix expression that starts on a new line and
// Objective-C is enabled, it is highly likely that the user forgot a
@@ -1300,7 +1370,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// expression and recover by pretending there is no suffix.
if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() &&
isSimpleObjCMessageExpression())
- return move(LHS);
+ return LHS;
// Reject array indices starting with a lambda-expression. '[[' is
// reserved for attributes.
@@ -1341,7 +1411,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
BalancedDelimiterTracker PT(*this, tok::l_paren);
if (OpKind == tok::lesslessless) {
- ExprVector ExecConfigExprs(Actions);
+ ExprVector ExecConfigExprs;
CommaLocsTy ExecConfigCommaLocs;
SourceLocation OpenLoc = ConsumeToken();
@@ -1372,7 +1442,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
OpenLoc,
- move_arg(ExecConfigExprs),
+ ExecConfigExprs,
CloseLoc);
if (ECResult.isInvalid())
LHS = ExprError();
@@ -1384,7 +1454,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Loc = PT.getOpenLocation();
}
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (Tok.is(tok::code_completion)) {
@@ -1414,7 +1484,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc,
- move_arg(ArgExprs), Tok.getLocation(),
+ ArgExprs, Tok.getLocation(),
ExecConfig);
PT.consumeClose();
}
@@ -1583,7 +1653,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
// If we get here, the operand to the typeof/sizeof/alignof was an expresion.
isCastExpr = false;
- return move(Operand);
+ return Operand;
}
@@ -1653,7 +1723,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof))
Diag(OpTok, diag::warn_cxx98_compat_alignof);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
@@ -1684,7 +1755,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
/*isType=*/false,
Operand.release(),
CastRange);
- return move(Operand);
+ return Operand;
}
/// ParseBuiltinPrimaryExpression
@@ -1796,7 +1867,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Res = ParseExpression();
if (Res.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Res);
+ return Res;
}
Comps.back().U.E = Res.release();
@@ -1823,7 +1894,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Cond(ParseAssignmentExpression());
if (Cond.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Cond);
+ return Cond;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
@@ -1831,7 +1902,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr1(ParseAssignmentExpression());
if (Expr1.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Expr1);
+ return Expr1;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprError();
@@ -1839,7 +1910,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
ExprResult Expr2(ParseAssignmentExpression());
if (Expr2.isInvalid()) {
SkipUntil(tok::r_paren);
- return move(Expr2);
+ return Expr2;
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
@@ -2083,7 +2154,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
DeclaratorInfo, CastTy,
RParenLoc, Result.take());
}
- return move(Result);
+ return Result;
}
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
@@ -2093,13 +2164,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
- ExprVector ArgExprs(Actions);
+ ExprVector ArgExprs;
CommaLocsTy CommaLocs;
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs));
+ ArgExprs);
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
@@ -2120,7 +2191,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
T.consumeClose();
RParenLoc = T.getCloseLocation();
- return move(Result);
+ return Result;
}
/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name
@@ -2141,7 +2212,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
ExprResult Result = ParseInitializer();
if (!Result.isInvalid() && Ty)
return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take());
- return move(Result);
+ return Result;
}
/// ParseStringLiteralExpression - This handles the various token types that
@@ -2211,8 +2282,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
}
SourceLocation DefaultLoc;
- TypeVector Types(Actions);
- ExprVector Exprs(Actions);
+ TypeVector Types;
+ ExprVector Exprs;
while (1) {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
@@ -2263,7 +2334,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc,
T.getCloseLocation(),
ControllingExpr.release(),
- move_arg(Types), move_arg(Exprs));
+ Types, Exprs);
}
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
@@ -2415,18 +2486,28 @@ ExprResult Parser::ParseBlockLiteralExpression() {
} else {
// Otherwise, pretend we saw (void).
ParsedAttributes attrs(AttrFactory);
- ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, false,
- SourceLocation(),
- 0, 0, 0,
- true, SourceLocation(),
- SourceLocation(),
- SourceLocation(),
- SourceLocation(),
- EST_None,
- SourceLocation(),
- 0, 0, 0, 0,
- CaretLoc, CaretLoc,
- ParamInfo),
+ SourceLocation NoLoc;
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/true,
+ /*IsAmbiguous=*/false,
+ /*RParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ CaretLoc, CaretLoc,
+ ParamInfo),
attrs, CaretLoc);
MaybeParseGNUAttributes(ParamInfo);
@@ -2450,7 +2531,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope());
else
Actions.ActOnBlockError(CaretLoc, getCurScope());
- return move(Result);
+ return Result;
}
/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index afac25793a73..2f615e150aad 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -96,6 +96,45 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
/*AtDigraph*/false);
}
+/// \brief Emits an error for a left parentheses after a double colon.
+///
+/// When a '(' is found after a '::', emit an error. Attempt to fix the token
+/// stream by removing the '(', and the matching ')' if it found.
+void Parser::CheckForLParenAfterColonColon() {
+ if (!Tok.is(tok::l_paren))
+ return;
+
+ SourceLocation l_parenLoc = ConsumeParen(), r_parenLoc;
+ Token Tok1 = getCurToken();
+ if (!Tok1.is(tok::identifier) && !Tok1.is(tok::star))
+ return;
+
+ if (Tok1.is(tok::identifier)) {
+ Token Tok2 = GetLookAheadToken(1);
+ if (Tok2.is(tok::r_paren)) {
+ ConsumeToken();
+ PP.EnterToken(Tok1);
+ r_parenLoc = ConsumeParen();
+ }
+ } else if (Tok1.is(tok::star)) {
+ Token Tok2 = GetLookAheadToken(1);
+ if (Tok2.is(tok::identifier)) {
+ Token Tok3 = GetLookAheadToken(2);
+ if (Tok3.is(tok::r_paren)) {
+ ConsumeToken();
+ ConsumeToken();
+ PP.EnterToken(Tok2);
+ PP.EnterToken(Tok1);
+ r_parenLoc = ConsumeParen();
+ }
+ }
+ }
+
+ Diag(l_parenLoc, diag::err_paren_after_colon_colon)
+ << FixItHint::CreateRemoval(l_parenLoc)
+ << FixItHint::CreateRemoval(r_parenLoc);
+}
+
/// \brief Parse global scope or nested-name-specifier if present.
///
/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
@@ -160,7 +199,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// '::' - Global scope qualifier.
if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS))
return true;
-
+
+ CheckForLParenAfterColonColon();
+
HasScopeSpecifier = true;
}
@@ -301,8 +342,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
HasScopeSpecifier = true;
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
@@ -372,6 +412,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
"NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
+ CheckForLParenAfterColonColon();
+
HasScopeSpecifier = true;
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
ObjectType, EnteringContext, SS))
@@ -757,10 +799,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Scope::FunctionPrototypeScope |
Scope::DeclScope);
- SourceLocation DeclLoc, DeclEndLoc;
+ SourceLocation DeclEndLoc;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- DeclLoc = T.getOpenLocation();
+ SourceLocation LParenLoc = T.getOpenLocation();
// Parse parameter-declaration-clause.
ParsedAttributes Attr(AttrFactory);
@@ -771,7 +813,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
T.consumeClose();
- DeclEndLoc = T.getCloseLocation();
+ SourceLocation RParenLoc = T.getCloseLocation();
+ DeclEndLoc = RParenLoc;
// Parse 'mutable'[opt].
SourceLocation MutableLoc;
@@ -797,9 +840,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse attribute-specifier[opt].
MaybeParseCXX0XAttributes(Attr, &DeclEndLoc);
+ SourceLocation FunLocalRangeEnd = DeclEndLoc;
+
// Parse trailing-return-type[opt].
TypeResult TrailingReturnType;
if (Tok.is(tok::arrow)) {
+ FunLocalRangeEnd = Tok.getLocation();
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range);
if (Range.getEnd().isValid())
@@ -808,15 +854,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
PrototypeScope.Exit();
+ SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
- /*isVariadic=*/EllipsisLoc.isValid(),
- /*isAmbiguous=*/false, EllipsisLoc,
+ /*isAmbiguous=*/false,
+ LParenLoc,
ParamInfo.data(), ParamInfo.size(),
+ EllipsisLoc, RParenLoc,
DS.getTypeQualifiers(),
/*RefQualifierIsLValueRef=*/true,
- /*RefQualifierLoc=*/SourceLocation(),
- /*ConstQualifierLoc=*/SourceLocation(),
- /*VolatileQualifierLoc=*/SourceLocation(),
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
MutableLoc,
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -824,7 +872,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
NoexceptExpr.get() : 0,
- DeclLoc, DeclEndLoc, D,
+ LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
} else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) {
@@ -853,25 +901,28 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
}
ParsedAttributes Attr(AttrFactory);
+ SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
- /*isVariadic=*/false,
- /*isAmbiguous=*/false,
- /*EllipsisLoc=*/SourceLocation(),
- /*Params=*/0, /*NumParams=*/0,
- /*TypeQuals=*/0,
- /*RefQualifierIsLValueRef=*/true,
- /*RefQualifierLoc=*/SourceLocation(),
- /*ConstQualifierLoc=*/SourceLocation(),
- /*VolatileQualifierLoc=*/SourceLocation(),
- MutableLoc,
- EST_None,
- /*ESpecLoc=*/SourceLocation(),
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
- /*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
- DeclLoc, DeclEndLoc, D,
- TrailingReturnType),
+ /*isAmbiguous=*/false,
+ /*LParenLoc=*/NoLoc,
+ /*Params=*/0,
+ /*NumParams=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLValueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ MutableLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ DeclLoc, DeclEndLoc, D,
+ TrailingReturnType),
Attr, DeclEndLoc);
}
@@ -926,10 +977,11 @@ ExprResult Parser::ParseCXXCasts() {
// Check for "<::" which is parsed as "[:". If found, fix token stream,
// diagnose error, suggest fix, and recover parsing.
- Token Next = NextToken();
- if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) &&
- areTokensAdjacent(Tok, Next))
- FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
+ if (Tok.is(tok::l_square) && Tok.getLength() == 2) {
+ Token Next = NextToken();
+ if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next))
+ FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
+ }
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
@@ -965,7 +1017,7 @@ ExprResult Parser::ParseCXXCasts() {
T.getOpenLocation(), Result.take(),
T.getCloseLocation());
- return move(Result);
+ return Result;
}
/// ParseCXXTypeid - This handles the C++ typeid expression.
@@ -988,6 +1040,22 @@ ExprResult Parser::ParseCXXTypeid() {
ExprResult Result;
+ // C++0x [expr.typeid]p3:
+ // When typeid is applied to an expression other than an lvalue of a
+ // polymorphic class type [...] The expression is an unevaluated
+ // operand (Clause 5).
+ //
+ // Note that we can't tell whether the expression is an lvalue of a
+ // polymorphic class type until after we've parsed the expression; we
+ // speculatively assume the subexpression is unevaluated, and fix it up
+ // later.
+ //
+ // We enter the unevaluated context before trying to determine whether we
+ // have a type-id, because the tentative parse logic will try to resolve
+ // names, and must treat them as unevaluated.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
+
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
@@ -1000,16 +1068,6 @@ ExprResult Parser::ParseCXXTypeid() {
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
Ty.get().getAsOpaquePtr(), RParenLoc);
} else {
- // C++0x [expr.typeid]p3:
- // When typeid is applied to an expression other than an lvalue of a
- // polymorphic class type [...] The expression is an unevaluated
- // operand (Clause 5).
- //
- // Note that we can't tell whether the expression is an lvalue of a
- // polymorphic class type until after we've parsed the expression; we
- // speculatively assume the subexpression is unevaluated, and fix it up
- // later.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -1026,7 +1084,7 @@ ExprResult Parser::ParseCXXTypeid() {
}
}
- return move(Result);
+ return Result;
}
/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression.
@@ -1074,7 +1132,7 @@ ExprResult Parser::ParseCXXUuidof() {
}
}
- return move(Result);
+ return Result;
}
/// \brief Parse a C++ pseudo-destructor expression after the base,
@@ -1196,7 +1254,7 @@ ExprResult Parser::ParseThrowExpression() {
default:
ExprResult Expr(ParseAssignmentExpression());
- if (Expr.isInvalid()) return move(Expr);
+ if (Expr.isInvalid()) return Expr;
return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take());
}
}
@@ -1245,7 +1303,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- ExprVector Exprs(Actions);
+ ExprVector Exprs;
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren)) {
@@ -1265,7 +1323,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
- move_arg(Exprs),
+ Exprs,
T.getCloseLocation());
}
}
@@ -1280,11 +1338,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
-/// \param ExprResult if the condition was parsed as an expression, the
-/// parsed expression.
+/// \param ExprOut if the condition was parsed as an expression, the parsed
+/// expression.
///
-/// \param DeclResult if the condition was parsed as a declaration, the
-/// parsed declaration.
+/// \param DeclOut if the condition was parsed as a declaration, the parsed
+/// declaration.
///
/// \param Loc The location of the start of the statement that requires this
/// condition, e.g., the "for" in a for loop.
@@ -1714,8 +1772,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
}
// Bundle the template arguments together.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgs.size());
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
// Constructor and destructor names.
TypeResult Type
@@ -1762,7 +1819,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
/// ptr-operator conversion-declarator[opt]
/// \endcode
///
-/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// \param SS The nested-name-specifier that preceded this unqualified-id. If
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
///
/// \param EnteringContext whether we are entering the scope of the
@@ -1867,8 +1924,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse a literal-operator-id.
//
- // literal-operator-id: [C++0x 13.5.8]
- // operator "" identifier
+ // literal-operator-id: C++11 [over.literal]
+ // operator string-literal identifier
+ // operator user-defined-string-literal
if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
@@ -1882,6 +1940,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
llvm::SmallVector<SourceLocation, 4> TokLocs;
while (isTokenStringLiteral()) {
if (!Tok.is(tok::string_literal) && !DiagId) {
+ // C++11 [over.literal]p1:
+ // The string-literal or user-defined-string-literal in a
+ // literal-operator-id shall have no encoding-prefix [...].
DiagLoc = Tok.getLocation();
DiagId = diag::err_literal_operator_string_prefix;
}
@@ -1903,9 +1964,6 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
Literal.getUDSuffixOffset(),
PP.getSourceManager(), getLangOpts());
- // This form is not permitted by the standard (yet).
- DiagLoc = SuffixLoc;
- DiagId = diag::err_literal_operator_missing_space;
} else if (Tok.is(tok::identifier)) {
II = Tok.getIdentifierInfo();
SuffixLoc = ConsumeToken();
@@ -1917,6 +1975,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// The string literal must be empty.
if (!Literal.GetString().empty() || Literal.Pascal) {
+ // C++11 [over.literal]p1:
+ // The string-literal or user-defined-string-literal in a
+ // literal-operator-id shall [...] contain no characters
+ // other than the implicit terminating '\0'.
DiagLoc = TokLocs.front();
DiagId = diag::err_literal_operator_string_not_empty;
}
@@ -1981,7 +2043,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
///
/// \endcode
///
-/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// \param SS The nested-name-specifier that preceded this unqualified-id. If
/// non-empty, then we are parsing the unqualified-id of a qualified-id.
///
/// \param EnteringContext whether we are entering the scope of the
@@ -2209,7 +2271,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
// A '(' now can be a new-placement or the '(' wrapping the type-id in the
// second form of new-expression. It can't be a new-type-id.
- ExprVector PlacementArgs(Actions);
+ ExprVector PlacementArgs;
SourceLocation PlacementLParen, PlacementRParen;
SourceRange TypeIdParens;
@@ -2279,7 +2341,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
if (Tok.is(tok::l_paren)) {
SourceLocation ConstructorLParen, ConstructorRParen;
- ExprVector ConstructorArgs(Actions);
+ ExprVector ConstructorArgs;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
@@ -2298,7 +2360,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
}
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
- move_arg(ConstructorArgs));
+ ConstructorArgs);
} else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -2308,7 +2370,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return Initializer;
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
- move_arg(PlacementArgs), PlacementRParen,
+ PlacementArgs, PlacementRParen,
TypeIdParens, DeclaratorInfo, Initializer.take());
}
@@ -2422,7 +2484,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
ExprResult Operand(ParseCastExpression(false));
if (Operand.isInvalid())
- return move(Operand);
+ return Operand;
return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take());
}
@@ -2453,6 +2515,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_function: return UTT_IsFunction;
case tok::kw___is_fundamental: return UTT_IsFundamental;
case tok::kw___is_integral: return UTT_IsIntegral;
+ case tok::kw___is_interface_class: return UTT_IsInterfaceClass;
case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference;
case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer;
case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer;
@@ -2804,7 +2867,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
DeclaratorInfo, CastTy,
Tracker.getCloseLocation(), Result.take());
- return move(Result);
+ return Result;
}
// Not a compound literal, and not followed by a cast-expression.
@@ -2823,5 +2886,5 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
}
Tracker.consumeClose();
- return move(Result);
+ return Result;
}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 1c349fddbd57..e47fd9bd24a6 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -313,7 +313,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
Idx = ParseAssignmentExpression();
if (Idx.isInvalid()) {
SkipUntil(tok::r_square);
- return move(Idx);
+ return Idx;
}
}
@@ -341,7 +341,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
ExprResult RHS(ParseConstantExpression());
if (RHS.isInvalid()) {
SkipUntil(tok::r_square);
- return move(RHS);
+ return RHS;
}
Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
RHS.release(),
@@ -405,15 +405,14 @@ ExprResult Parser::ParseBraceInitializer() {
/// InitExprs - This is the actual list of expressions contained in the
/// initializer.
- ExprVector InitExprs(Actions);
+ ExprVector InitExprs;
if (Tok.is(tok::r_brace)) {
// Empty initializers are a C++ feature and a GNU extension to C.
if (!getLangOpts().CPlusPlus)
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
// Match the '}'.
- return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions),
- ConsumeBrace());
+ return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace());
}
bool InitExprsOk = true;
@@ -476,7 +475,7 @@ ExprResult Parser::ParseBraceInitializer() {
bool closed = !T.consumeClose();
if (InitExprsOk && closed)
- return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
+ return Actions.ActOnInitList(LBraceLoc, InitExprs,
T.getCloseLocation());
return ExprError(); // an error occurred.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index db35a386c350..d321baf836bf 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -1031,7 +1032,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Scope::FunctionPrototypeScope|Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
-
while (1) {
ParsedAttributes paramAttrs(AttrFactory);
Sema::ObjCArgInfo ArgInfo;
@@ -1102,6 +1102,14 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SelIdent = ParseObjCSelectorPiece(selLoc);
if (!SelIdent && Tok.isNot(tok::colon))
break;
+ if (!SelIdent) {
+ SourceLocation ColonLoc = Tok.getLocation();
+ if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) {
+ Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name;
+ Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name;
+ Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name;
+ }
+ }
// We have a selector or a colon, continue parsing.
}
@@ -1806,7 +1814,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
- StmtVector CatchStmts(Actions);
+ StmtVector CatchStmts;
StmtResult FinallyStmt;
ParseScope TryScope(this, Scope::DeclScope);
StmtResult TryBody(ParseCompoundStatementBody());
@@ -1894,7 +1902,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
}
return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(),
- move_arg(CatchStmts),
+ CatchStmts,
FinallyStmt.take());
}
@@ -2061,13 +2069,13 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take());
if (Lit.isInvalid())
- return move(Lit);
+ return Lit;
return ParsePostfixExpressionSuffix(
Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2134,7 +2142,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
}
-/// \brirg Parse the receiver of an Objective-C++ message send.
+/// \brief Parse the receiver of an Objective-C++ message send.
///
/// This routine parses the receiver of a message send in
/// Objective-C++ either as a type or as an expression. Note that this
@@ -2346,7 +2354,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
ExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
@@ -2418,7 +2426,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
- ExprVector KeyExprs(Actions);
+ ExprVector KeyExprs;
if (Tok.is(tok::colon)) {
while (1) {
@@ -2465,7 +2473,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// We have a valid expression.
@@ -2512,7 +2520,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// We have a valid expression.
@@ -2551,32 +2559,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (SuperLoc.isValid())
return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
else if (ReceiverType)
return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel,
- LBracLoc, KeyLocs, RBracLoc,
- MultiExprArg(Actions,
- KeyExprs.take(),
- KeyExprs.size()));
+ LBracLoc, KeyLocs, RBracLoc, KeyExprs);
}
ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
ExprResult Res(ParseStringLiteralExpression());
- if (Res.isInvalid()) return move(Res);
+ if (Res.isInvalid()) return Res;
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
// expressions. At this point, we know that the only valid thing that starts
// with '@' is an @"".
SmallVector<SourceLocation, 4> AtLocs;
- ExprVector AtStrings(Actions);
+ ExprVector AtStrings;
AtLocs.push_back(AtLoc);
AtStrings.push_back(Res.release());
@@ -2589,12 +2588,12 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
ExprResult Lit(ParseStringLiteralExpression());
if (Lit.isInvalid())
- return move(Lit);
+ return Lit;
AtStrings.push_back(Lit.release());
}
- return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
+ return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
AtStrings.size()));
}
@@ -2615,7 +2614,7 @@ ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2629,7 +2628,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
ExprResult Lit(Actions.ActOnNumericConstant(Tok));
if (Lit.isInvalid()) {
- return move(Lit);
+ return Lit;
}
ConsumeToken(); // Consume the literal token.
return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
@@ -2661,7 +2660,7 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
}
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
- ExprVector ElementExprs(Actions); // array elements.
+ ExprVector ElementExprs; // array elements.
ConsumeBracket(); // consume the l_square.
while (Tok.isNot(tok::r_square)) {
@@ -2672,7 +2671,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_square);
- return move(Res);
+ return Res;
}
// Parse the ellipsis that indicates a pack expansion.
@@ -2689,7 +2688,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma));
}
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
- MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size());
+ MultiExprArg Args(ElementExprs);
return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args));
}
@@ -2707,7 +2706,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_brace);
- return move(KeyExpr);
+ return KeyExpr;
}
}
@@ -2723,7 +2722,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// stop at the '}' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
SkipUntil(tok::r_brace);
- return move(ValueExpr);
+ return ValueExpr;
}
// Parse the ellipsis that designates this as a pack expansion.
@@ -2752,7 +2751,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
}
/// objc-encode-expression:
-/// @encode ( type-name )
+/// \@encode ( type-name )
ExprResult
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index eb13e0d3574a..a7605f0cf4e0 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -40,7 +40,7 @@ void Parser::HandlePragmaVisibility() {
struct PragmaPackInfo {
Sema::PragmaPackKind Kind;
IdentifierInfo *Name;
- Expr *Alignment;
+ Token Alignment;
SourceLocation LParenLoc;
SourceLocation RParenLoc;
};
@@ -50,10 +50,107 @@ void Parser::HandlePragmaPack() {
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
SourceLocation PragmaLoc = ConsumeToken();
- Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc,
+ ExprResult Alignment;
+ if (Info->Alignment.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Info->Alignment);
+ if (Alignment.isInvalid())
+ return;
+ }
+ Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc,
Info->LParenLoc, Info->RParenLoc);
}
+void Parser::HandlePragmaMSStruct() {
+ assert(Tok.is(tok::annot_pragma_msstruct));
+ Sema::PragmaMSStructKind Kind =
+ static_cast<Sema::PragmaMSStructKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ Actions.ActOnPragmaMSStruct(Kind);
+ ConsumeToken(); // The annotation token.
+}
+
+void Parser::HandlePragmaAlign() {
+ assert(Tok.is(tok::annot_pragma_align));
+ Sema::PragmaOptionsAlignKind Kind =
+ static_cast<Sema::PragmaOptionsAlignKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ SourceLocation PragmaLoc = ConsumeToken();
+ Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
+}
+
+void Parser::HandlePragmaWeak() {
+ assert(Tok.is(tok::annot_pragma_weak));
+ SourceLocation PragmaLoc = ConsumeToken();
+ Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc,
+ Tok.getLocation());
+ ConsumeToken(); // The weak name.
+}
+
+void Parser::HandlePragmaWeakAlias() {
+ assert(Tok.is(tok::annot_pragma_weakalias));
+ SourceLocation PragmaLoc = ConsumeToken();
+ IdentifierInfo *WeakName = Tok.getIdentifierInfo();
+ SourceLocation WeakNameLoc = Tok.getLocation();
+ ConsumeToken();
+ IdentifierInfo *AliasName = Tok.getIdentifierInfo();
+ SourceLocation AliasNameLoc = Tok.getLocation();
+ ConsumeToken();
+ Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc,
+ WeakNameLoc, AliasNameLoc);
+
+}
+
+void Parser::HandlePragmaRedefineExtname() {
+ assert(Tok.is(tok::annot_pragma_redefine_extname));
+ SourceLocation RedefLoc = ConsumeToken();
+ IdentifierInfo *RedefName = Tok.getIdentifierInfo();
+ SourceLocation RedefNameLoc = Tok.getLocation();
+ ConsumeToken();
+ IdentifierInfo *AliasName = Tok.getIdentifierInfo();
+ SourceLocation AliasNameLoc = Tok.getLocation();
+ ConsumeToken();
+ Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
+ RedefNameLoc, AliasNameLoc);
+}
+
+void Parser::HandlePragmaFPContract() {
+ assert(Tok.is(tok::annot_pragma_fp_contract));
+ tok::OnOffSwitch OOS =
+ static_cast<tok::OnOffSwitch>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ Actions.ActOnPragmaFPContract(OOS);
+ ConsumeToken(); // The annotation token.
+}
+
+namespace {
+ typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData;
+}
+
+void Parser::HandlePragmaOpenCLExtension() {
+ assert(Tok.is(tok::annot_pragma_opencl_extension));
+ OpenCLExtData data =
+ OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue());
+ unsigned state = data.getInt();
+ IdentifierInfo *ename = data.getPointer();
+ SourceLocation NameLoc = Tok.getLocation();
+ ConsumeToken(); // The annotation token.
+
+ OpenCLOptions &f = Actions.getOpenCLOptions();
+ // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
+ // overriding all previously issued extension directives, but only if the
+ // behavior is set to disable."
+ if (state == 0 && ename->isStr("all")) {
+#define OPENCLEXT(nm) f.nm = 0;
+#include "clang/Basic/OpenCLExtensions.def"
+ }
+#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
+#include "clang/Basic/OpenCLExtensions.def"
+ else {
+ PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
+ return;
+ }
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -130,13 +227,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
Sema::PragmaPackKind Kind = Sema::PPK_Default;
IdentifierInfo *Name = 0;
- ExprResult Alignment;
+ Token Alignment;
+ Alignment.startToken();
SourceLocation LParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
@@ -165,9 +261,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
@@ -182,9 +276,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
return;
}
- Alignment = Actions.ActOnNumericConstant(Tok);
- if (Alignment.isInvalid())
- return;
+ Alignment = Tok;
PP.Lex(Tok);
}
@@ -219,7 +311,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
new (Info) PragmaPackInfo();
Info->Kind = Kind;
Info->Name = Name;
- Info->Alignment = Alignment.release();
+ Info->Alignment = Alignment;
Info->LParenLoc = LParenLoc;
Info->RParenLoc = RParenLoc;
@@ -265,12 +357,23 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
<< "ms_struct";
return;
}
- Actions.ActOnPragmaMSStruct(Kind);
+
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_msstruct);
+ Toks[0].setLocation(MSStructTok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(Kind)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
-static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
+static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
bool IsOptions) {
Token Tok;
@@ -317,7 +420,6 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
return;
}
- SourceLocation KindLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
@@ -325,19 +427,29 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
return;
}
- Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_align);
+ Toks[0].setLocation(FirstTok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(Kind)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &AlignTok) {
- ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
+ ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false);
}
void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &OptionsTok) {
- ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
+ ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true);
}
// #pragma unused(identifier)
@@ -426,7 +538,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &WeakTok) {
- // FIXME: Should we be expanding macros here? My guess is no.
SourceLocation WeakLoc = WeakTok.getLocation();
Token Tok;
@@ -436,19 +547,20 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
return;
}
- IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
- SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
+ Token WeakName = Tok;
+ bool HasAlias = false;
+ Token AliasName;
PP.Lex(Tok);
if (Tok.is(tok::equal)) {
+ HasAlias = true;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "weak";
return;
}
- AliasName = Tok.getIdentifierInfo();
- AliasNameLoc = Tok.getLocation();
+ AliasName = Tok;
PP.Lex(Tok);
}
@@ -457,11 +569,29 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
return;
}
- if (AliasName) {
- Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
- AliasNameLoc);
+ if (HasAlias) {
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 3, llvm::alignOf<Token>());
+ Token &pragmaUnusedTok = Toks[0];
+ pragmaUnusedTok.startToken();
+ pragmaUnusedTok.setKind(tok::annot_pragma_weakalias);
+ pragmaUnusedTok.setLocation(WeakLoc);
+ Toks[1] = WeakName;
+ Toks[2] = AliasName;
+ PP.EnterTokenStream(Toks, 3,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
} else {
- Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 2, llvm::alignOf<Token>());
+ Token &pragmaUnusedTok = Toks[0];
+ pragmaUnusedTok.startToken();
+ pragmaUnusedTok.setKind(tok::annot_pragma_weak);
+ pragmaUnusedTok.setLocation(WeakLoc);
+ Toks[1] = WeakName;
+ PP.EnterTokenStream(Toks, 2,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
}
@@ -479,17 +609,16 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
return;
}
- IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0;
- SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc;
-
+ Token RedefName = Tok;
PP.Lex(Tok);
+
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "redefine_extname";
return;
}
- AliasName = Tok.getIdentifierInfo();
- AliasNameLoc = Tok.getLocation();
+
+ Token AliasName = Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
@@ -498,8 +627,17 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
return;
}
- Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
- RedefNameLoc, AliasNameLoc);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 3, llvm::alignOf<Token>());
+ Token &pragmaRedefTok = Toks[0];
+ pragmaRedefTok.startToken();
+ pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname);
+ pragmaRedefTok.setLocation(RedefLoc);
+ Toks[1] = RedefName;
+ Toks[2] = AliasName;
+ PP.EnterTokenStream(Toks, 3,
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
@@ -511,7 +649,17 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
if (PP.LexOnOffSwitch(OOS))
return;
- Actions.ActOnPragmaFPContract(OOS);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_fp_contract);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setAnnotationValue(reinterpret_cast<void*>(
+ static_cast<uintptr_t>(OOS)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
void
@@ -550,19 +698,23 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
return;
}
- OpenCLOptions &f = Actions.getOpenCLOptions();
- // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
- // overriding all previously issued extension directives, but only if the
- // behavior is set to disable."
- if (state == 0 && ename->isStr("all")) {
-#define OPENCLEXT(nm) f.nm = 0;
-#include "clang/Basic/OpenCLExtensions.def"
- }
-#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
-#include "clang/Basic/OpenCLExtensions.def"
- else {
- PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
+ "OPENCL EXTENSION";
return;
}
+
+ OpenCLExtData data(ename, state);
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_opencl_extension);
+ Toks[0].setLocation(NameLoc);
+ Toks[0].setAnnotationValue(data.getOpaqueValue());
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index fef6960813d8..b9a2a251fcd4 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -21,9 +21,8 @@ namespace clang {
class Parser;
class PragmaAlignHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {}
+ explicit PragmaAlignHandler() : PragmaHandler("align") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
@@ -31,38 +30,31 @@ public:
class PragmaGCCVisibilityHandler : public PragmaHandler {
public:
- explicit PragmaGCCVisibilityHandler(Sema &/*A*/)
- : PragmaHandler("visibility") {}
+ explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaOptionsHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"),
- Actions(A) {}
+ explicit PragmaOptionsHandler() : PragmaHandler("options") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaPackHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"),
- Actions(A) {}
+ explicit PragmaPackHandler() : PragmaHandler("pack") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaMSStructHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaMSStructHandler(Sema &A) : PragmaHandler("ms_struct"),
- Actions(A) {}
+ explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
@@ -70,48 +62,39 @@ public:
class PragmaUnusedHandler : public PragmaHandler {
public:
- PragmaUnusedHandler(Sema &/*A*/)
- : PragmaHandler("unused") {}
+ PragmaUnusedHandler() : PragmaHandler("unused") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaWeakHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaWeakHandler(Sema &A)
- : PragmaHandler("weak"), Actions(A) {}
+ explicit PragmaWeakHandler() : PragmaHandler("weak") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaRedefineExtnameHandler : public PragmaHandler {
- Sema &Actions;
public:
- explicit PragmaRedefineExtnameHandler(Sema &A)
- : PragmaHandler("redefine_extname"), Actions(A) {}
+ explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaOpenCLExtensionHandler : public PragmaHandler {
- Sema &Actions;
public:
- PragmaOpenCLExtensionHandler(Sema &A) :
- PragmaHandler("EXTENSION"), Actions(A) {}
+ PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaFPContractHandler : public PragmaHandler {
- Sema &Actions;
public:
- PragmaFPContractHandler(Sema &A) :
- PragmaHandler("FP_CONTRACT"), Actions(A) {}
+ PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index df9b996aa315..f604e038d2ad 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -17,6 +17,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
+#include "clang/Sema/TypoCorrection.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
@@ -130,96 +131,38 @@ Retry:
return ParseLabeledStatement(Attrs);
}
+ // Look up the identifier, and typo-correct it to a keyword if it's not
+ // found.
if (Next.isNot(tok::coloncolon)) {
- CXXScopeSpec SS;
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation NameLoc = Tok.getLocation();
-
- if (getLangOpts().CPlusPlus)
- CheckForTemplateAndDigraph(Next, ParsedType(),
- /*EnteringContext=*/false, *Name, SS);
-
- Sema::NameClassification Classification
- = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next);
- switch (Classification.getKind()) {
- case Sema::NC_Keyword:
- // The identifier was corrected to a keyword. Update the token
- // to this keyword, and try again.
- if (Name->getTokenID() != tok::identifier) {
- Tok.setIdentifierInfo(Name);
- Tok.setKind(Name->getTokenID());
- goto Retry;
- }
-
- // Fall through via the normal error path.
- // FIXME: This seems like it could only happen for context-sensitive
- // keywords.
-
- case Sema::NC_Error:
+ // 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)
+ == 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);
if (Tok.is(tok::semi))
ConsumeToken();
return StmtError();
-
- case Sema::NC_Unknown:
- // Either we don't know anything about this identifier, or we know that
- // we're in a syntactic context we haven't handled yet.
- break;
-
- case Sema::NC_Type:
- Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Classification.getType());
- Tok.setAnnotationEndLoc(NameLoc);
- PP.AnnotateCachedTokens(Tok);
- break;
-
- case Sema::NC_Expression:
- Tok.setKind(tok::annot_primary_expr);
- setExprAnnotation(Tok, Classification.getExpression());
- Tok.setAnnotationEndLoc(NameLoc);
- PP.AnnotateCachedTokens(Tok);
- break;
-
- case Sema::NC_TypeTemplate:
- case Sema::NC_FunctionTemplate: {
- ConsumeToken(); // the identifier
- UnqualifiedId Id;
- Id.setIdentifier(Name, NameLoc);
- if (AnnotateTemplateIdToken(
- TemplateTy::make(Classification.getTemplateName()),
- Classification.getTemplateNameKind(),
- SS, SourceLocation(), Id,
- /*AllowTypeAnnotation=*/false)) {
- // 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);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
-
- // If the next token is '::', jump right into parsing a
- // nested-name-specifier. We don't want to leave the template-id
- // hanging.
- if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){
- // 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);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
-
- // We've annotated a template-id, so try again now.
- goto Retry;
}
- case Sema::NC_NestedNameSpecifier:
- // FIXME: Implement this!
- break;
- }
+ // If the identifier was typo-corrected, try again.
+ if (Tok.isNot(tok::identifier))
+ goto Retry;
}
// Fall through
@@ -289,7 +232,7 @@ Retry:
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
Res = Actions.ActOnFinishFullStmt(Res.get());
- if (msAsm) return move(Res);
+ if (msAsm) return Res;
SemiError = "asm";
break;
}
@@ -310,6 +253,41 @@ Retry:
ProhibitAttributes(Attrs);
HandlePragmaPack();
return StmtEmpty();
+
+ case tok::annot_pragma_msstruct:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSStruct();
+ return StmtEmpty();
+
+ case tok::annot_pragma_align:
+ ProhibitAttributes(Attrs);
+ HandlePragmaAlign();
+ return StmtEmpty();
+
+ case tok::annot_pragma_weak:
+ ProhibitAttributes(Attrs);
+ HandlePragmaWeak();
+ return StmtEmpty();
+
+ case tok::annot_pragma_weakalias:
+ ProhibitAttributes(Attrs);
+ HandlePragmaWeakAlias();
+ return StmtEmpty();
+
+ case tok::annot_pragma_redefine_extname:
+ ProhibitAttributes(Attrs);
+ HandlePragmaRedefineExtname();
+ return StmtEmpty();
+
+ case tok::annot_pragma_fp_contract:
+ Diag(Tok, diag::err_pragma_fp_contract_scope);
+ ConsumeToken();
+ return StmtError();
+
+ case tok::annot_pragma_opencl_extension:
+ ProhibitAttributes(Attrs);
+ HandlePragmaOpenCLExtension();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -324,7 +302,7 @@ Retry:
SkipUntil(tok::r_brace, true, true);
}
- return move(Res);
+ return Res;
}
/// \brief Parse an expression statement.
@@ -381,7 +359,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
StmtResult TryBlock(ParseCompoundStatement());
if(TryBlock.isInvalid())
- return move(TryBlock);
+ return TryBlock;
StmtResult Handler;
if (Tok.is(tok::identifier) &&
@@ -396,7 +374,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
}
if(Handler.isInvalid())
- return move(Handler);
+ return Handler;
return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
TryLoc,
@@ -441,7 +419,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
}
@@ -458,7 +436,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
StmtResult Block(ParseCompoundStatement());
if(Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
}
@@ -603,7 +581,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// Otherwise we link it into the current chain.
Stmt *NextDeepest = Case.get();
if (TopLevelCase.isInvalid())
- TopLevelCase = move(Case);
+ TopLevelCase = Case;
else
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
DeepestParsedCaseStmt = NextDeepest;
@@ -636,7 +614,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
// Return the top level parsed statement tree.
- return move(TopLevelCase);
+ return TopLevelCase;
}
/// ParseDefaultStatement
@@ -728,6 +706,48 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
return ParseCompoundStatementBody(isStmtExpr);
}
+/// Parse any pragmas at the start of the compound expression. We handle these
+/// separately since some pragmas (FP_CONTRACT) must appear before any C
+/// statement in the compound, but may be intermingled with other pragmas.
+void Parser::ParseCompoundStatementLeadingPragmas() {
+ bool checkForPragmas = true;
+ while (checkForPragmas) {
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_vis:
+ HandlePragmaVisibility();
+ break;
+ case tok::annot_pragma_pack:
+ HandlePragmaPack();
+ break;
+ case tok::annot_pragma_msstruct:
+ HandlePragmaMSStruct();
+ break;
+ case tok::annot_pragma_align:
+ HandlePragmaAlign();
+ break;
+ case tok::annot_pragma_weak:
+ HandlePragmaWeak();
+ break;
+ case tok::annot_pragma_weakalias:
+ HandlePragmaWeakAlias();
+ break;
+ case tok::annot_pragma_redefine_extname:
+ HandlePragmaRedefineExtname();
+ break;
+ case tok::annot_pragma_opencl_extension:
+ HandlePragmaOpenCLExtension();
+ break;
+ case tok::annot_pragma_fp_contract:
+ HandlePragmaFPContract();
+ break;
+ default:
+ checkForPragmas = false;
+ break;
+ }
+ }
+
+}
+
/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
/// consume the '}' at the end of the block. It does not manipulate the scope
@@ -736,6 +756,11 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
"in compound statement ('{}')");
+
+ // Record the state of the FP_CONTRACT pragma, restore on leaving the
+ // compound statement.
+ Sema::FPContractStateRAII SaveFPContractState(Actions);
+
InMessageExpressionRAIIObject InMessage(*this, false);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen())
@@ -743,7 +768,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- StmtVector Stmts(Actions);
+ // Parse any pragmas at the beginning of the compound statement.
+ ParseCompoundStatementLeadingPragmas();
+
+ StmtVector Stmts;
// "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
// only allowed at the start of a compound stmt regardless of the language.
@@ -850,7 +878,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
}
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
- move_arg(Stmts), isStmtExpr);
+ Stmts, isStmtExpr);
}
/// ParseParenExprOrCondition:
@@ -1096,7 +1124,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
SkipUntil(tok::r_brace, false, false);
} else
SkipUntil(tok::semi);
- return move(Switch);
+ return Switch;
}
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
@@ -1375,7 +1403,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
DeclEnd, attrs, false,
MightBeForRangeStmt ?
@@ -1498,7 +1526,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
- T.getCloseLocation());
+ T.getCloseLocation(),
+ Sema::BFRK_Build);
// Similarly, we need to do the semantic analysis for a for-range
@@ -1580,7 +1609,7 @@ StmtResult Parser::ParseGotoStatement() {
return StmtError();
}
- return move(Res);
+ return Res;
}
/// ParseContinueStatement
@@ -1653,6 +1682,9 @@ StmtResult Parser::ParseReturnStatement() {
/// ms-asm-line '\n' ms-asm-instruction-block
///
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
+ // MS-style inline assembly is not fully supported, so emit a warning.
+ Diag(AsmLoc, diag::warn_unsupported_msasm);
+
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
@@ -1745,6 +1777,21 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
return StmtError();
}
+ // If MS-style inline assembly is disabled, then build an empty asm.
+ if (!getLangOpts().EmitMicrosoftInlineAsm) {
+ Token t;
+ t.setKind(tok::string_literal);
+ t.setLiteralData("\"/*FIXME: not done*/\"");
+ t.clearFlag(Token::NeedsCleaning);
+ t.setLength(21);
+ ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
+ ExprVector Constraints;
+ ExprVector Exprs;
+ ExprVector Clobbers;
+ return Actions.ActOnGCCAsmStmt(AsmLoc, true, true, 0, 0, 0, Constraints,
+ Exprs, AsmString.take(), Clobbers, EndLoc);
+ }
+
// FIXME: We should be passing source locations for better diagnostics.
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc,
llvm::makeArrayRef(AsmToks), EndLoc);
@@ -1806,18 +1853,17 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
SmallVector<IdentifierInfo *, 4> Names;
- ExprVector Constraints(Actions);
- ExprVector Exprs(Actions);
- ExprVector Clobbers(Actions);
+ ExprVector Constraints;
+ ExprVector Exprs;
+ ExprVector Clobbers;
if (Tok.is(tok::r_paren)) {
// We have a simple asm expression like 'asm("foo")'.
T.consumeClose();
- return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
- /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
- move_arg(Constraints), move_arg(Exprs),
- AsmString.take(), move_arg(Clobbers),
- T.getCloseLocation());
+ return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
+ Constraints, Exprs, AsmString.take(),
+ Clobbers, T.getCloseLocation());
}
// Parse Outputs, if present.
@@ -1878,11 +1924,10 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
}
T.consumeClose();
- return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile,
- NumOutputs, NumInputs, Names.data(),
- move_arg(Constraints), move_arg(Exprs),
- AsmString.take(), move_arg(Clobbers),
- T.getCloseLocation());
+ return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,
+ NumInputs, Names.data(), Constraints, Exprs,
+ AsmString.take(), Clobbers,
+ T.getCloseLocation());
}
/// ParseAsmOperands - Parse the asm-operands production as used by
@@ -1975,7 +2020,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(Actions), false);
+ MultiStmtArg(), false);
}
BodyScope.Exit();
@@ -2006,13 +2051,13 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
}
SourceLocation LBraceLoc = Tok.getLocation();
- StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
+ StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
// If we failed to parse the try-catch, we just give the function an empty
// compound statement as the body.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
- MultiStmtArg(Actions), false);
+ MultiStmtArg(), false);
}
BodyScope.Exit();
@@ -2024,12 +2069,18 @@ bool Parser::trySkippingFunctionBody() {
assert(SkipFunctionBodies &&
"Should only be called when SkipFunctionBodies is enabled");
+ if (!PP.isCodeCompletionEnabled()) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false);
+ return true;
+ }
+
// We're in code-completion mode. Skip parsing for all function bodies unless
// the body contains the code-completion point.
TentativeParsingAction PA(*this);
ConsumeBrace();
if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false,
- /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) {
+ /*StopAtCodeCompletion=*/true)) {
PA.Commit();
return true;
}
@@ -2066,15 +2117,16 @@ StmtResult Parser::ParseCXXTryBlock() {
/// 'try' compound-statement seh-except-block
/// 'try' compound-statment seh-finally-block
///
-StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
+StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope|Scope::TryScope));
+ Scope::DeclScope |
+ (FnTry ? Scope::FnTryScope : Scope::TryScope)));
if (TryBlock.isInvalid())
- return move(TryBlock);
+ return TryBlock;
// Borland allows SEH-handlers with 'try'
@@ -2092,7 +2144,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
Handler = ParseSEHFinallyBlock(Loc);
}
if(Handler.isInvalid())
- return move(Handler);
+ return Handler;
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
TryLoc,
@@ -2100,7 +2152,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
Handler.take());
}
else {
- StmtVector Handlers(Actions);
+ StmtVector Handlers;
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
ProhibitAttributes(attrs);
@@ -2108,7 +2160,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::kw_catch))
return StmtError(Diag(Tok, diag::err_expected_catch));
while (Tok.is(tok::kw_catch)) {
- StmtResult Handler(ParseCXXCatchBlock());
+ StmtResult Handler(ParseCXXCatchBlock(FnTry));
if (!Handler.isInvalid())
Handlers.push_back(Handler.release());
}
@@ -2117,7 +2169,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Handlers.empty())
return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),move_arg(Handlers));
+ return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers);
}
}
@@ -2132,7 +2184,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
/// type-specifier-seq
/// '...'
///
-StmtResult Parser::ParseCXXCatchBlock() {
+StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
SourceLocation CatchLoc = ConsumeToken();
@@ -2144,7 +2196,8 @@ StmtResult Parser::ParseCXXCatchBlock() {
// C++ 3.3.2p3:
// The name in a catch exception-declaration is local to the handler and
// shall not be redeclared in the outermost block of the handler.
- ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope);
+ ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
+ (FnCatch ? Scope::FnCatchScope : 0));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
@@ -2169,7 +2222,7 @@ StmtResult Parser::ParseCXXCatchBlock() {
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult Block(ParseCompoundStatement());
if (Block.isInvalid())
- return move(Block);
+ return Block;
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index ade918fb221a..2e0411e8a81c 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -246,7 +246,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
return 0;
}
- LateParsedAttrList LateParsedAttrs;
+ LateParsedAttrList LateParsedAttrs(true);
if (DeclaratorInfo.isFunctionDeclarator())
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -889,8 +889,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
return true;
}
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
- TemplateArgs.size());
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
@@ -942,8 +941,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
Tok.setLocation(TemplateKWLoc);
else
Tok.setLocation(TemplateNameLoc);
-
- TemplateArgsPtr.release();
}
// Common fields for the annotation token
@@ -969,8 +966,7 @@ void Parser::AnnotateTemplateIdTokenAsType() {
TemplateId->Kind == TNK_Dependent_template_name) &&
"Only works for type and dependent templates");
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult Type
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 1a4df4791b5f..40c4eee1994b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -104,16 +104,27 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
// a case.
- TPResult TPR = isCXXDeclarationSpecifier();
+ bool InvalidAsDeclaration = false;
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ &InvalidAsDeclaration);
if (TPR != TPResult::Ambiguous())
return TPR != TPResult::False(); // Returns true for TPResult::True() or
// TPResult::Error().
+ // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
+ // and so gets some cases wrong. We can't carry on if we've already seen
+ // something which makes this statement invalid as a declaration in this case,
+ // since it can cause us to misparse valid code. Revisit this once
+ // TryParseInitDeclaratorList is fixed.
+ if (InvalidAsDeclaration)
+ return false;
+
// FIXME: Add statistics about the number of ambiguous statements encountered
// and how they were resolved (number of declarations+number of expressions).
- // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
- // We need tentative parsing...
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '(',
+ // or an identifier which doesn't resolve as anything. We need tentative
+ // parsing...
TentativeParsingAction PA(*this);
TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
@@ -140,20 +151,28 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
/// attribute-specifier-seqopt type-specifier-seq declarator
///
Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
- // We know that we have a simple-type-specifier/typename-specifier followed
- // by a '('.
- assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
-
if (Tok.is(tok::kw_typeof))
TryParseTypeofSpecifier();
else {
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
ConsumeToken();
-
+
if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
-
- assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // Two decl-specifiers in a row conclusively disambiguate this as being a
+ // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
+ // overwhelmingly common case that the next token is a '('.
+ if (Tok.isNot(tok::l_paren)) {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR == TPResult::Ambiguous())
+ return TPResult::True();
+ if (TPR == TPResult::True() || TPR == TPResult::Error())
+ return TPR;
+ assert(TPR == TPResult::False());
+ }
TPResult TPR = TryParseInitDeclaratorList();
if (TPR != TPResult::Ambiguous())
@@ -623,6 +642,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// declarator-id
if (Tok.is(tok::annot_cxxscope))
ConsumeToken();
+ else
+ TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
ConsumeToken();
} else if (Tok.is(tok::l_paren)) {
ConsumeParen();
@@ -761,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_convertible_to:
case tok::kw___is_empty:
case tok::kw___is_enum:
+ case tok::kw___is_interface_class:
case tok::kw___is_final:
case tok::kw___is_literal:
case tok::kw___is_literal_type:
@@ -824,6 +846,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
return TPResult::Ambiguous();
}
+bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
+ return std::find(TentativelyDeclaredIdentifiers.begin(),
+ TentativelyDeclaredIdentifiers.end(), II)
+ != TentativelyDeclaredIdentifiers.end();
+}
+
/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
/// be either a decl-specifier or a function-style cast, and TPResult::Error()
@@ -831,7 +859,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
///
/// If HasMissingTypename is provided, a name with a dependent scope specifier
/// will be treated as ambiguous if the 'typename' keyword is missing. If this
-/// happens, *HasMissingTypename will be set to 'true'.
+/// happens, *HasMissingTypename will be set to 'true'. This will also be used
+/// as an indicator that undeclared identifiers (which will trigger a later
+/// parse error) should be treated as types. Returns TPResult::Ambiguous() in
+/// such cases.
///
/// decl-specifier:
/// storage-class-specifier
@@ -927,22 +958,64 @@ Parser::TPResult
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
bool *HasMissingTypename) {
switch (Tok.getKind()) {
- case tok::identifier: // foo::bar
+ case tok::identifier: {
// Check for need to substitute AltiVec __vector keyword
// for "vector" identifier.
if (TryAltiVecVectorToken())
return TPResult::True();
- // Fall through.
+
+ const Token &Next = NextToken();
+ // In 'foo bar', 'foo' is always a type name outside of Objective-C.
+ if (!getLangOpts().ObjC1 && Next.is(tok::identifier))
+ return TPResult::True();
+
+ if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
+ // Determine whether this is a valid expression. If not, we will hit
+ // a parse error one way or another. In that case, tell the caller that
+ // this is ambiguous. Typo-correct to type and expression keywords and
+ // to types and identifiers, in order to try to recover from errors.
+ CorrectionCandidateCallback TypoCorrection;
+ TypoCorrection.WantRemainingKeywords = false;
+ switch (TryAnnotateName(false /* no nested name specifier */,
+ &TypoCorrection)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False();
+ case ANK_Success:
+ break;
+ }
+ assert(Tok.isNot(tok::identifier) &&
+ "TryAnnotateName succeeded without producing an annotation");
+ } else {
+ // This might possibly be a type with a dependent scope specifier and
+ // a missing 'typename' keyword. Don't use TryAnnotateName in this case,
+ // since it will annotate as a primary expression, and we want to use the
+ // "missing 'typename'" logic.
+ if (TryAnnotateTypeOrScopeToken())
+ return TPResult::Error();
+ // If annotation failed, assume it's a non-type.
+ // FIXME: If this happens due to an undeclared identifier, treat it as
+ // ambiguous.
+ if (Tok.is(tok::identifier))
+ return TPResult::False();
+ }
+
+ // We annotated this token as something. Recurse to handle whatever we got.
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
+ }
+
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error();
- if (Tok.is(tok::identifier)) {
- const Token &Next = NextToken();
- return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ?
- TPResult::True() : TPResult::False();
- }
return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
case tok::coloncolon: { // ::foo::bar
@@ -1073,6 +1146,28 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
*HasMissingTypename = true;
return TPResult::Ambiguous();
}
+ } else {
+ // Try to resolve the name. If it doesn't exist, assume it was
+ // intended to name a type and keep disambiguating.
+ switch (TryAnnotateName(false /* SS is not dependent */)) {
+ case ANK_Error:
+ return TPResult::Error();
+ case ANK_TentativeDecl:
+ return TPResult::False();
+ case ANK_TemplateName:
+ // A bare type template-name which can't be a template template
+ // argument is an error, and was probably intended to be a type.
+ return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ case ANK_Unresolved:
+ return HasMissingTypename ? TPResult::Ambiguous()
+ : TPResult::False();
+ case ANK_Success:
+ // Annotated it, check again.
+ assert(Tok.isNot(tok::annot_cxxscope) ||
+ NextToken().isNot(tok::identifier));
+ return isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
+ }
}
}
return TPResult::False();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 3725e2b84550..f4cdd619cef4 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ASTConsumer.h"
using namespace clang;
+
namespace {
/// \brief A comment handler that passes comments found by the preprocessor
/// to the parser action.
@@ -47,11 +48,13 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
return Ident__except;
}
-Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
+Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
GreaterThanIsOperator(true), ColonIsSacred(false),
InMessageExpression(false), TemplateParameterDepth(0),
- ParsingInObjCContainer(false), SkipFunctionBodies(SkipFunctionBodies) {
+ ParsingInObjCContainer(false) {
+ SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
+ Tok.startToken();
Tok.setKind(tok::eof);
Actions.CurScope = 0;
NumCachedScopes = 0;
@@ -60,35 +63,35 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
- AlignHandler.reset(new PragmaAlignHandler(actions));
+ AlignHandler.reset(new PragmaAlignHandler());
PP.AddPragmaHandler(AlignHandler.get());
- GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions));
+ GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler());
PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
- OptionsHandler.reset(new PragmaOptionsHandler(actions));
+ OptionsHandler.reset(new PragmaOptionsHandler());
PP.AddPragmaHandler(OptionsHandler.get());
- PackHandler.reset(new PragmaPackHandler(actions));
+ PackHandler.reset(new PragmaPackHandler());
PP.AddPragmaHandler(PackHandler.get());
- MSStructHandler.reset(new PragmaMSStructHandler(actions));
+ MSStructHandler.reset(new PragmaMSStructHandler());
PP.AddPragmaHandler(MSStructHandler.get());
- UnusedHandler.reset(new PragmaUnusedHandler(actions));
+ UnusedHandler.reset(new PragmaUnusedHandler());
PP.AddPragmaHandler(UnusedHandler.get());
- WeakHandler.reset(new PragmaWeakHandler(actions));
+ WeakHandler.reset(new PragmaWeakHandler());
PP.AddPragmaHandler(WeakHandler.get());
- RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions));
+ RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler());
PP.AddPragmaHandler(RedefineExtnameHandler.get());
- FPContractHandler.reset(new PragmaFPContractHandler(actions));
+ FPContractHandler.reset(new PragmaFPContractHandler());
PP.AddPragmaHandler("STDC", FPContractHandler.get());
if (getLangOpts().OpenCL) {
- OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler(actions));
+ OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
@@ -135,7 +138,7 @@ DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) {
/// given range.
///
/// \param Loc The location where we'll emit the diagnostic.
-/// \param Loc The kind of diagnostic to emit.
+/// \param DK The kind of diagnostic to emit.
/// \param ParenRange Source range enclosing code that should be parenthesized.
void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange) {
@@ -154,7 +157,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) {
switch (ExpectedTok) {
- case tok::semi: return Tok.is(tok::colon); // : for ;
+ case tok::semi:
+ return Tok.is(tok::colon) || Tok.is(tok::comma); // : or , for ;
default: return false;
}
}
@@ -466,9 +470,6 @@ void Parser::Initialize() {
EnterScope(Scope::DeclScope);
Actions.ActOnTranslationUnitScope(getCurScope());
- // Prime the lexer look-ahead.
- ConsumeToken();
-
// Initialization for Objective-C context sensitive keywords recognition.
// Referenced in Parser::ParseObjCTypeQualifierList.
if (getLangOpts().ObjC1) {
@@ -523,6 +524,11 @@ void Parser::Initialize() {
PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block);
PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
}
+
+ Actions.Initialize();
+
+ // Prime the lexer look-ahead.
+ ConsumeToken();
}
namespace {
@@ -634,6 +640,27 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_pack:
HandlePragmaPack();
return DeclGroupPtrTy();
+ case tok::annot_pragma_msstruct:
+ HandlePragmaMSStruct();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_align:
+ HandlePragmaAlign();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_weak:
+ HandlePragmaWeak();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_weakalias:
+ HandlePragmaWeakAlias();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_redefine_extname:
+ HandlePragmaRedefineExtname();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_fp_contract:
+ HandlePragmaFPContract();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_opencl_extension:
+ HandlePragmaOpenCLExtension();
+ return DeclGroupPtrTy();
case tok::semi:
ConsumeExtraSemi(OutsideFunction);
// TODO: Invoke action for top-level semicolon.
@@ -693,7 +720,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
@@ -704,7 +731,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
goto dont_know;
@@ -716,7 +743,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
@@ -726,7 +753,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- StmtVector Stmts(Actions);
+ StmtVector Stmts;
return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs);
}
}
@@ -972,16 +999,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (getLangOpts().DelayedTemplateParsing &&
Tok.isNot(tok::equal) &&
TemplateInfo.Kind == ParsedTemplateInfo::Template) {
- MultiTemplateParamsArg TemplateParameterLists(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size());
+ MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = Actions.HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ TemplateParameterLists);
D.complete(DP);
D.getMutableDeclSpec().abort();
@@ -1009,13 +1034,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
(Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
Actions.CurContext->isTranslationUnit()) {
- MultiTemplateParamsArg TemplateParameterLists(Actions, 0, 0);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ MultiTemplateParamsArg());
D.complete(FuncDecl);
D.getMutableDeclSpec().abort();
if (FuncDecl) {
@@ -1033,10 +1057,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// specified Declarator for the function.
Decl *Res = TemplateInfo.TemplateParams?
Actions.ActOnStartOfFunctionTemplateDef(getCurScope(),
- MultiTemplateParamsArg(Actions,
- TemplateInfo.TemplateParams->data(),
- TemplateInfo.TemplateParams->size()),
- D)
+ *TemplateInfo.TemplateParams, D)
: Actions.ActOnStartOfFunctionDef(getCurScope(), D);
// Break out of the ParsingDeclarator context before we parse the body.
@@ -1288,7 +1309,7 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
*EndLoc = T.getCloseLocation();
}
- return move(Result);
+ return Result;
}
/// \brief Get the TemplateIdAnnotation from the token and put it in the
@@ -1301,6 +1322,143 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
return Id;
}
+void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them
+ // with the annotation token. We don't need to do this if we've
+ // just reverted back to a prior state.
+ if (IsNewAnnotation)
+ PP.AnnotateCachedTokens(Tok);
+}
+
+/// \brief Attempt to classify the name at the current token position. This may
+/// form a type, scope or primary expression annotation, or replace the token
+/// with a typo-corrected keyword. This is only appropriate when the current
+/// name must refer to an entity which has already been declared.
+///
+/// \param IsAddressOfOperand Must be \c true if the name is preceded by an '&'
+/// and might possibly have a dependent nested name specifier.
+/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
+/// no typo correction will be performed.
+Parser::AnnotatedNameKind
+Parser::TryAnnotateName(bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC) {
+ assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
+
+ const bool EnteringContext = false;
+ const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+
+ CXXScopeSpec SS;
+ if (getLangOpts().CPlusPlus &&
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+ return ANK_Error;
+
+ if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS,
+ !WasScopeAnnotation))
+ return ANK_Error;
+ return ANK_Unresolved;
+ }
+
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = Tok.getLocation();
+
+ // FIXME: Move the tentative declaration logic into ClassifyName so we can
+ // typo-correct to tentatively-declared identifiers.
+ if (isTentativelyDeclared(Name)) {
+ // Identifier has been tentatively declared, and thus cannot be resolved as
+ // an expression. Fall back to annotating it as a type.
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS,
+ !WasScopeAnnotation))
+ return ANK_Error;
+ return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl;
+ }
+
+ Token Next = NextToken();
+
+ // Look up and classify the identifier. We don't perform any typo-correction
+ // after a scope specifier, because in general we can't recover from typos
+ // there (eg, after correcting 'A::tempalte B<X>::C', we would need to jump
+ // back into scope specifier parsing).
+ Sema::NameClassification Classification
+ = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
+ IsAddressOfOperand, SS.isEmpty() ? CCC : 0);
+
+ switch (Classification.getKind()) {
+ case Sema::NC_Error:
+ return ANK_Error;
+
+ case Sema::NC_Keyword:
+ // The identifier was typo-corrected to a keyword.
+ Tok.setIdentifierInfo(Name);
+ Tok.setKind(Name->getTokenID());
+ PP.TypoCorrectToken(Tok);
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ // We've "annotated" this as a keyword.
+ return ANK_Success;
+
+ case Sema::NC_Unknown:
+ // It's not something we know about. Leave it unannotated.
+ break;
+
+ case Sema::NC_Type:
+ Tok.setKind(tok::annot_typename);
+ setTypeAnnotation(Tok, Classification.getType());
+ Tok.setAnnotationEndLoc(NameLoc);
+ if (SS.isNotEmpty())
+ Tok.setLocation(SS.getBeginLoc());
+ PP.AnnotateCachedTokens(Tok);
+ return ANK_Success;
+
+ case Sema::NC_Expression:
+ Tok.setKind(tok::annot_primary_expr);
+ setExprAnnotation(Tok, Classification.getExpression());
+ Tok.setAnnotationEndLoc(NameLoc);
+ if (SS.isNotEmpty())
+ Tok.setLocation(SS.getBeginLoc());
+ PP.AnnotateCachedTokens(Tok);
+ return ANK_Success;
+
+ case Sema::NC_TypeTemplate:
+ if (Next.isNot(tok::less)) {
+ // This may be a type template being used as a template template argument.
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_TemplateName;
+ }
+ // Fall through.
+ case Sema::NC_FunctionTemplate: {
+ // We have a type or function template followed by '<'.
+ ConsumeToken();
+ UnqualifiedId Id;
+ Id.setIdentifier(Name, NameLoc);
+ if (AnnotateTemplateIdToken(
+ TemplateTy::make(Classification.getTemplateName()),
+ Classification.getTemplateNameKind(), SS, SourceLocation(), Id))
+ return ANK_Error;
+ return ANK_Success;
+ }
+
+ case Sema::NC_NestedNameSpecifier:
+ llvm_unreachable("already parsed nested name specifier");
+ }
+
+ // Unable to classify the name, but maybe we can annotate a scope specifier.
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_Unresolved;
+}
+
/// 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
@@ -1377,8 +1535,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
return true;
}
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
@@ -1404,13 +1561,24 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
}
// Remembers whether the token was originally a scope annotation.
- bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope);
+ bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
CXXScopeSpec SS;
if (getLangOpts().CPlusPlus)
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
return true;
+ return TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, NeedType,
+ SS, !WasScopeAnnotation);
+}
+
+/// \brief Try to annotate a type or scope token, having already parsed an
+/// optional scope specifier. \p IsNewScope should be \c true unless the scope
+/// specifier was extracted from an existing tok::annot_cxxscope annotation.
+bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
+ bool NeedType,
+ CXXScopeSpec &SS,
+ bool IsNewScope) {
if (Tok.is(tok::identifier)) {
IdentifierInfo *CorrectedII = 0;
// Determine whether the identifier is a type name.
@@ -1492,21 +1660,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
return false;
// A C++ scope specifier that isn't followed by a typename.
- // Push the current token back into the token stream (or revert it if it is
- // cached) and use an annotation scope token for current token.
- if (PP.isBacktrackEnabled())
- PP.RevertCachedTokens(1);
- else
- PP.EnterToken(Tok);
- Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
- Tok.setAnnotationRange(SS.getRange());
-
- // In case the tokens were cached, have Preprocessor replace them
- // with the annotation token. We don't need to do this if we've
- // just reverted back to the state we were in before being called.
- if (!wasScopeAnnotation)
- PP.AnnotateCachedTokens(Tok);
+ AnnotateScopeToken(SS, IsNewScope);
return false;
}
@@ -1529,19 +1683,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
if (SS.isEmpty())
return false;
- // Push the current token back into the token stream (or revert it if it is
- // cached) and use an annotation scope token for current token.
- if (PP.isBacktrackEnabled())
- PP.RevertCachedTokens(1);
- else
- PP.EnterToken(Tok);
- Tok.setKind(tok::annot_cxxscope);
- Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS));
- Tok.setAnnotationRange(SS.getRange());
-
- // In case the tokens were cached, have Preprocessor replace them with the
- // annotation token.
- PP.AnnotateCachedTokens(Tok);
+ AnnotateScopeToken(SS, true);
return false;
}
@@ -1798,8 +1940,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() {
}
P.Diag(P.Tok, DID);
P.Diag(LOpen, diag::note_matching) << LHSName;
- if (P.SkipUntil(Close))
- LClose = P.Tok.getLocation();
+ if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true))
+ LClose = P.ConsumeAnyToken();
return true;
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 455c4af2ffae..060fd206cd71 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -87,9 +87,8 @@ namespace clang {
Sema::ParsingDeclState State;
bool Popped;
- // Do not implement.
- ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other);
- ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other);
+ ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION;
+ void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION;
public:
enum NoParent_t { NoParent };
@@ -245,8 +244,9 @@ namespace clang {
/// the way they used to be. This is used to handle __extension__ in the
/// parser.
class ExtensionRAIIObject {
- void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
- ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
+ ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION;
+ void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION;
+
DiagnosticsEngine &Diags;
public:
ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index af8f6d4f90dd..d3d75430233f 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -1,33 +1,2 @@
-add_clang_library(clangRewrite
- DeltaTree.cpp
- FixItRewriter.cpp
- FrontendActions.cpp
- HTMLPrint.cpp
- HTMLRewrite.cpp
- InclusionRewriter.cpp
- RewriteMacros.cpp
- RewriteModernObjC.cpp
- RewriteObjC.cpp
- RewriteRope.cpp
- RewriteTest.cpp
- Rewriter.cpp
- TokenRewriter.cpp
- )
-
-add_dependencies(clangRewrite
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangRewrite
- clangBasic
- clangAST
- clangParse
- clangFrontend
- )
+add_subdirectory(Core)
+add_subdirectory(Frontend)
diff --git a/lib/Rewrite/Core/CMakeLists.txt b/lib/Rewrite/Core/CMakeLists.txt
new file mode 100644
index 000000000000..07978187ff19
--- /dev/null
+++ b/lib/Rewrite/Core/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_clang_library(clangRewriteCore
+ DeltaTree.cpp
+ HTMLRewrite.cpp
+ RewriteRope.cpp
+ Rewriter.cpp
+ TokenRewriter.cpp
+ )
+
+add_dependencies(clangRewriteCore
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangRewriteCore
+ clangBasic
+ clangAST
+ clangParse
+ )
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/Core/DeltaTree.cpp
index 4297dc8de62f..46922772c5a2 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/Core/DeltaTree.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/DeltaTree.h"
+#include "clang/Rewrite/Core/DeltaTree.h"
#include "clang/Basic/LLVM.h"
#include <cstring>
#include <cstdio>
@@ -113,8 +113,6 @@ namespace {
void RecomputeFullDeltaLocally();
void Destroy();
-
- //static inline bool classof(const DeltaTreeNode *) { return true; }
};
} // end anonymous namespace
@@ -149,7 +147,6 @@ namespace {
return Children[i];
}
- //static inline bool classof(const DeltaTreeInteriorNode *) { return true; }
static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
};
}
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp
index 236b98fc2828..0e8e4fec9f4a 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/Core/HTMLRewrite.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Rewriter.h"
-#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
@@ -484,6 +484,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// Temporarily change the diagnostics object so that we ignore any generated
// diagnostics from this pass.
DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
+ &PP.getDiagnostics().getDiagnosticOptions(),
new IgnoringDiagConsumer);
// FIXME: This is a huge hack; we reuse the input preprocessor because we want
diff --git a/lib/Rewrite/Core/Makefile b/lib/Rewrite/Core/Makefile
new file mode 100644
index 000000000000..8c8d2e478135
--- /dev/null
+++ b/lib/Rewrite/Core/Makefile
@@ -0,0 +1,18 @@
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangRewriteCore
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/Core/RewriteRope.cpp
index cc8de1b11a18..fe7aa2d6477d 100644
--- a/lib/Rewrite/RewriteRope.cpp
+++ b/lib/Rewrite/Core/RewriteRope.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/RewriteRope.h"
+#include "clang/Rewrite/Core/RewriteRope.h"
#include "clang/Basic/LLVM.h"
#include <algorithm>
using namespace clang;
@@ -117,8 +117,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeNode *) { return true; }
-
};
} // end anonymous namespace
@@ -221,7 +219,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeLeaf *) { return true; }
static inline bool classof(const RopePieceBTreeNode *N) {
return N->isLeaf();
}
@@ -458,7 +455,6 @@ namespace {
/// guaranteed that there is a split at Offset.
void erase(unsigned Offset, unsigned NumBytes);
- //static inline bool classof(const RopePieceBTreeInterior *) { return true; }
static inline bool classof(const RopePieceBTreeNode *N) {
return !N->isLeaf();
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp
index 7c27114f1cfd..4df967f39bc0 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Core/Rewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/DiagnosticIDs.h"
diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp
index 03ce63ea1174..940ece2f9e03 100644
--- a/lib/Rewrite/TokenRewriter.cpp
+++ b/lib/Rewrite/Core/TokenRewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/TokenRewriter.h"
+#include "clang/Rewrite/Core/TokenRewriter.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Basic/SourceManager.h"
diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..9017e479ab77
--- /dev/null
+++ b/lib/Rewrite/Frontend/CMakeLists.txt
@@ -0,0 +1,28 @@
+add_clang_library(clangRewriteFrontend
+ FixItRewriter.cpp
+ FrontendActions.cpp
+ HTMLPrint.cpp
+ InclusionRewriter.cpp
+ RewriteMacros.cpp
+ RewriteModernObjC.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+ )
+
+add_dependencies(clangRewriteFrontend
+ ClangAttrClasses
+ ClangAttrList
+ ClangAttrParsedAttrList
+ ClangCommentNodes
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangRewriteFrontend
+ clangBasic
+ clangAST
+ clangParse
+ clangFrontend
+ )
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp
index 3863adb4f162..43a1ab1ac100 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/Frontend/FixItRewriter.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Basic/FileManager.h"
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp
index 9bc218e994fe..7d29b6d4219d 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/Frontend/FrontendActions.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/FrontendActions.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
@@ -16,9 +16,9 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/FixItRewriter.h"
-#include "clang/Rewrite/Rewriters.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/Frontend/HTMLPrint.cpp
index 3d190abffcf8..79e44470ada5 100644
--- a/lib/Rewrite/HTMLPrint.cpp
+++ b/lib/Rewrite/Frontend/HTMLPrint.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -19,8 +19,8 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/HTMLRewrite.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Rewrite/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 3dfc3b008987..9d1bec957d6d 100644
--- a/lib/Rewrite/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -57,10 +57,11 @@ private:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath);
+ StringRef RelativePath,
+ const Module *Imported);
void WriteLineInfo(const char *Filename, int Line,
SrcMgr::CharacteristicKind FileType,
StringRef EOL, StringRef Extra = StringRef());
@@ -152,10 +153,11 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
const Token &/*IncludeTok*/,
StringRef /*FileName*/,
bool /*IsAngled*/,
+ CharSourceRange /*FilenameRange*/,
const FileEntry * /*File*/,
- SourceLocation /*EndLoc*/,
StringRef /*SearchPath*/,
- StringRef /*RelativePath*/) {
+ StringRef /*RelativePath*/,
+ const Module * /*Imported*/) {
assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion "
"directive was found before the previous one was processed");
std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert(
diff --git a/lib/Rewrite/Frontend/Makefile b/lib/Rewrite/Frontend/Makefile
new file mode 100644
index 000000000000..ac97d4074ecb
--- /dev/null
+++ b/lib/Rewrite/Frontend/Makefile
@@ -0,0 +1,18 @@
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangRewriteFrontend
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Rewrite/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp
index 3fa0bdb74534..f399dd5d7ce9 100644
--- a/lib/Rewrite/RewriteMacros.cpp
+++ b/lib/Rewrite/Frontend/RewriteMacros.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index dcd003f50160..4b56b3720a3f 100644
--- a/lib/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ParentMap.h"
@@ -278,6 +278,9 @@ namespace {
// Syntactic Rewriting.
void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
+ void RewriteLineDirective(const Decl *D);
+ void ConvertSourceLocationToLineDirective(SourceLocation Loc,
+ std::string &LineString);
void RewriteForwardClassDecl(DeclGroupRef D);
void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
@@ -1602,6 +1605,19 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
return 0;
}
+void RewriteModernObjC::ConvertSourceLocationToLineDirective(
+ SourceLocation Loc,
+ std::string &LineString) {
+ if (Loc.isFileID()) {
+ LineString += "\n#line ";
+ PresumedLoc PLoc = SM->getPresumedLoc(Loc);
+ LineString += utostr(PLoc.getLine());
+ LineString += " \"";
+ LineString += Lexer::Stringify(PLoc.getFilename());
+ LineString += "\"\n";
+ }
+}
+
/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
/// statement to continue with its inner synthesized loop.
///
@@ -1664,7 +1680,10 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
StringRef elementName;
std::string elementTypeAsString;
std::string buf;
- buf = "\n{\n\t";
+ // line directive first.
+ SourceLocation ForEachLoc = S->getForLoc();
+ ConvertSourceLocationToLineDirective(ForEachLoc, buf);
+ buf += "{\n\t";
if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
// type elem;
NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());
@@ -1836,7 +1855,9 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
assert((*startBuf == '@') && "bogus @synchronized location");
std::string buf;
- buf = "{ id _rethrow = 0; id _sync_obj = ";
+ SourceLocation SynchLoc = S->getAtSynchronizedLoc();
+ ConvertSourceLocationToLineDirective(SynchLoc, buf);
+ buf += "{ id _rethrow = 0; id _sync_obj = ";
const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++;
@@ -1902,12 +1923,14 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt();
bool noCatch = S->getNumCatchStmts() == 0;
std::string buf;
+ SourceLocation TryLocation = S->getAtTryLoc();
+ ConvertSourceLocationToLineDirective(TryLocation, buf);
if (finalStmt) {
if (noCatch)
- buf = "{ id volatile _rethrow = 0;\n";
+ buf += "{ id volatile _rethrow = 0;\n";
else {
- buf = "{ id volatile _rethrow = 0;\ntry {\n";
+ buf += "{ id volatile _rethrow = 0;\ntry {\n";
}
}
// Get the start location and compute the semi location.
@@ -1934,13 +1957,15 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface();
if (IDecl) {
std::string Result;
+ ConvertSourceLocationToLineDirective(Catch->getLocStart(), Result);
+
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @catch location");
SourceLocation rParenLoc = Catch->getRParenLoc();
const char *rParenBuf = SM->getCharacterData(rParenLoc);
// _objc_exc_Foo *_e as argument to catch.
- Result = "catch (_objc_exc_"; Result += IDecl->getNameAsString();
+ Result += "catch (_objc_exc_"; Result += IDecl->getNameAsString();
Result += " *_"; Result += catchDecl->getNameAsString();
Result += ")";
ReplaceText(startLoc, rParenBuf-startBuf+1, Result);
@@ -1966,11 +1991,18 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
if (finalStmt) {
buf.clear();
- if (noCatch)
- buf = "catch (id e) {_rethrow = e;}\n";
- else
- buf = "}\ncatch (id e) {_rethrow = e;}\n";
-
+ SourceLocation FinallyLoc = finalStmt->getLocStart();
+
+ if (noCatch) {
+ ConvertSourceLocationToLineDirective(FinallyLoc, buf);
+ buf += "catch (id e) {_rethrow = e;}\n";
+ }
+ else {
+ buf += "}\n";
+ ConvertSourceLocationToLineDirective(FinallyLoc, buf);
+ buf += "catch (id e) {_rethrow = e;}\n";
+ }
+
SourceLocation startFinalLoc = finalStmt->getLocStart();
ReplaceText(startFinalLoc, 8, buf);
Stmt *body = finalStmt->getFinallyBody();
@@ -2070,7 +2102,7 @@ CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl(
const FunctionType *FT = msgSendType->getAs<FunctionType>();
CallExpr *Exp =
- new (Context) CallExpr(*Context, ICE, args, nargs,
+ new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs),
FT->getCallResultType(*Context),
VK_RValue, EndLoc);
return Exp;
@@ -2675,8 +2707,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -2718,7 +2749,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
for (unsigned i = 0; i < NumElements; i++)
InitExprs.push_back(Exp->getElement(i));
Expr *NSArrayCallExpr =
- new (Context) CallExpr(*Context, NSArrayDRE, &InitExprs[0], InitExprs.size(),
+ new (Context) CallExpr(*Context, NSArrayDRE, InitExprs,
NSArrayFType, VK_LValue, SourceLocation());
FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -2814,8 +2845,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -2865,7 +2895,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// (const id [])objects
Expr *NSValueCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(),
+ new (Context) CallExpr(*Context, NSDictDRE, ValueExprs,
NSDictFType, VK_LValue, SourceLocation());
FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -2887,7 +2917,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
DictLiteralValueME);
// (const id <NSCopying> [])keys
Expr *NSKeyCallExpr =
- new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(),
+ new (Context) CallExpr(*Context, NSDictDRE, KeyExprs,
NSDictFType, VK_LValue, SourceLocation());
MemberExpr *DictLiteralKeyME =
@@ -2989,8 +3019,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
ReplaceStmt(Exp, CE);
@@ -3078,6 +3107,34 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R,
return FD->getTypeSpecStartLoc();
}
+void RewriteModernObjC::RewriteLineDirective(const Decl *D) {
+
+ SourceLocation Location = D->getLocation();
+
+ if (Location.isFileID()) {
+ std::string LineString("\n#line ");
+ PresumedLoc PLoc = SM->getPresumedLoc(Location);
+ LineString += utostr(PLoc.getLine());
+ LineString += " \"";
+ LineString += Lexer::Stringify(PLoc.getFilename());
+ if (isa<ObjCMethodDecl>(D))
+ LineString += "\"";
+ else LineString += "\"\n";
+
+ Location = D->getLocStart();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isExternC() && !FD->isMain()) {
+ const DeclContext *DC = FD->getDeclContext();
+ if (const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(DC))
+ // if it is extern "C" {...}, return function decl's own location.
+ if (!LSD->getRBraceLoc().isValid())
+ Location = LSD->getExternLoc();
+ }
+ }
+ InsertText(Location, LineString);
+ }
+}
+
/// SynthMsgSendStretCallExpr - This routine translates message expression
/// into a call to objc_msgSend_stret() entry point. Tricky part is that
/// nil check on receiver must be performed before calling objc_msgSend_stret.
@@ -3140,7 +3197,14 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy());
str += " s;\n";
str += "};\n\n";
- SourceLocation FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef);
+ SourceLocation FunLocStart;
+ if (CurFunctionDef)
+ FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef);
+ else {
+ assert(CurMethodDef && "SynthMsgSendStretCallExpr - CurMethodDef is null");
+ FunLocStart = CurMethodDef->getLocStart();
+ }
+
InsertText(FunLocStart, str);
++stretCount;
@@ -3151,7 +3215,7 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
SC_None, false, false);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue,
SourceLocation());
- CallExpr *STCE = new (Context) CallExpr(*Context, DRE, &MsgExprs[0], MsgExprs.size(),
+ CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs,
castType, VK_LValue, SourceLocation());
FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(),
@@ -3260,8 +3324,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue,
SourceLocation());
// The code for super is a little tricky to prevent collision with
@@ -3280,8 +3343,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct __rw_objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3370,8 +3432,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
@@ -3389,8 +3450,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct __rw_objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3544,10 +3604,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
+ FT->getResultType(), VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
if (MsgSendStretFlavor) {
// We have the method which returns a struct/union. Must also generate
@@ -3578,7 +3636,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation());
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(),
+ false);
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3968,8 +4027,12 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
const FunctionType *AFT = CE->getFunctionType();
QualType RT = AFT->getResultType();
std::string StructRef = "struct " + Tag;
- std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
- funcName.str() + "_block_func_" + utostr(i);
+ SourceLocation BlockLoc = CE->getExprLoc();
+ std::string S;
+ ConvertSourceLocationToLineDirective(BlockLoc, S);
+
+ S += "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
+ funcName.str() + "_block_func_" + utostr(i);
BlockDecl *BD = CE->getBlockDecl();
@@ -4585,8 +4648,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
E = Exp->arg_end(); I != E; ++I) {
BlkExprs.push_back(*I);
}
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
- BlkExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs,
Exp->getType(), VK_RValue,
SourceLocation());
return CE;
@@ -4869,7 +4931,7 @@ void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
else if (*argListBegin == '<') {
buf += "/*";
buf += *argListBegin++;
- OrigLength++;;
+ OrigLength++;
while (*argListBegin != '>') {
buf += *argListBegin++;
OrigLength++;
@@ -5347,7 +5409,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
Context->IntTy, SourceLocation());
InitExprs.push_back(FlagExp);
}
- NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ NewRep = new (Context) CallExpr(*Context, DRE, InitExprs,
FType, VK_LValue, SourceLocation());
if (GlobalBlockExpr) {
@@ -5666,6 +5728,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
+ RewriteLineDirective(D);
CurFunctionDef = 0;
}
break;
@@ -5684,6 +5747,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
PropParentMap = 0;
}
InsertBlockLiteralsWithinMethod(MD);
+ RewriteLineDirective(D);
CurMethodDef = 0;
}
break;
@@ -5894,8 +5958,8 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "(const char *);\n";
Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n";
// @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter( struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit( struct objc_object *);\n";
+ 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 += "#ifndef __FASTENUMERATIONSTATE\n";
Preamble += "struct __objcFastEnumerationState {\n\t";
@@ -7476,7 +7540,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BinaryOperator *addExpr =
new (Context) BinaryOperator(castExpr, DRE, BO_Add,
Context->getPointerType(Context->CharTy),
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(), false);
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
SourceLocation(),
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index 37c17e63db94..a6dcc6b8d804 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/ASTConsumers.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ParentMap.h"
@@ -2059,7 +2059,7 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
const FunctionType *FT = msgSendType->getAs<FunctionType>();
CallExpr *Exp =
- new (Context) CallExpr(*Context, ICE, args, nargs,
+ new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs),
FT->getCallResultType(*Context),
VK_RValue, EndLoc);
return Exp;
@@ -2661,8 +2661,7 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *STCE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
SourceLocation());
return STCE;
@@ -2766,8 +2765,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue,
SourceLocation());
// The code for super is a little tricky to prevent collision with
@@ -2786,8 +2784,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -2876,8 +2873,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
false, superType, VK_LValue,
SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
+ SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs,
superType, VK_LValue, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
@@ -2895,8 +2891,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
- new (Context) InitListExpr(*Context, SourceLocation(),
- &InitExprs[0], InitExprs.size(),
+ new (Context) InitListExpr(*Context, SourceLocation(), InitExprs,
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
@@ -3050,8 +3045,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
- MsgExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
FT->getResultType(), VK_RValue,
EndLoc);
Stmt *ReplacingStmt = CE;
@@ -3084,7 +3078,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation());
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
- VK_RValue, OK_Ordinary, SourceLocation());
+ VK_RValue, OK_Ordinary, SourceLocation(),
+ false);
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3923,8 +3918,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
E = Exp->arg_end(); I != E; ++I) {
BlkExprs.push_back(*I);
}
- CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
- BlkExprs.size(),
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs,
Exp->getType(), VK_RValue,
SourceLocation());
return CE;
@@ -4190,7 +4184,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
else if (*argListBegin == '<') {
buf += "/*";
buf += *argListBegin++;
- OrigLength++;;
+ OrigLength++;
while (*argListBegin != '>') {
buf += *argListBegin++;
OrigLength++;
@@ -4651,7 +4645,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
Context->IntTy, SourceLocation());
InitExprs.push_back(FlagExp);
}
- NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ NewRep = new (Context) CallExpr(*Context, DRE, InitExprs,
FType, VK_LValue, SourceLocation());
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
Context->getPointerType(NewRep->getType()),
@@ -5119,8 +5113,8 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) {
Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
Preamble += "(struct objc_class *, struct objc_object *);\n";
// @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+ 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 += "#ifndef __FASTENUMERATIONSTATE\n";
Preamble += "struct __objcFastEnumerationState {\n\t";
diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/Frontend/RewriteTest.cpp
index 019e5e73120d..722c5e80b443 100644
--- a/lib/Rewrite/RewriteTest.cpp
+++ b/lib/Rewrite/Frontend/RewriteTest.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Rewrite/Rewriters.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/TokenRewriter.h"
+#include "clang/Rewrite/Core/TokenRewriter.h"
#include "llvm/Support/raw_ostream.h"
void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) {
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index 5fef9b2c0d38..0be84d406405 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -1,4 +1,4 @@
-##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
+##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -6,13 +6,9 @@
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
-#
-# This implements code transformation / rewriting facilities.
-#
-##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
-LIBRARYNAME := clangRewrite
+DIRS := Frontend
+PARALLEL_DIRS := Core
include $(CLANG_LEVEL)/Makefile
-
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 19a7d6f35c8f..801a1b1e0264 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/AnalysisContext.h"
@@ -36,10 +37,12 @@
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
@@ -182,13 +185,6 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
HasFakeEdge = true;
continue;
}
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
- if (AS->isMSAsm()) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
- }
if (isa<MSAsmStmt>(S)) {
// TODO: Verify this is correct.
HasFakeEdge = true;
@@ -506,7 +502,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
// Information used when building the diagnostic.
unsigned DiagKind;
- const char *Str;
+ StringRef Str;
SourceRange Range;
// FixIts to suppress the diagnosic by removing the dead condition.
@@ -822,6 +818,18 @@ namespace {
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
+ // Only perform this analysis when using C++11. There is no good workflow
+ // for this warning when not using C++11. There is no good way to silence
+ // the warning (no attribute is available) unless we are using C++11's support
+ // for generalized attributes. Once could use pragmas to silence the warning,
+ // but as a general solution that is gross and not in the spirit of this
+ // warning.
+ //
+ // NOTE: This an intermediate solution. There are on-going discussions on
+ // how to properly support this warning outside of C++11 with an annotation.
+ if (!AC.getASTContext().getLangOpts().CPlusPlus0x)
+ return;
+
FallthroughMapper FM(S);
FM.TraverseStmt(AC.getBody());
@@ -859,8 +867,21 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (S.getLangOpts().CPlusPlus0x) {
const Stmt *Term = B.getTerminator();
if (!(B.empty() && Term && isa<BreakStmt>(Term))) {
+ Preprocessor &PP = S.getPreprocessor();
+ TokenValue Tokens[] = {
+ tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+ StringRef AnnotationSpelling = "[[clang::fallthrough]]";
+ StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens);
+ if (!MacroName.empty())
+ AnnotationSpelling = MacroName;
+ SmallString<64> TextToInsert(AnnotationSpelling);
+ TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
- FixItHint::CreateInsertion(L, "[[clang::fallthrough]]; ");
+ AnnotationSpelling <<
+ FixItHint::CreateInsertion(L, TextToInsert);
}
}
S.Diag(L, diag::note_insert_break_fixit) <<
@@ -878,6 +899,199 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
namespace {
+typedef std::pair<const Stmt *,
+ sema::FunctionScopeInfo::WeakObjectUseMap::const_iterator>
+ StmtUsesPair;
+
+class StmtUseSorter {
+ const SourceManager &SM;
+
+public:
+ explicit StmtUseSorter(const SourceManager &SM) : SM(SM) { }
+
+ bool operator()(const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(),
+ RHS.first->getLocStart());
+ }
+};
+}
+
+static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
+ const Stmt *S) {
+ assert(S);
+
+ do {
+ switch (S->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ return true;
+ case Stmt::DoStmtClass: {
+ const Expr *Cond = cast<DoStmt>(S)->getCond();
+ llvm::APSInt Val;
+ if (!Cond->EvaluateAsInt(Val, Ctx))
+ return true;
+ return Val.getBoolValue();
+ }
+ default:
+ break;
+ }
+ } while ((S = PM.getParent(S)));
+
+ return false;
+}
+
+
+static void diagnoseRepeatedUseOfWeak(Sema &S,
+ const sema::FunctionScopeInfo *CurFn,
+ const Decl *D,
+ const ParentMap &PM) {
+ typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
+ typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
+ typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
+
+ ASTContext &Ctx = S.getASTContext();
+
+ const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();
+
+ // Extract all weak objects that are referenced more than once.
+ SmallVector<StmtUsesPair, 8> UsesByStmt;
+ for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
+ I != E; ++I) {
+ const WeakUseVector &Uses = I->second;
+
+ // Find the first read of the weak object.
+ WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ for ( ; UI != UE; ++UI) {
+ if (UI->isUnsafe())
+ break;
+ }
+
+ // If there were only writes to this object, don't warn.
+ if (UI == UE)
+ continue;
+
+ // If there was only one read, followed by any number of writes, and the
+ // read is not within a loop, don't warn. Additionally, don't warn in a
+ // loop if the base object is a local variable -- local variables are often
+ // changed in loops.
+ if (UI == Uses.begin()) {
+ WeakUseVector::const_iterator UI2 = UI;
+ for (++UI2; UI2 != UE; ++UI2)
+ if (UI2->isUnsafe())
+ break;
+
+ if (UI2 == UE) {
+ if (!isInLoop(Ctx, PM, UI->getUseExpr()))
+ continue;
+
+ const WeakObjectProfileTy &Profile = I->first;
+ if (!Profile.isExactProfile())
+ continue;
+
+ const NamedDecl *Base = Profile.getBase();
+ if (!Base)
+ Base = Profile.getProperty();
+ assert(Base && "A profile always has a base or property.");
+
+ if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base))
+ if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base))
+ continue;
+ }
+ }
+
+ UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
+ }
+
+ if (UsesByStmt.empty())
+ return;
+
+ // Sort by first use so that we emit the warnings in a deterministic order.
+ std::sort(UsesByStmt.begin(), UsesByStmt.end(),
+ StmtUseSorter(S.getSourceManager()));
+
+ // Classify the current code body for better warning text.
+ // This enum should stay in sync with the cases in
+ // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
+ // FIXME: Should we use a common classification enum and the same set of
+ // possibilities all throughout Sema?
+ enum {
+ Function,
+ Method,
+ Block,
+ Lambda
+ } FunctionKind;
+
+ if (isa<sema::BlockScopeInfo>(CurFn))
+ FunctionKind = Block;
+ else if (isa<sema::LambdaScopeInfo>(CurFn))
+ FunctionKind = Lambda;
+ else if (isa<ObjCMethodDecl>(D))
+ FunctionKind = Method;
+ else
+ FunctionKind = Function;
+
+ // Iterate through the sorted problems and emit warnings for each.
+ for (SmallVectorImpl<StmtUsesPair>::const_iterator I = UsesByStmt.begin(),
+ E = UsesByStmt.end();
+ I != E; ++I) {
+ const Stmt *FirstRead = I->first;
+ const WeakObjectProfileTy &Key = I->second->first;
+ const WeakUseVector &Uses = I->second->second;
+
+ // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy
+ // may not contain enough information to determine that these are different
+ // properties. We can only be 100% sure of a repeated use in certain cases,
+ // and we adjust the diagnostic kind accordingly so that the less certain
+ // case can be turned off if it is too noisy.
+ unsigned DiagKind;
+ if (Key.isExactProfile())
+ DiagKind = diag::warn_arc_repeated_use_of_weak;
+ else
+ DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
+
+ // Classify the weak object being accessed for better warning text.
+ // This enum should stay in sync with the cases in
+ // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
+ enum {
+ Variable,
+ Property,
+ ImplicitProperty,
+ Ivar
+ } ObjectKind;
+
+ const NamedDecl *D = Key.getProperty();
+ if (isa<VarDecl>(D))
+ ObjectKind = Variable;
+ else if (isa<ObjCPropertyDecl>(D))
+ ObjectKind = Property;
+ else if (isa<ObjCMethodDecl>(D))
+ ObjectKind = ImplicitProperty;
+ else if (isa<ObjCIvarDecl>(D))
+ ObjectKind = Ivar;
+ else
+ llvm_unreachable("Unexpected weak object kind!");
+
+ // Show the first time the object was read.
+ S.Diag(FirstRead->getLocStart(), DiagKind)
+ << ObjectKind << D << FunctionKind
+ << FirstRead->getSourceRange();
+
+ // Print all the other accesses as notes.
+ for (WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ UI != UE; ++UI) {
+ if (UI->getUseExpr() == FirstRead)
+ continue;
+ S.Diag(UI->getUseExpr()->getLocStart(),
+ diag::note_arc_weak_also_accessed_here)
+ << UI->getUseExpr()->getSourceRange();
+ }
+ }
+}
+
+
+namespace {
struct SLocSort {
bool operator()(const UninitUse &a, const UninitUse &b) {
// Prefer a more confident report over a less confident one.
@@ -1091,27 +1305,47 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
diag::warn_variable_requires_any_lock:
diag::warn_var_deref_requires_any_lock;
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getName() << getLockKindFromAccessKind(AK));
+ << D->getNameAsString() << getLockKindFromAccessKind(AK));
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
- Name LockName, LockKind LK, SourceLocation Loc) {
+ Name LockName, LockKind LK, SourceLocation Loc,
+ Name *PossibleMatch) {
unsigned DiagID = 0;
- switch (POK) {
- case POK_VarAccess:
- DiagID = diag::warn_variable_requires_lock;
- break;
- case POK_VarDereference:
- DiagID = diag::warn_var_deref_requires_lock;
- break;
- case POK_FunctionCall:
- DiagID = diag::warn_fun_requires_lock;
- break;
+ if (PossibleMatch) {
+ switch (POK) {
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock_precise;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock_precise;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock_precise;
+ break;
+ }
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getNameAsString() << LockName << LK);
+ PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
+ << *PossibleMatch);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
+ } else {
+ switch (POK) {
+ case POK_VarAccess:
+ DiagID = diag::warn_variable_requires_lock;
+ break;
+ case POK_VarDereference:
+ DiagID = diag::warn_var_deref_requires_lock;
+ break;
+ case POK_FunctionCall:
+ DiagID = diag::warn_fun_requires_lock;
+ break;
+ }
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getNameAsString() << LockName << LK);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getName() << LockName << LK);
- Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
@@ -1206,7 +1440,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
AC.getCFGBuildOptions().AddEHEdges = false;
AC.getCFGBuildOptions().AddInitializers = true;
AC.getCFGBuildOptions().AddImplicitDtors = true;
-
+ AC.getCFGBuildOptions().AddTemporaryDtors = true;
+
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
// FIXME: This isn't the right factoring. This is here for initial
@@ -1350,6 +1585,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
+ if (S.getLangOpts().ObjCARCWeak &&
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ D->getLocStart()) != DiagnosticsEngine::Ignored)
+ diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 46dfa05adec1..7cfe3ae8462c 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -13,7 +13,9 @@ add_clang_library(clangSema
DelayedDiagnostic.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
+ MultiplexExternalSemaSource.cpp
Scope.cpp
+ ScopeInfo.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
@@ -39,6 +41,7 @@ add_clang_library(clangSema
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp
+ SemaStmtAsm.cpp
SemaStmtAttr.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index a8357255343d..0a236018bdfd 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -193,11 +193,10 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
CXAvailabilityKind Availability,
const char **Annotations,
unsigned NumAnnotations,
- CXCursorKind ParentKind,
StringRef ParentName,
const char *BriefComment)
: NumChunks(NumChunks), NumAnnotations(NumAnnotations),
- Priority(Priority), Availability(Availability), ParentKind(ParentKind),
+ Priority(Priority), Availability(Availability),
ParentName(ParentName), BriefComment(BriefComment)
{
assert(NumChunks <= 0xffff);
@@ -339,7 +338,7 @@ CodeCompletionString *CodeCompletionBuilder::TakeString() {
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
Annotations.data(), Annotations.size(),
- ParentKind, ParentName, BriefComment);
+ ParentName, BriefComment);
Chunks.clear();
return Result;
}
@@ -380,7 +379,6 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (DC->isTranslationUnit()) {
- ParentKind = CXCursor_TranslationUnit;
return;
}
@@ -391,7 +389,6 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (!ND)
return;
- ParentKind = getCursorKindForDecl(ND);
ParentName = getCodeCompletionTUInfo().getParentName(DC);
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index d12ca7839095..b3066eb08013 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -144,11 +144,13 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
-DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
bool isAmbiguous,
- SourceLocation EllipsisLoc,
+ SourceLocation LParenLoc,
ParamInfo *ArgInfo,
unsigned NumArgs,
+ SourceLocation EllipsisLoc,
+ SourceLocation RParenLoc,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
@@ -173,9 +175,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.EndLoc = LocalRangeEnd;
I.Fun.AttrList = 0;
I.Fun.hasPrototype = hasProto;
- I.Fun.isVariadic = isVariadic;
+ I.Fun.isVariadic = EllipsisLoc.isValid();
I.Fun.isAmbiguous = isAmbiguous;
+ I.Fun.LParenLoc = LParenLoc.getRawEncoding();
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ I.Fun.RParenLoc = RParenLoc.getRawEncoding();
I.Fun.DeleteArgInfo = false;
I.Fun.TypeQuals = TypeQuals;
I.Fun.NumArgs = NumArgs;
@@ -270,6 +274,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_int:
case TST_int128:
case TST_struct:
+ case TST_interface:
case TST_union:
case TST_unknown_anytype:
case TST_unspecified:
@@ -325,10 +330,14 @@ unsigned DeclSpec::getParsedSpecifiers() const {
template <class T> static bool BadSpecifier(T TNew, T TPrev,
const char *&PrevSpec,
- unsigned &DiagID) {
+ unsigned &DiagID,
+ bool IsExtension = true) {
PrevSpec = DeclSpec::getSpecifierName(TPrev);
- DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec
- : diag::err_invalid_decl_spec_combination);
+ if (TNew != TPrev)
+ DiagID = diag::err_invalid_decl_spec_combination;
+ else
+ DiagID = IsExtension ? diag::ext_duplicate_declspec :
+ diag::warn_duplicate_declspec;
return true;
}
@@ -396,6 +405,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_class: return "class";
case DeclSpec::TST_union: return "union";
case DeclSpec::TST_struct: return "struct";
+ case DeclSpec::TST_interface: return "__interface";
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
@@ -670,12 +680,16 @@ bool DeclSpec::SetTypeSpecError() {
}
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID, const LangOptions &Lang,
- bool IsTypeSpec) {
- // Duplicates are permitted in C99, and are permitted in C++11 unless the
- // cv-qualifier appears as a type-specifier.
- if ((TypeQualifiers & T) && !Lang.C99 && (!Lang.CPlusPlus0x || IsTypeSpec))
- return BadSpecifier(T, T, PrevSpec, DiagID);
+ 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.
+ if (TypeQualifiers & T) {
+ bool IsExtension = true;
+ if (Lang.C99)
+ IsExtension = false;
+ return BadSpecifier(T, T, PrevSpec, DiagID, IsExtension);
+ }
TypeQualifiers |= T;
switch (T) {
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 876f9d7a9545..310043288554 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -22,6 +22,7 @@ using namespace sema;
DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
StringRef Msg) {
DelayedDiagnostic DD;
DD.Kind = Deprecation;
@@ -29,6 +30,7 @@ DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
DD.Loc = Loc;
DD.DeprecationData.Decl = D;
DD.DeprecationData.UnknownObjCClass = UnknownObjCClass;
+ DD.DeprecationData.ObjCProperty = ObjCProperty;
char *MessageData = 0;
if (Msg.size()) {
MessageData = new char [Msg.size()];
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 4d62cab16765..00939151c673 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -135,8 +135,16 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
// of the controlled statement.
//
assert(S->getParent() && "No TUScope?");
- if (S->getParent()->getFlags() & Scope::ControlScope)
+ if (S->getFlags() & Scope::FnTryScope)
return S->getParent()->isDeclScope(D);
+ if (S->getParent()->getFlags() & Scope::ControlScope) {
+ if (S->getParent()->getFlags() & Scope::FnCatchScope) {
+ S = S->getParent();
+ if (S->isDeclScope(D))
+ return true;
+ }
+ return S->getParent()->isDeclScope(D);
+ }
}
return false;
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index ab786c65aab9..e2ec1ccebdcf 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -123,7 +123,7 @@ typedef std::pair<unsigned,unsigned> ScopePair;
/// diagnostic that should be emitted if control goes over it. If not, return 0.
static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- unsigned InDiag = 0, OutDiag = 0;
+ unsigned InDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
@@ -164,43 +164,53 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
// where it is in scope is ill-formed unless the variable has
// POD type and is declared without an initializer.
- if (const Expr *init = VD->getInit()) {
- // We actually give variables of record type (or array thereof)
- // an initializer even if that initializer only calls a trivial
- // ctor. Detect that case.
- // FIXME: With generalized initializer lists, this may
- // classify "X x{};" as having no initializer.
- unsigned inDiagToUse = diag::note_protected_by_variable_init;
-
- const CXXRecordDecl *record = 0;
-
- if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
- const CXXConstructorDecl *ctor = cce->getConstructor();
- record = ctor->getParent();
-
- if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
- if (!record->hasTrivialDestructor())
- inDiagToUse = diag::note_protected_by_variable_nontriv_destructor;
- else if (!record->isPOD())
- inDiagToUse = diag::note_protected_by_variable_non_pod;
- else
- inDiagToUse = 0;
- }
- } else if (VD->getType()->isArrayType()) {
- record = VD->getType()->getBaseElementTypeUnsafe()
- ->getAsCXXRecordDecl();
+ const Expr *Init = VD->getInit();
+ if (!Init)
+ return ScopePair(InDiag, 0);
+
+ const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init);
+ if (EWC)
+ Init = EWC->getSubExpr();
+
+ const MaterializeTemporaryExpr *M = NULL;
+ Init = Init->findMaterializedTemporary(M);
+
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ Init = Init->skipRValueSubobjectAdjustments(Adjustments);
+
+ QualType QT = Init->getType();
+ if (QT.isNull())
+ return ScopePair(diag::note_protected_by_variable_init, 0);
+
+ const Type *T = QT.getTypePtr();
+ if (T->isArrayType())
+ T = T->getBaseElementTypeUnsafe();
+
+ const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+ if (!Record)
+ return ScopePair(diag::note_protected_by_variable_init, 0);
+
+ // If we need to call a non trivial destructor for this variable,
+ // record an out diagnostic.
+ unsigned OutDiag = 0;
+ if (!Init->isGLValue() && !Record->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
+
+ if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
+ const CXXConstructorDecl *ctor = cce->getConstructor();
+ if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+ if (OutDiag)
+ InDiag = diag::note_protected_by_variable_nontriv_destructor;
+ else if (!Record->isPOD())
+ InDiag = diag::note_protected_by_variable_non_pod;
+ return ScopePair(InDiag, OutDiag);
}
-
- if (inDiagToUse)
- InDiag = inDiagToUse;
-
- // Also object to indirect jumps which leave scopes with dtors.
- if (record && !record->hasTrivialDestructor())
- OutDiag = diag::note_exits_dtor;
}
+
+ return ScopePair(diag::note_protected_by_variable_init, OutDiag);
}
-
- return ScopePair(InDiag, OutDiag);
+
+ return ScopePair(InDiag, 0);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
@@ -322,6 +332,29 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
Jumps.push_back(S);
break;
+ case Stmt::CXXTryStmtClass: {
+ CXXTryStmt *TS = cast<CXXTryStmt>(S);
+ unsigned newParentScope;
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_try,
+ diag::note_exits_cxx_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
+
+ // Jump from the catch into the try is not allowed either.
+ for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
+ CXXCatchStmt *CS = TS->getHandler(I);
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_catch,
+ diag::note_exits_cxx_catch,
+ CS->getSourceRange().getBegin()));
+ BuildScopeInformation(CS->getHandlerBlock(),
+ (newParentScope = Scopes.size()-1));
+ }
+ return;
+ }
+
default:
break;
}
@@ -418,30 +451,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
continue;
}
- // Disallow jumps into any part of a C++ try statement. This is pretty
- // much the same as for Obj-C.
- if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) {
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_cxx_try,
- diag::note_exits_cxx_try,
- TS->getSourceRange().getBegin()));
- if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
-
- // Jump from the catch into the try is not allowed either.
- for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
- CXXCatchStmt *CS = TS->getHandler(I);
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_cxx_catch,
- diag::note_exits_cxx_catch,
- CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(),
- (newParentScope = Scopes.size()-1));
- }
-
- continue;
- }
-
// Disallow jumps into the protected statement of an @autoreleasepool.
if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
// Recursively walk the AST for the @autoreleasepool part, protected by a new
@@ -453,14 +462,19 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1));
continue;
}
-
- if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) {
- const BlockDecl *BDecl = BE->getBlockDecl();
+
+ // Disallow jumps past full-expressions that use blocks with
+ // non-trivial cleanups of their captures. This is theoretically
+ // implementable but a lot of work which we haven't felt up to doing.
+ if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) {
+ for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
+ const BlockDecl *BDecl = EWC->getObject(i);
for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(),
ce = BDecl->capture_end(); ci != ce; ++ci) {
VarDecl *variable = ci->getVariable();
BuildScopeInformation(variable, BDecl, ParentScope);
}
+ }
}
// Recursively walk the AST.
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
new file mode 100644
index 000000000000..f930fb348a25
--- /dev/null
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -0,0 +1,271 @@
+//===--- MultiplexExternalSemaSource.cpp ---------------------------------===//
+//
+// 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 event dispatching to the subscribed clients.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/Sema/Lookup.h"
+
+using namespace clang;
+
+///\brief Constructs a new multiplexing external sema source and appends the
+/// given element to it.
+///
+///\param[in] source - An ExternalSemaSource.
+///
+MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
+ ExternalSemaSource &s2){
+ Sources.push_back(&s1);
+ Sources.push_back(&s2);
+}
+
+// pin the vtable here.
+MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {}
+
+///\brief Appends new source to the source list.
+///
+///\param[in] source - An ExternalSemaSource.
+///
+void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) {
+ Sources.push_back(&source);
+}
+
+//===----------------------------------------------------------------------===//
+// ExternalASTSource.
+//===----------------------------------------------------------------------===//
+
+Decl *MultiplexExternalSemaSource::GetExternalDecl(uint32_t ID) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Decl *Result = Sources[i]->GetExternalDecl(ID))
+ return Result;
+ return 0;
+}
+
+Selector MultiplexExternalSemaSource::GetExternalSelector(uint32_t ID) {
+ Selector Sel;
+ for(size_t i = 0; i < Sources.size(); ++i) {
+ Sel = Sources[i]->GetExternalSelector(ID);
+ if (!Sel.isNull())
+ return Sel;
+ }
+ return Sel;
+}
+
+uint32_t MultiplexExternalSemaSource::GetNumExternalSelectors() {
+ uint32_t total = 0;
+ for(size_t i = 0; i < Sources.size(); ++i)
+ total += Sources[i]->GetNumExternalSelectors();
+ return total;
+}
+
+Stmt *MultiplexExternalSemaSource::GetExternalDeclStmt(uint64_t Offset) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
+ return Result;
+ return 0;
+}
+
+CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
+ uint64_t Offset){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (CXXBaseSpecifier *R = Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
+ return R;
+ return 0;
+}
+
+DeclContextLookupResult MultiplexExternalSemaSource::
+FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
+ StoredDeclsList DeclsFound;
+ DeclContextLookupResult lookup;
+ for(size_t i = 0; i < Sources.size(); ++i) {
+ lookup = Sources[i]->FindExternalVisibleDeclsByName(DC, Name);
+ while(lookup.first != lookup.second) {
+ if (!DeclsFound.HandleRedeclaration(*lookup.first))
+ DeclsFound.AddSubsequentDecl(*lookup.first);
+ lookup.first++;
+ }
+ }
+ return DeclsFound.getLookupResult();
+}
+
+void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->completeVisibleDeclsMap(DC);
+}
+
+ExternalLoadResult MultiplexExternalSemaSource::
+FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl*> &Result) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ // FIXME: The semantics of the return result is unclear to me...
+ Sources[i]->FindExternalLexicalDecls(DC, isKindWeWant, Result);
+
+ return ELR_Success;
+}
+
+void MultiplexExternalSemaSource::FindFileRegionDecls(FileID File,
+ unsigned Offset,
+ unsigned Length,
+ SmallVectorImpl<Decl *> &Decls){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
+}
+
+void MultiplexExternalSemaSource::CompleteType(TagDecl *Tag) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Tag);
+}
+
+void MultiplexExternalSemaSource::CompleteType(ObjCInterfaceDecl *Class) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Class);
+}
+
+void MultiplexExternalSemaSource::ReadComments() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadComments();
+}
+
+void MultiplexExternalSemaSource::StartedDeserializing() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartedDeserializing();
+}
+
+void MultiplexExternalSemaSource::FinishedDeserializing() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FinishedDeserializing();
+}
+
+void MultiplexExternalSemaSource::StartTranslationUnit(ASTConsumer *Consumer) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartTranslationUnit(Consumer);
+}
+
+void MultiplexExternalSemaSource::PrintStats() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->PrintStats();
+}
+
+bool MultiplexExternalSemaSource::layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets))
+ return true;
+ return false;
+}
+
+void MultiplexExternalSemaSource::
+getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->getMemoryBufferSizes(sizes);
+
+}
+
+//===----------------------------------------------------------------------===//
+// ExternalSemaSource.
+//===----------------------------------------------------------------------===//
+
+
+void MultiplexExternalSemaSource::InitializeSema(Sema &S) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->InitializeSema(S);
+}
+
+void MultiplexExternalSemaSource::ForgetSema() {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ForgetSema();
+}
+
+void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadMethodPool(Sel);
+}
+
+void MultiplexExternalSemaSource::ReadKnownNamespaces(
+ SmallVectorImpl<NamespaceDecl*> &Namespaces){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadKnownNamespaces(Namespaces);
+}
+
+bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->LookupUnqualified(R, S);
+
+ return !R.empty();
+}
+
+void MultiplexExternalSemaSource::ReadTentativeDefinitions(
+ SmallVectorImpl<VarDecl*> &TentativeDefs) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadTentativeDefinitions(TentativeDefs);
+}
+
+void MultiplexExternalSemaSource::ReadUnusedFileScopedDecls(
+ SmallVectorImpl<const DeclaratorDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUnusedFileScopedDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadDelegatingConstructors(
+ SmallVectorImpl<CXXConstructorDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadDelegatingConstructors(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadExtVectorDecls(
+ SmallVectorImpl<TypedefNameDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadExtVectorDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadDynamicClasses(
+ SmallVectorImpl<CXXRecordDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadDynamicClasses(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls(
+ SmallVectorImpl<NamedDecl*> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadLocallyScopedExternalDecls(Decls);
+}
+
+void MultiplexExternalSemaSource::ReadReferencedSelectors(
+ SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadReferencedSelectors(Sels);
+}
+
+void MultiplexExternalSemaSource::ReadWeakUndeclaredIdentifiers(
+ SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadWeakUndeclaredIdentifiers(WI);
+}
+
+void MultiplexExternalSemaSource::ReadUsedVTables(
+ SmallVectorImpl<ExternalVTableUse> &VTables) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUsedVTables(VTables);
+}
+
+void MultiplexExternalSemaSource::ReadPendingInstantiations(
+ SmallVectorImpl<std::pair<ValueDecl*,
+ SourceLocation> > &Pending) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadPendingInstantiations(Pending);
+}
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
new file mode 100644
index 000000000000..4d29a34a73ef
--- /dev/null
+++ b/lib/Sema/ScopeInfo.cpp
@@ -0,0 +1,189 @@
+//===--- ScopeInfo.cpp - Information about a semantic context -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements FunctionScopeInfo and its subclasses, which contain
+// information about a single function, block, lambda, or method body.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+
+using namespace clang;
+using namespace sema;
+
+void FunctionScopeInfo::Clear() {
+ HasBranchProtectedScope = false;
+ HasBranchIntoScope = false;
+ HasIndirectGoto = false;
+
+ SwitchStack.clear();
+ Returns.clear();
+ ErrorTrap.reset();
+ PossiblyUnreachableDiags.clear();
+ WeakObjectUses.clear();
+}
+
+static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
+ if (PropE->isExplicitProperty())
+ return PropE->getExplicitProperty();
+
+ return PropE->getImplicitPropertyGetter();
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::BaseInfoTy
+FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
+ E = E->IgnoreParenCasts();
+
+ const NamedDecl *D = 0;
+ bool IsExact = false;
+
+ switch (E->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ D = cast<DeclRefExpr>(E)->getDecl();
+ IsExact = isa<VarDecl>(D);
+ break;
+ case Stmt::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ D = ME->getMemberDecl();
+ IsExact = isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts());
+ break;
+ }
+ case Stmt::ObjCIvarRefExprClass: {
+ const ObjCIvarRefExpr *IE = cast<ObjCIvarRefExpr>(E);
+ D = IE->getDecl();
+ IsExact = IE->getBase()->isObjCSelfExpr();
+ break;
+ }
+ case Stmt::PseudoObjectExprClass: {
+ const PseudoObjectExpr *POE = cast<PseudoObjectExpr>(E);
+ const ObjCPropertyRefExpr *BaseProp =
+ dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
+ if (BaseProp) {
+ D = getBestPropertyDecl(BaseProp);
+
+ const Expr *DoubleBase = BaseProp->getBase();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase))
+ DoubleBase = OVE->getSourceExpr();
+
+ IsExact = DoubleBase->isObjCSelfExpr();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return BaseInfoTy(D, IsExact);
+}
+
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const ObjCPropertyRefExpr *PropE)
+ : Base(0, true), Property(getBestPropertyDecl(PropE)) {
+
+ if (PropE->isObjectReceiver()) {
+ const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(PropE->getBase());
+ const Expr *E = OVE->getSourceExpr();
+ Base = getBaseInfo(E);
+ } else if (PropE->isClassReceiver()) {
+ Base.setPointer(PropE->getClassReceiver());
+ } else {
+ assert(PropE->isSuperReceiver());
+ }
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(const Expr *BaseE,
+ const ObjCPropertyDecl *Prop)
+ : Base(0, true), Property(Prop) {
+ if (BaseE)
+ Base = getBaseInfo(BaseE);
+ // else, this is a message accessing a property on super.
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const DeclRefExpr *DRE)
+ : Base(0, true), Property(DRE->getDecl()) {
+ assert(isa<VarDecl>(Property));
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const ObjCIvarRefExpr *IvarE)
+ : Base(getBaseInfo(IvarE->getBase())), Property(IvarE->getDecl()) {
+}
+
+void FunctionScopeInfo::recordUseOfWeak(const ObjCMessageExpr *Msg,
+ const ObjCPropertyDecl *Prop) {
+ assert(Msg && Prop);
+ WeakUseVector &Uses =
+ WeakObjectUses[WeakObjectProfileTy(Msg->getInstanceReceiver(), Prop)];
+ Uses.push_back(WeakUseTy(Msg, Msg->getNumArgs() == 0));
+}
+
+void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
+ E = E->IgnoreParenCasts();
+
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+ markSafeWeakUse(POE->getSyntacticForm());
+ return;
+ }
+
+ if (const ConditionalOperator *Cond = dyn_cast<ConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getTrueExpr());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ if (const BinaryConditionalOperator *Cond =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getCommon());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ // Has this weak object been seen before?
+ FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
+ if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr));
+ else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE));
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
+ else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
+ Uses = WeakObjectUses.end();
+ if (const ObjCMethodDecl *MD = MsgE->getMethodDecl()) {
+ if (const ObjCPropertyDecl *Prop = MD->findPropertyDecl()) {
+ Uses =
+ WeakObjectUses.find(WeakObjectProfileTy(MsgE->getInstanceReceiver(),
+ Prop));
+ }
+ }
+ }
+ else
+ return;
+
+ if (Uses == WeakObjectUses.end())
+ return;
+
+ // Has there been a read from the object using this Expr?
+ FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse =
+ std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true));
+ if (ThisUse == Uses->second.rend())
+ return;
+
+ ThisUse->markSafe();
+}
+
+FunctionScopeInfo::~FunctionScopeInfo() { }
+BlockScopeInfo::~BlockScopeInfo() { }
+LambdaScopeInfo::~LambdaScopeInfo() { }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7f79f0c6d98a..13a33b785b43 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -22,6 +22,7 @@
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
@@ -43,22 +44,6 @@
using namespace clang;
using namespace sema;
-FunctionScopeInfo::~FunctionScopeInfo() { }
-
-void FunctionScopeInfo::Clear() {
- HasBranchProtectedScope = false;
- HasBranchIntoScope = false;
- HasIndirectGoto = false;
-
- SwitchStack.clear();
- Returns.clear();
- ErrorTrap.reset();
- PossiblyUnreachableDiags.clear();
-}
-
-BlockScopeInfo::~BlockScopeInfo() { }
-LambdaScopeInfo::~LambdaScopeInfo() { }
-
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -84,12 +69,14 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), FPFeatures(pp.getLangOpts()),
+ : TheTargetAttributesSema(0), ExternalSource(0),
+ isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
+ CollectStats(false), CodeCompleter(CodeCompleter),
CurContext(0), OriginalLexicalContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
NSNumberDecl(0),
@@ -203,6 +190,10 @@ Sema::~Sema() {
if (ExternalSemaSource *ExternalSema
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->ForgetSema();
+
+ // If Sema's ExternalSource is the multiplexer - we own it.
+ if (isMultiplexExternalSource)
+ delete ExternalSource;
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -234,6 +225,27 @@ ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
+///\brief Registers an external source. If an external source already exists,
+/// creates a multiplex external source and appends to it.
+///
+///\param[in] E - A non-null external sema source.
+///
+void Sema::addExternalSource(ExternalSemaSource *E) {
+ assert(E && "Cannot use with NULL ptr");
+
+ if (!ExternalSource) {
+ ExternalSource = E;
+ return;
+ }
+
+ if (isMultiplexExternalSource)
+ static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E);
+ else {
+ ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E);
+ isMultiplexExternalSource = true;
+ }
+}
+
/// \brief Print out statistics about the semantic analysis.
void Sema::PrintStats() const {
llvm::errs() << "\n*** Semantic Analysis Stats:\n";
@@ -507,6 +519,11 @@ void Sema::ActOnEndOfTranslationUnit() {
assert(DelayedDiagnostics.getCurrentPool() == NULL
&& "reached end of translation unit with a pool attached?");
+ // If code completion is enabled, don't perform any end-of-translation-unit
+ // work.
+ if (PP.isCodeCompletionEnabled())
+ return;
+
// Only complete translation units define vtables and perform implicit
// instantiations.
if (TUKind == TU_Complete) {
@@ -648,6 +665,8 @@ void Sema::ActOnEndOfTranslationUnit() {
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
+ CheckCompleteVariableDeclaration(VD);
+
// Notify the consumer that we've completed a tentative definition.
if (!VD->isInvalidDecl())
Consumer.CompleteTentativeDefinition(VD);
@@ -1021,6 +1040,9 @@ LambdaScopeInfo *Sema::getCurLambda() {
}
void Sema::ActOnComment(SourceRange Comment) {
+ if (!LangOpts.RetainCommentsFromSystemHeaders &&
+ SourceMgr.isInSystemHeader(Comment.getBegin()))
+ return;
RawComment RC(SourceMgr, Comment);
if (RC.isAlmostTrailingComment()) {
SourceRange MagicMarkerRange(Comment.getBegin(),
@@ -1165,8 +1187,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
// FIXME: Magic number for max shown overloads stolen from
// OverloadCandidateSet::NoteCandidates.
- if (ShownOverloads >= 4 &&
- S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) {
+ if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) {
++SuppressedOverloads;
continue;
}
@@ -1237,8 +1258,7 @@ 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,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc.getLocWithOffset(1));
+ MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1));
return true;
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 3481171c7735..58b1a51ae573 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -97,14 +97,19 @@ struct EffectiveContext {
// functions (which can gain privileges through friendship), but we
// take that as an oversight.
while (true) {
+ // We want to add canonical declarations to the EC lists for
+ // simplicity of checking, but we need to walk up through the
+ // actual current DC chain. Otherwise, something like a local
+ // extern or friend which happens to be the canonical
+ // declaration will really mess us up.
+
if (isa<CXXRecordDecl>(DC)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
- Records.push_back(Record);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ Records.push_back(Record->getCanonicalDecl());
DC = Record->getDeclContext();
} else if (isa<FunctionDecl>(DC)) {
- FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
- Functions.push_back(Function);
-
+ FunctionDecl *Function = cast<FunctionDecl>(DC);
+ Functions.push_back(Function->getCanonicalDecl());
if (Function->getFriendObjectKind())
DC = Function->getLexicalDeclContext();
else
@@ -1791,7 +1796,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
/// specifiers into account, but no member access expressions and such.
///
/// \param Decl the declaration to check if it can be accessed
-/// \param Class the class/context from which to start the search
+/// \param Ctx the class/context from which to start the search
/// \return true if the Decl is accessible from the Class, false otherwise.
bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index e935fc735b23..f1154c1a8aeb 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -136,23 +136,12 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
}
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
- SourceLocation PragmaLoc,
- SourceLocation KindLoc) {
+ SourceLocation PragmaLoc) {
if (PackContext == 0)
PackContext = new PragmaPackStack();
PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
- // Reset just pops the top of the stack, or resets the current alignment to
- // default.
- if (Kind == Sema::POAK_Reset) {
- if (!Context->pop(0, /*IsReset=*/true)) {
- Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
- << "stack empty";
- }
- return;
- }
-
switch (Kind) {
// For all targets we support native and natural are the same.
//
@@ -181,9 +170,13 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
break;
- default:
- Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
- << KindLoc;
+ case POAK_Reset:
+ // Reset just pops the top of the stack, or resets the current alignment to
+ // default.
+ if (!Context->pop(0, /*IsReset=*/true)) {
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ }
break;
}
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 0de9dd5f64c9..15bfd1ce6294 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -520,7 +520,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
<< Name << CorrectedQuotedStr
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index d8d51e77ee24..bf25c6178541 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -227,7 +227,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckExtraCXXDefaultArguments(D);
}
- return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E),
+ return BuildCXXNamedCast(OpLoc, Kind, TInfo, E,
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
SourceRange(LParenLoc, RParenLoc));
}
@@ -1331,8 +1331,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
- ExprResult Result
- = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExprRaw, 1));
+ ExprResult Result = InitSeq.Perform(Self, Entity, InitKind, SrcExprRaw);
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
@@ -1343,7 +1342,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
else
Kind = CK_NoOp;
- SrcExpr = move(Result);
+ SrcExpr = Result;
return TC_Success;
}
@@ -1492,6 +1491,22 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
}
}
+static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
+ const Expr *SrcExpr, QualType DestType,
+ Sema &Self) {
+ QualType SrcType = SrcExpr->getType();
+
+ // Not warning on reinterpret_cast, boolean, constant expressions, etc
+ // are not explicit design choices, but consistent with GCC's behavior.
+ // Feel free to modify them if you've reason/evidence for an alternative.
+ if (CStyle && SrcType->isIntegralType(Self.Context)
+ && !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;
+}
+
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
@@ -1513,7 +1528,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
SingleFunctionExpr,
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
) && SingleFunctionExpr.isUsable()) {
- SrcExpr = move(SingleFunctionExpr);
+ SrcExpr = SingleFunctionExpr;
SrcType = SrcExpr.get()->getType();
} else {
return TC_NotApplicable;
@@ -1690,6 +1705,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
+ checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
+ Self);
// C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
// converted to a pointer.
// C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not
@@ -1903,6 +1920,43 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
SrcExpr = ExprError();
}
+/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a
+/// non-matching type. Such as enum function call to int, int call to
+/// pointer; etc. Cast to 'void' is an exception.
+static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ if (Self.Diags.getDiagnosticLevel(diag::warn_bad_function_cast,
+ SrcExpr.get()->getExprLoc())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (!isa<CallExpr>(SrcExpr.get()))
+ return;
+
+ QualType SrcType = SrcExpr.get()->getType();
+ if (DestType.getUnqualifiedType()->isVoidType())
+ return;
+ if ((SrcType->isAnyPointerType() || SrcType->isBlockPointerType())
+ && (DestType->isAnyPointerType() || DestType->isBlockPointerType()))
+ return;
+ if (SrcType->isIntegerType() && DestType->isIntegerType() &&
+ (SrcType->isBooleanType() == DestType->isBooleanType()) &&
+ (SrcType->isEnumeralType() == DestType->isEnumeralType()))
+ return;
+ if (SrcType->isRealFloatingType() && DestType->isRealFloatingType())
+ return;
+ if (SrcType->isEnumeralType() && DestType->isEnumeralType())
+ return;
+ if (SrcType->isComplexType() && DestType->isComplexType())
+ return;
+ if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType())
+ return;
+
+ Self.Diag(SrcExpr.get()->getExprLoc(),
+ diag::warn_bad_function_cast)
+ << SrcType << DestType << SrcExpr.get()->getSourceRange();
+}
+
/// Check the semantics of a C-style cast operation, in C.
void CastOperation::CheckCStyleCast() {
assert(!Self.getLangOpts().CPlusPlus);
@@ -2035,6 +2089,8 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
+ checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
+ DestType, Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
@@ -2076,7 +2132,7 @@ void CastOperation::CheckCStyleCast() {
}
}
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
-
+ DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
Kind = Self.PrepareScalarCast(SrcExpr, DestType);
if (SrcExpr.isInvalid())
return;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 2559f00f71e0..692a210ef304 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -266,11 +266,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_swap_4:
case Builtin::BI__sync_swap_8:
case Builtin::BI__sync_swap_16:
- return SemaBuiltinAtomicOverloaded(move(TheCallResult));
+ return SemaBuiltinAtomicOverloaded(TheCallResult);
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case Builtin::BI##ID: \
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID);
+ return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
case Builtin::BI__builtin_annotation:
if (SemaBuiltinAnnotation(*this, TheCall))
@@ -299,7 +299,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
}
- return move(TheCallResult);
+ return TheCallResult;
}
// Get the valid immediate range for the specified NEON type code.
@@ -437,6 +437,11 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
default: return false;
case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break;
case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break;
+ case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break;
+ case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break;
+ case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break;
};
// We can't check the value of a dependent argument.
@@ -490,9 +495,8 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
SourceLocation Loc,
SourceRange Range,
VariadicCallType CallType) {
- // FIXME: This mechanism should be abstracted to be less fragile and
- // more efficient. For example, just map function ids to custom
- // handlers.
+ if (CurContext->isDependentContext())
+ return;
// Printf and scanf checking.
bool HandledFormatString = false;
@@ -506,8 +510,11 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
// Refuse POD arguments that weren't caught by the format string
// checks above.
if (!HandledFormatString && CallType != VariadicDoesNotApply)
- for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx)
- variadicArgumentPODCheck(Args[ArgIdx], CallType);
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) {
+ // Args[ArgIdx] can be null in malformed code.
+ if (Expr *Arg = Args[ArgIdx])
+ variadicArgumentPODCheck(Arg, CallType);
+ }
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
@@ -538,11 +545,23 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
/// and safety properties not strictly enforced by the C type system.
bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
const FunctionProtoType *Proto) {
- bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
+ bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
+ isa<CXXMethodDecl>(FDecl);
+ bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
+ IsMemberOperatorCall;
VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
TheCall->getCallee());
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
- checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
+ Expr** Args = TheCall->getArgs();
+ unsigned NumArgs = TheCall->getNumArgs();
+ if (IsMemberOperatorCall) {
+ // If this is a call to a member operator, hide the first argument
+ // from checkCall.
+ // FIXME: Our choice of AST representation here is less than ideal.
+ ++Args;
+ --NumArgs;
+ }
+ checkCall(FDecl, Args, NumArgs, NumProtoArgs,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -737,6 +756,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
+ if (AtomTy.isConstQualified()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
ValType = AtomTy->getAs<AtomicType>()->getValueType();
}
@@ -885,8 +909,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
}
return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
- SubExprs.data(), SubExprs.size(),
- ResultType, Op,
+ SubExprs, ResultType, Op,
TheCall->getRParenLoc()));
}
@@ -1189,10 +1212,19 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID);
- IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName);
- FunctionDecl *NewBuiltinDecl =
- cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID,
- TUScope, false, DRE->getLocStart()));
+ FunctionDecl *NewBuiltinDecl;
+ if (NewBuiltinID == BuiltinID)
+ NewBuiltinDecl = FDecl;
+ else {
+ // Perform builtin lookup to avoid redeclaring it.
+ DeclarationName DN(&Context.Idents.get(NewBuiltinName));
+ LookupResult Res(*this, DN, DRE->getLocStart(), LookupOrdinaryName);
+ LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true);
+ assert(Res.getFoundDecl());
+ NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl());
+ if (NewBuiltinDecl == 0)
+ return ExprError();
+ }
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
@@ -1228,14 +1260,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
NewBuiltinDecl,
/*enclosing*/ false,
DRE->getLocation(),
- NewBuiltinDecl->getType(),
+ Context.BuiltinFnTy,
DRE->getValueKind());
// Set the callee in the CallExpr.
- // FIXME: This leaks the original parens and implicit casts.
- ExprResult PromotedCall = UsualUnaryConversions(NewDRE);
- if (PromotedCall.isInvalid())
- return ExprError();
+ // FIXME: This loses syntactic information.
+ QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
+ ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
+ CK_BuiltinFnToFnPtr);
TheCall->setCallee(PromotedCall.take());
// Change the result type of the call to match the original value type. This
@@ -1243,7 +1275,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// gracefully.
TheCall->setType(ResultType);
- return move(TheCallResult);
+ return TheCallResult;
}
/// CheckObjCString - Checks that the argument to the builtin
@@ -1264,7 +1296,7 @@ bool Sema::CheckObjCString(Expr *Arg) {
StringRef String = Literal->getString();
unsigned NumBytes = String.size();
SmallVector<UTF16, 128> ToBuf(NumBytes);
- const UTF8 *FromPtr = (UTF8 *)String.data();
+ const UTF8 *FromPtr = (const UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes,
@@ -1503,8 +1535,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->setArg(i, 0);
}
- return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(),
- exprs.size(), resType,
+ return Owned(new (Context) ShuffleVectorExpr(Context, exprs, resType,
TheCall->getCallee()->getLocStart(),
TheCall->getRParenLoc()));
}
@@ -1935,19 +1966,19 @@ public:
void HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen);
+ void HandleInvalidLengthModifier(
+ const analyze_format_string::FormatSpecifier &FS,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen, unsigned DiagID);
+
void HandleNonStandardLengthModifier(
- const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::FormatSpecifier &FS,
const char *startSpecifier, unsigned specifierLen);
void HandleNonStandardConversionSpecifier(
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen);
- void HandleNonStandardConversionSpecification(
- const analyze_format_string::LengthModifier &LM,
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen);
-
virtual void HandlePosition(const char *startPos, unsigned posLen);
virtual void HandleInvalidPosition(const char *startSpecifier,
@@ -1964,7 +1995,7 @@ public:
PartialDiagnostic PDiag,
SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- FixItHint Fixit = FixItHint());
+ ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>());
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
@@ -1991,7 +2022,7 @@ protected:
template <typename Range>
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- FixItHint Fixit = FixItHint());
+ ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>());
void CheckPositionalAndNonpositionalArgs(
const analyze_format_string::FormatSpecifier *FS);
@@ -2025,35 +2056,95 @@ void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
getSpecifierRange(startSpecifier, specifierLen));
}
+void CheckFormatHandler::HandleInvalidLengthModifier(
+ const analyze_format_string::FormatSpecifier &FS,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen, unsigned DiagID) {
+ using namespace analyze_format_string;
+
+ const LengthModifier &LM = FS.getLengthModifier();
+ CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+ // See if we know how to fix this length modifier.
+ llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ if (FixedLM) {
+ EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+ << FixedLM->toString()
+ << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+ } else {
+ FixItHint Hint;
+ if (DiagID == diag::warn_format_nonsensical_length)
+ Hint = FixItHint::CreateRemoval(LMRange);
+
+ EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ Hint);
+ }
+}
+
void CheckFormatHandler::HandleNonStandardLengthModifier(
- const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::FormatSpecifier &FS,
const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString()
- << 0,
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
+ using namespace analyze_format_string;
+
+ const LengthModifier &LM = FS.getLengthModifier();
+ CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+ // See if we know how to fix this length modifier.
+ llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ if (FixedLM) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << LM.toString() << 0,
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+ << FixedLM->toString()
+ << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << LM.toString() << 0,
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
}
void CheckFormatHandler::HandleNonStandardConversionSpecifier(
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString()
- << 1,
- getLocationOfByte(CS.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
-}
+ using namespace analyze_format_string;
-void CheckFormatHandler::HandleNonStandardConversionSpecification(
- const analyze_format_string::LengthModifier &LM,
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_conversion_spec)
- << LM.toString() << CS.toString(),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen));
+ // See if we know how to fix this conversion specifier.
+ llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ if (FixedCS) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << CS.toString() << /*conversion specifier*/1,
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+
+ CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength());
+ S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier)
+ << FixedCS->toString()
+ << FixItHint::CreateReplacement(CSRange, FixedCS->toString());
+ } else {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+ << CS.toString() << /*conversion specifier*/1,
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
}
void CheckFormatHandler::HandlePosition(const char *startPos,
@@ -2182,7 +2273,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
- FixItHint FixIt) {
+ ArrayRef<FixItHint> FixIt) {
EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
Loc, IsStringLocation, StringRange, FixIt);
}
@@ -2190,7 +2281,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
/// \brief If the format string is not within the funcion call, emit a note
/// so that the function call and string are in diagnostic messages.
///
-/// \param inFunctionCall if true, the format string is within the function
+/// \param InFunctionCall if true, the format string is within the function
/// call and only one diagnostic message will be produced. Otherwise, an
/// extra note will be emitted pointing to location of the format string.
///
@@ -2213,7 +2304,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
/// \param StringRange some or all of the string to highlight. This is
/// templated so it can accept either a CharSourceRange or a SourceRange.
///
-/// \param Fixit optional fix it hint for the format string.
+/// \param FixIt optional fix it hint for the format string.
template<typename Range>
void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
const Expr *ArgumentExpr,
@@ -2221,15 +2312,27 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
SourceLocation Loc,
bool IsStringLocation,
Range StringRange,
- FixItHint FixIt) {
- if (InFunctionCall)
- S.Diag(Loc, PDiag) << StringRange << FixIt;
- else {
+ ArrayRef<FixItHint> FixIt) {
+ if (InFunctionCall) {
+ const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
+ D << StringRange;
+ for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end();
+ I != E; ++I) {
+ D << *I;
+ }
+ } else {
S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
<< ArgumentExpr->getSourceRange();
- S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
- diag::note_format_string_defined)
- << StringRange << FixIt;
+
+ const Sema::SemaDiagnosticBuilder &Note =
+ S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
+ diag::note_format_string_defined);
+
+ Note << StringRange;
+ for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end();
+ I != E; ++I) {
+ Note << *I;
+ }
}
}
@@ -2550,23 +2653,17 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
startSpecifier, specifierLen);
// Check the length modifier is valid with the given conversion specifier.
- const LengthModifier &LM = FS.getLengthModifier();
- if (!FS.hasValidLengthModifier())
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString(),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true,
- getSpecifierRange(startSpecifier, specifierLen),
- FixItHint::CreateRemoval(
- getSpecifierRange(LM.getStart(),
- LM.getLength())));
- if (!FS.hasStandardLengthModifier())
- HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_nonsensical_length);
+ else if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+ else if (!FS.hasStandardLengthConversionCombination())
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_non_standard_conversion_spec);
+
if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
- if (!FS.hasStandardLengthConversionCombination())
- HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
- specifierLen);
// The remaining checks depend on the data arguments.
if (HasVAListArg)
@@ -2582,6 +2679,30 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
}
+static bool requiresParensToAddCast(const Expr *E) {
+ // FIXME: We should have a general way to reason about operator
+ // precedence and whether parens are actually needed here.
+ // Take care of a few common cases where they aren't.
+ const Expr *Inside = E->IgnoreImpCasts();
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside))
+ Inside = POE->getSyntacticForm()->IgnoreImpCasts();
+
+ switch (Inside->getStmtClass()) {
+ case Stmt::ArraySubscriptExprClass:
+ case Stmt::CallExprClass:
+ case Stmt::DeclRefExprClass:
+ case Stmt::MemberExprClass:
+ case Stmt::ObjCIvarRefExprClass:
+ case Stmt::ObjCMessageExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ParenExprClass:
+ case Stmt::UnaryOperatorClass:
+ return false;
+ default:
+ return true;
+ }
+}
+
bool
CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
@@ -2593,81 +2714,151 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// format specifier.
const analyze_printf::ArgType &AT = FS.getArgType(S.Context,
ObjCContext);
- if (AT.isValid() && !AT.matchesType(S.Context, E->getType())) {
- // Look through argument promotions for our error message's reported type.
- // This includes the integral and floating promotions, but excludes array
- // and function pointer decay; seeing that an argument intended to be a
- // string has type 'char [6]' is probably more confusing than 'char *'.
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() == CK_IntegralCast ||
- ICE->getCastKind() == CK_FloatingCast) {
- E = ICE->getSubExpr();
-
- // Check if we didn't match because of an implicit cast from a 'char'
- // or 'short' to an 'int'. This is done because printf is a varargs
- // function.
- if (ICE->getType() == S.Context.IntTy ||
- ICE->getType() == S.Context.UnsignedIntTy) {
- // All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, E->getType()))
- return true;
- }
+ if (!AT.isValid())
+ return true;
+
+ QualType IntendedTy = E->getType();
+ if (AT.matchesType(S.Context, IntendedTy))
+ return true;
+
+ // Look through argument promotions for our error message's reported type.
+ // This includes the integral and floating promotions, but excludes array
+ // and function pointer decay; seeing that an argument intended to be a
+ // string has type 'char [6]' is probably more confusing than 'char *'.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_IntegralCast ||
+ ICE->getCastKind() == CK_FloatingCast) {
+ E = ICE->getSubExpr();
+ IntendedTy = E->getType();
+
+ // Check if we didn't match because of an implicit cast from a 'char'
+ // or 'short' to an 'int'. This is done because printf is a varargs
+ // function.
+ if (ICE->getType() == S.Context.IntTy ||
+ ICE->getType() == S.Context.UnsignedIntTy) {
+ // All further checking is done on the subexpression.
+ if (AT.matchesType(S.Context, IntendedTy))
+ return true;
}
}
+ }
- // We may be able to offer a FixItHint if it is a supported type.
- PrintfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(E->getType(), S.getLangOpts(),
- S.Context, ObjCContext);
+ if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
+ // Special-case some of Darwin's platform-independence types.
+ if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
+ StringRef Name = UserTy->getDecl()->getName();
+ IntendedTy = llvm::StringSwitch<QualType>(Name)
+ .Case("NSInteger", S.Context.LongTy)
+ .Case("NSUInteger", S.Context.UnsignedLongTy)
+ .Case("SInt32", S.Context.IntTy)
+ .Case("UInt32", S.Context.UnsignedIntTy)
+ .Default(IntendedTy);
+ }
+ }
- if (success) {
- // Get the fix string from the fixed format specifier
- SmallString<16> buf;
- llvm::raw_svector_ostream os(buf);
- fixedFS.toString(os);
+ // We may be able to offer a FixItHint if it is a supported type.
+ PrintfSpecifier fixedFS = FS;
+ bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(),
+ S.Context, ObjCContext);
+
+ if (success) {
+ // Get the fix string from the fixed format specifier
+ SmallString<16> buf;
+ llvm::raw_svector_ostream os(buf);
+ fixedFS.toString(os);
+
+ CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
+
+ if (IntendedTy != E->getType()) {
+ // The canonical type for formatting this value is different from the
+ // actual type of the expression. (This occurs, for example, with Darwin's
+ // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
+ // should be printed as 'long' for 64-bit compatibility.)
+ // Rather than emitting a normal format/argument mismatch, we want to
+ // add a cast to the recommended type (and correct the format string
+ // if necessary).
+ SmallString<16> CastBuf;
+ llvm::raw_svector_ostream CastFix(CastBuf);
+ CastFix << "(";
+ IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
+ CastFix << ")";
+
+ SmallVector<FixItHint,4> Hints;
+ if (!AT.matchesType(S.Context, IntendedTy))
+ Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
+
+ if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
+ // If there's already a cast present, just replace it.
+ SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc());
+ Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str()));
+
+ } else if (!requiresParensToAddCast(E)) {
+ // If the expression has high enough precedence,
+ // just write the C-style cast.
+ Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(),
+ CastFix.str()));
+ } else {
+ // Otherwise, add parens around the expression as well as the cast.
+ CastFix << "(";
+ Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(),
+ CastFix.str()));
+
+ SourceLocation After = S.PP.getLocForEndOfToken(E->getLocEnd());
+ Hints.push_back(FixItHint::CreateInsertion(After, ")"));
+ }
+ // We extract the name from the typedef because we don't want to show
+ // the underlying type in the diagnostic.
+ const TypedefType *UserTy = cast<TypedefType>(E->getType());
+ StringRef Name = UserTy->getDecl()->getName();
+
+ // Finally, emit the diagnostic.
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
+ << Name << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation=*/false,
+ SpecRange, Hints);
+ } else {
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << IntendedTy
<< E->getSourceRange(),
E->getLocStart(),
/*IsStringLocation*/false,
- getSpecifierRange(StartSpecifier, SpecifierLen),
- FixItHint::CreateReplacement(
- getSpecifierRange(StartSpecifier, SpecifierLen),
- os.str()));
- } else {
- const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
- SpecifierLen);
- // 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(E->getType()) == Sema::VAK_Invalid) {
- unsigned DiagKind;
- if (E->getType()->isObjCObjectType())
- DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
- else
- DiagKind = diag::warn_non_pod_vararg_with_format_string;
-
- EmitFormatDiagnostic(
- S.PDiag(DiagKind)
- << S.getLangOpts().CPlusPlus0x
- << E->getType()
- << CallType
- << AT.getRepresentativeTypeName(S.Context)
- << 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) << E->getType()
- << CSR
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation*/false, CSR);
+ SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
}
+ } else {
+ const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
+ SpecifierLen);
+ // 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(E->getType()) == Sema::VAK_Invalid) {
+ unsigned DiagKind;
+ if (E->getType()->isObjCObjectType())
+ DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
+ else
+ DiagKind = diag::warn_non_pod_vararg_with_format_string;
+
+ EmitFormatDiagnostic(
+ S.PDiag(DiagKind)
+ << S.getLangOpts().CPlusPlus0x
+ << E->getType()
+ << CallType
+ << AT.getRepresentativeTypeName(S.Context)
+ << 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) << E->getType()
+ << CSR
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false, CSR);
}
return true;
@@ -2776,24 +2967,17 @@ bool CheckScanfHandler::HandleScanfSpecifier(
}
// Check the length modifier is valid with the given conversion specifier.
- const LengthModifier &LM = FS.getLengthModifier();
- if (!FS.hasValidLengthModifier()) {
- const CharSourceRange &R = getSpecifierRange(LM.getStart(), LM.getLength());
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen),
- getLocationOfByte(LM.getStart()),
- /*IsStringLocation*/true, R,
- FixItHint::CreateRemoval(R));
- }
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_nonsensical_length);
+ else if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+ else if (!FS.hasStandardLengthConversionCombination())
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_non_standard_conversion_spec);
- if (!FS.hasStandardLengthModifier())
- HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
- if (!FS.hasStandardLengthConversionCombination())
- HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
- specifierLen);
// The remaining checks depend on the data arguments.
if (HasVAListArg)
@@ -2881,7 +3065,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- getLangOpts()))
+ getLangOpts(),
+ Context.getTargetInfo()))
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
@@ -2889,7 +3074,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
- getLangOpts()))
+ getLangOpts(),
+ Context.getTargetInfo()))
H.DoneProcessing();
} // TODO: handle other formats
}
@@ -4138,6 +4324,44 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
}
}
+static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
+ Expr *Constant, Expr *Other,
+ llvm::APSInt Value,
+ bool RhsConstant) {
+ BinaryOperatorKind op = E->getOpcode();
+ QualType OtherT = Other->getType();
+ QualType ConstantT = Constant->getType();
+ if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
+ return;
+ assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
+ && "comparison with non-integer type");
+ // FIXME. handle cases for signedness to catch (signed char)N == 200
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
+ if (OtherRange.Width >= LitRange.Width)
+ return;
+ bool IsTrue = true;
+ if (op == BO_EQ)
+ IsTrue = false;
+ else if (op == BO_NE)
+ IsTrue = true;
+ else if (RhsConstant) {
+ if (op == BO_GT || op == BO_GE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_LT || op == BO_LE
+ IsTrue = LitRange.NonNegative;
+ } else {
+ if (op == BO_LT || op == BO_LE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_GT || op == BO_GE
+ IsTrue = LitRange.NonNegative;
+ }
+ SmallString<16> PrettySourceValue(Value.toString(10));
+ S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
+ << PrettySourceValue << OtherT << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+}
+
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
@@ -4153,20 +4377,42 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
QualType T = E->getLHS()->getType();
assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
&& "comparison with mismatched types");
+ if (E->isValueDependent())
+ return AnalyzeImpConvsInComparison(S, E);
+ Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
+ Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
+
+ bool IsComparisonConstant = false;
+
+ // Check whether an integer constant comparison results in a value
+ // of 'true' or 'false'.
+ if (T->isIntegralType(S.Context)) {
+ llvm::APSInt RHSValue;
+ bool IsRHSIntegralLiteral =
+ RHS->isIntegerConstantExpr(RHSValue, S.Context);
+ llvm::APSInt LHSValue;
+ bool IsLHSIntegralLiteral =
+ LHS->isIntegerConstantExpr(LHSValue, S.Context);
+ if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true);
+ else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false);
+ else
+ IsComparisonConstant =
+ (IsRHSIntegralLiteral && IsLHSIntegralLiteral);
+ } else if (!T->hasUnsignedIntegerRepresentation())
+ IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
+
// We don't do anything special if this isn't an unsigned integral
// comparison: we're only interested in integral comparisons, and
// signed comparisons only happen in cases we don't care to warn about.
//
// We also don't care about value-dependent expressions or expressions
// whose result is a constant.
- if (!T->hasUnsignedIntegerRepresentation()
- || E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
+ if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
return AnalyzeImpConvsInComparison(S, E);
-
- Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
- Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
-
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
@@ -4353,6 +4599,46 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
+static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
+ if (!isa<ImplicitCastExpr>(Ex))
+ return false;
+
+ Expr *InnerE = Ex->IgnoreParenImpCasts();
+ const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
+ const Type *Source =
+ S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+ if (Target->isDependentType())
+ return false;
+
+ const BuiltinType *FloatCandidateBT =
+ dyn_cast<BuiltinType>(ToBool ? Source : Target);
+ const Type *BoolCandidateType = ToBool ? Target : Source;
+
+ return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) &&
+ FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
+}
+
+void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
+ SourceLocation CC) {
+ unsigned NumArgs = TheCall->getNumArgs();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ Expr *CurrA = TheCall->getArg(i);
+ if (!IsImplicitBoolFloatConversion(S, CurrA, true))
+ continue;
+
+ bool IsSwapped = ((i > 0) &&
+ IsImplicitBoolFloatConversion(S, TheCall->getArg(i - 1), false));
+ IsSwapped |= ((i < (NumArgs - 1)) &&
+ IsImplicitBoolFloatConversion(S, TheCall->getArg(i + 1), false));
+ if (IsSwapped) {
+ // Warn on this floating-point to bool conversion.
+ DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
+ CurrA->getType(), CC,
+ diag::warn_impcast_floating_point_to_bool);
+ }
+ }
+}
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -4488,12 +4774,33 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
+ // If the target is bool, warn if expr is a function or method call.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool) &&
+ isa<CallExpr>(E)) {
+ // Check last argument of function call to see if it is an
+ // implicit cast from a type matching the type the result
+ // is being cast to.
+ CallExpr *CEx = cast<CallExpr>(E);
+ unsigned NumArgs = CEx->getNumArgs();
+ if (NumArgs > 0) {
+ Expr *LastA = CEx->getArg(NumArgs - 1);
+ Expr *InnerE = LastA->IgnoreParenImpCasts();
+ const Type *InnerType =
+ S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+ if (isa<ImplicitCastExpr>(LastA) && (InnerType == Target)) {
+ // Warn on this floating-point to bool conversion
+ DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_floating_point_to_bool);
+ }
+ }
+ }
return;
}
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
- && !Target->isBlockPointerType() && !Target->isMemberPointerType()) {
+ && !Target->isBlockPointerType() && !Target->isMemberPointerType()
+ && Target->isScalarType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
@@ -4658,6 +4965,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
return;
}
+ // Check implicit argument conversions for function calls.
+ if (CallExpr *Call = dyn_cast<CallExpr>(E))
+ CheckImplicitArgumentConversions(S, Call, CC);
+
// Go ahead and check any implicit conversions we might have skipped.
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
@@ -5077,7 +5388,8 @@ static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
return false;
owner.Variable = var;
- owner.setLocsFrom(ref);
+ if (ref)
+ owner.setLocsFrom(ref);
return true;
}
@@ -5186,6 +5498,12 @@ namespace {
if (block->getBlockDecl()->capturesVariable(Variable))
Visit(block->getBlockDecl()->getBody());
}
+
+ void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) {
+ if (Capturer) return;
+ if (OVE->getSourceExpr())
+ Visit(OVE->getSourceExpr());
+ }
};
}
@@ -5195,6 +5513,28 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
assert(owner.Variable && owner.Loc.isValid());
e = e->IgnoreParenCasts();
+
+ // Look through [^{...} copy] and Block_copy(^{...}).
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(e)) {
+ Selector Cmd = ME->getSelector();
+ if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") {
+ e = ME->getInstanceReceiver();
+ if (!e)
+ return 0;
+ e = e->IgnoreParenCasts();
+ }
+ } else if (CallExpr *CE = dyn_cast<CallExpr>(e)) {
+ if (CE->getNumArgs() == 1) {
+ FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
+ if (Fn) {
+ const IdentifierInfo *FnI = Fn->getIdentifier();
+ if (FnI && FnI->isStr("_Block_copy")) {
+ e = CE->getArg(0)->IgnoreParenCasts();
+ }
+ }
+ }
+ }
+
BlockExpr *block = dyn_cast<BlockExpr>(e);
if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
return 0;
@@ -5271,6 +5611,20 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
diagnoseRetainCycle(*this, capturer, owner);
}
+void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
+ RetainCycleOwner Owner;
+ if (!considerVariable(Var, /*DeclRefExpr=*/0, Owner))
+ return;
+
+ // Because we don't have an expression for the variable, we have to set the
+ // location explicitly here.
+ Owner.Loc = Var->getLocation();
+ Owner.Range = Var->getSourceRange();
+
+ if (Expr *Capturer = findCapturingExpr(*this, Init, Owner))
+ diagnoseRetainCycle(*this, Capturer, Owner);
+}
+
bool Sema::checkUnsafeAssigns(SourceLocation Loc,
QualType LHS, Expr *RHS) {
Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
@@ -5304,9 +5658,19 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LHSType.isNull())
LHSType = LHS->getType();
+
+ Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+
+ if (LT == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(LHS);
+ }
+
if (checkUnsafeAssigns(Loc, LHSType, RHS))
return;
- Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+
// FIXME. Check for other life times.
if (LT != Qualifiers::OCL_None)
return;
@@ -5826,7 +6190,8 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
if (IsPointerAttr) {
// Skip implicit cast of pointer to `void *' (as a function argument).
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
- if (ICE->getType()->isVoidPointerType())
+ if (ICE->getType()->isVoidPointerType() &&
+ ICE->getCastKind() == CK_BitCast)
ArgumentExpr = ICE->getSubExpr();
}
QualType ArgumentType = ArgumentExpr->getType();
@@ -5881,4 +6246,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
-
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index adf132715738..b1aead8f026d 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1059,10 +1059,12 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
// Allow us to find class templates, too.
if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
-
+
+ // For purposes of this check, interfaces match too.
if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Class ||
- RD->getTagKind() == TTK_Struct;
+ RD->getTagKind() == TTK_Struct ||
+ RD->getTagKind() == TTK_Interface;
return false;
}
@@ -1422,7 +1424,8 @@ static const char *GetCompletionTypeString(QualType T,
if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
- case TTK_Class: return "class <anonymous>";
+ case TTK_Interface: return "__interface <anonymous>";
+ case TTK_Class: return "class <anonymous>";
case TTK_Union: return "union <anonymous>";
case TTK_Enum: return "enum <anonymous>";
}
@@ -1449,7 +1452,7 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) {
Policy,
Allocator));
Builder.AddTypedTextChunk("this");
- Results.AddResult(CodeCompletionResult(Builder.TakeString()));
+ Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
/// \brief Add language constructs that show up for "ordinary" names.
@@ -2480,7 +2483,6 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
if (Declaration) {
Result.addParentContext(Declaration->getDeclContext());
- Pattern->ParentKind = Result.getParentKind();
Pattern->ParentName = Result.getParentName();
}
@@ -2493,7 +2495,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
if (Kind == RK_Macro) {
- MacroInfo *MI = PP.getMacroInfo(Macro);
+ MacroInfo *MI = PP.getMacroInfoHistory(Macro);
assert(MI && "Not a macro?");
Result.AddTypedTextChunk(
@@ -2880,10 +2882,14 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case ObjCPropertyImplDecl::Synthesize:
return CXCursor_ObjCSynthesizeDecl;
}
+
+ case Decl::Import:
+ return CXCursor_ModuleImportDecl;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
+ case TTK_Interface: // fall through
case TTK_Struct: return CXCursor_StructDecl;
case TTK_Class: return CXCursor_ClassDecl;
case TTK_Union: return CXCursor_UnionDecl;
@@ -2896,6 +2902,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
}
static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
+ bool IncludeUndefined,
bool TargetTypeIsPointer = false) {
typedef CodeCompletionResult Result;
@@ -2904,7 +2911,8 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M) {
- Results.AddResult(Result(M->first,
+ if (IncludeUndefined || M->first->hasMacroDefinition())
+ Results.AddResult(Result(M->first,
getMacroUsagePriority(M->first->getName(),
PP.getLangOpts(),
TargetTypeIsPointer)));
@@ -3125,7 +3133,6 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
void Sema::CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, CompletionContext));
@@ -3204,7 +3211,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
}
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(),Results.size());
@@ -3296,7 +3303,6 @@ struct Sema::CodeCompleteExpressionData {
/// type we're looking for.
void Sema::CodeCompleteExpression(Scope *S,
const CodeCompleteExpressionData &Data) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
@@ -3336,7 +3342,7 @@ void Sema::CodeCompleteExpression(Scope *S,
AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results, PreferredTypeIsPointer);
+ AddMacroResults(PP, Results, false, PreferredTypeIsPointer);
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext(CodeCompletionContext::CCC_Expression,
Data.PreferredType),
@@ -3580,7 +3586,6 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
if (!CodeCompleter)
return;
- typedef CodeCompletionResult Result;
ResultBuilder::LookupFilter Filter = 0;
enum CodeCompletionContext::Kind ContextKind
= CodeCompletionContext::CCC_Other;
@@ -3597,6 +3602,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
case DeclSpec::TST_struct:
case DeclSpec::TST_class:
+ case DeclSpec::TST_interface:
Filter = &ResultBuilder::IsClassOrStruct;
ContextKind = CodeCompletionContext::CCC_ClassOrStructTag;
break;
@@ -3728,7 +3734,7 @@ void Sema::CodeCompleteCase(Scope *S) {
//so only say we include macros if the code completer says we do
enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other;
if (CodeCompleter->includeMacros()) {
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
kind = CodeCompletionContext::CCC_OtherWithMacros;
}
@@ -3898,7 +3904,6 @@ void Sema::CodeCompleteReturn(Scope *S) {
}
void Sema::CodeCompleteAfterIf(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, PCC_Statement));
@@ -3952,7 +3957,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(),Results.size());
@@ -4408,7 +4413,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
}
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -4595,26 +4599,23 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
// Check for collisions with "readonly".
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)))
+ (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
return true;
- // Check for more than one of { assign, copy, retain, strong }.
+ // Check for more than one of { assign, copy, retain, strong, weak }.
unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign |
ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain|
- ObjCDeclSpec::DQ_PR_strong);
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak);
if (AssignCopyRetMask &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong)
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong &&
+ AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak)
return true;
return false;
@@ -4626,7 +4627,6 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
unsigned Attributes = ODS.getPropertyAttributes();
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -4650,6 +4650,12 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("nonatomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
Results.AddResult(CodeCompletionResult("atomic"));
+
+ // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC.
+ if (getLangOpts().ObjCARCWeak || getLangOpts().getGC() != LangOptions::NonGC)
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak))
+ Results.AddResult(CodeCompletionResult("weak"));
+
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionBuilder Setter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -4837,8 +4843,6 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
- typedef CodeCompletionResult Result;
-
// Try to find the interface where getters might live.
ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
if (!Class) {
@@ -4866,8 +4870,6 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
}
void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
- typedef CodeCompletionResult Result;
-
// Try to find the interface where setters might live.
ObjCInterfaceDecl *Class
= dyn_cast_or_null<ObjCInterfaceDecl>(CurContext);
@@ -4898,7 +4900,6 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
bool IsParameter) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Type);
@@ -4957,7 +4958,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
CodeCompleter->includeGlobals());
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Type,
@@ -5041,7 +5042,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
///
/// \param S The semantic analysis object.
///
-/// \param S NeedSuperKeyword Whether we need to prefix this completion with
+/// \param NeedSuperKeyword Whether we need to prefix this completion with
/// the "super" keyword. Otherwise, we just need to provide the arguments.
///
/// \param SelIdents The identifiers in the selector that have already been
@@ -5187,7 +5188,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, false);
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(), Results.size());
@@ -5339,11 +5340,11 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
// If we have an external source, load the entire class method
// pool from the AST file.
- if (SemaRef.ExternalSource) {
+ if (SemaRef.getExternalSource()) {
for (uint32_t I = 0,
- N = SemaRef.ExternalSource->GetNumExternalSelectors();
+ N = SemaRef.getExternalSource()->GetNumExternalSelectors();
I != N; ++I) {
- Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I);
+ Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I);
if (Sel.isNull() || SemaRef.MethodPool.count(Sel))
continue;
@@ -5868,7 +5869,6 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
}
void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
- typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
@@ -7169,7 +7169,9 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
M != MEnd; ++M) {
Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(
M->first->getName()));
- Results.AddResult(Builder.TakeString());
+ Results.AddResult(CodeCompletionResult(Builder.TakeString(),
+ CCP_CodePattern,
+ CXCursor_MacroDefinition));
}
Results.ExitScope();
} else if (IsDefinition) {
@@ -7186,7 +7188,7 @@ void Sema::CodeCompletePreprocessorExpression() {
CodeCompletionContext::CCC_PreprocessorExpression);
if (!CodeCompleter || CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
+ AddMacroResults(PP, Results, true);
// defined (<macro>)
Results.EnterNewScope();
@@ -7235,7 +7237,7 @@ void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
}
if (!CodeCompleter || CodeCompleter->includeMacros())
- AddMacroResults(PP, Builder);
+ AddMacroResults(PP, Builder, true);
Results.clear();
Results.insert(Results.end(),
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index ea181de00a98..0092d5dab1f4 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -350,8 +350,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
/// isTagName() - This method is called *for error recovery purposes only*
/// to determine if the specified name is a valid tag name ("struct foo"). If
/// so, this returns the TST for the tag corresponding to it (TST_enum,
-/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C
-/// where the user forgot to specify the tag.
+/// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose
+/// cases in C where the user forgot to specify the tag.
DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
// Do a tag name lookup in this scope.
LookupResult R(*this, &II, SourceLocation(), LookupTagName);
@@ -361,6 +361,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
case TTK_Struct: return DeclSpec::TST_struct;
+ case TTK_Interface: return DeclSpec::TST_interface;
case TTK_Union: return DeclSpec::TST_union;
case TTK_Class: return DeclSpec::TST_class;
case TTK_Enum: return DeclSpec::TST_enum;
@@ -434,7 +435,8 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
<< II << DC << CorrectedQuotedStr << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
llvm_unreachable("could not have corrected a typo here");
@@ -517,9 +519,9 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
Scope *S, CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc) {
- Result.clear(Sema::LookupTagName);
- SemaRef.LookupParsedName(Result, S, &SS);
- if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+ LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
+ SemaRef.LookupParsedName(R, S, &SS);
+ if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
const char *TagName = 0;
const char *FixItTagName = 0;
switch (Tag->getTagKind()) {
@@ -538,6 +540,11 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
FixItTagName = "struct ";
break;
+ case TTK_Interface:
+ TagName = "__interface";
+ FixItTagName = "__interface ";
+ break;
+
case TTK_Union:
TagName = "union";
FixItTagName = "union ";
@@ -548,25 +555,42 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
<< Name << TagName << SemaRef.getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
- LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName);
- if (SemaRef.LookupParsedName(R, S, &SS)) {
- for (LookupResult::iterator I = R.begin(), IEnd = R.end();
- I != IEnd; ++I)
- SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
- << Name << TagName;
- }
+ for (LookupResult::iterator I = Result.begin(), IEnd = Result.end();
+ I != IEnd; ++I)
+ SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
+ << Name << TagName;
+
+ // Replace lookup results with just the tag decl.
+ Result.clear(Sema::LookupTagName);
+ SemaRef.LookupParsedName(Result, S, &SS);
return true;
}
- Result.clear(Sema::LookupOrdinaryName);
return false;
}
+/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier.
+static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
+ QualType T, SourceLocation NameLoc) {
+ ASTContext &Context = S.Context;
+
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+
+ T = S.getElaboratedType(ETK_None, SS, T);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
Sema::NameClassification Sema::ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc,
- const Token &NextToken) {
+ const Token &NextToken,
+ bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
@@ -632,25 +656,11 @@ Corrected:
// Perform typo correction to determine if there is another name that is
// close to this name.
- if (!SecondTry) {
+ if (!SecondTry && CCC) {
SecondTry = true;
- CorrectionCandidateCallback DefaultValidator;
- // Try to limit which sets of keywords should be included in typo
- // correction based on what the next token is.
- DefaultValidator.WantTypeSpecifiers =
- NextToken.is(tok::l_paren) || NextToken.is(tok::less) ||
- NextToken.is(tok::identifier) || NextToken.is(tok::star) ||
- NextToken.is(tok::amp) || NextToken.is(tok::l_square);
- DefaultValidator.WantExpressionKeywords =
- NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) ||
- NextToken.is(tok::arrow) || NextToken.is(tok::period);
- DefaultValidator.WantRemainingKeywords =
- NextToken.is(tok::l_paren) || NextToken.is(tok::semi) ||
- NextToken.is(tok::identifier) || NextToken.is(tok::l_brace);
- DefaultValidator.WantCXXNamedCasts = false;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS, DefaultValidator)) {
+ &SS, *CCC)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
@@ -675,11 +685,12 @@ Corrected:
Diag(NameLoc, UnqualifiedDiag)
<< Name << CorrectedQuotedStr
<< FixItHint::CreateReplacement(NameLoc, CorrectedStr);
- else
+ else // FIXME: is this even reachable? Test it.
Diag(NameLoc, QualifiedDiag)
<< Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
// Update the name, so that the caller has the new name.
Name = Corrected.getCorrectionAsIdentifierInfo();
@@ -705,7 +716,7 @@ Corrected:
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
Result.clear();
ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
- return move(E);
+ return E;
}
goto Corrected;
@@ -731,8 +742,9 @@ Corrected:
// perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
- return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/0);
+ return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, IsAddressOfOperand,
+ /*TemplateArgs=*/0);
}
case LookupResult::Found:
@@ -808,14 +820,16 @@ Corrected:
return NameClassification::TypeTemplate(Template);
}
}
-
+
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
DiagnoseUseOfDecl(Type, NameLoc);
QualType T = Context.getTypeDeclType(Type);
+ if (SS.isNotEmpty())
+ return buildNestedType(*this, SS, T, NameLoc);
return ParsedType::make(T);
}
-
+
ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
if (!Class) {
// FIXME: It's unfortunate that we don't have a Type node for handling this.
@@ -838,24 +852,28 @@ Corrected:
return ParsedType::make(T);
}
+ // We can have a type template here if we're classifying a template argument.
+ if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl))
+ return NameClassification::TypeTemplate(
+ TemplateName(cast<TemplateDecl>(FirstDecl)));
+
// 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 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) &&
- !isa<TypeAliasTemplateDecl>(FirstDecl)) {
+ 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)) {
- FirstDecl = (*Result.begin())->getUnderlyingDecl();
- if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
- DiagnoseUseOfDecl(Type, NameLoc);
- QualType T = Context.getTypeDeclType(Type);
- return ParsedType::make(T);
- }
+ 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 (!Result.empty() && (*Result.begin())->isCXXClassMember())
+ if (FirstDecl->isCXXClassMember())
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
@@ -1186,8 +1204,14 @@ 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().isConstant(Context) ||
+ VD->getType().isConstQualified() ||
+ VD->getType()->isReferenceType() ||
Context.DeclMustBeEmitted(VD))
return false;
@@ -1248,7 +1272,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
QualType Ty = VD->getType();
// Only look at the outermost level of typedef.
- if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) {
+ if (const TypedefType *TT = Ty->getAs<TypedefType>()) {
if (TT->getDecl()->hasAttr<UnusedAttr>())
return false;
}
@@ -1268,6 +1292,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const Expr *Init = VD->getInit()) {
+ if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(Init))
+ Init = Cleanups->getSubExpr();
const CXXConstructExpr *Construct =
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
@@ -1706,6 +1732,25 @@ DeclHasAttr(const Decl *D, const Attr *A) {
if (AA)
return false;
+ // The following thread safety attributes can also be duplicated.
+ switch (A->getKind()) {
+ case attr::ExclusiveLocksRequired:
+ case attr::SharedLocksRequired:
+ case attr::LocksExcluded:
+ case attr::ExclusiveLockFunction:
+ case attr::SharedLockFunction:
+ case attr::UnlockFunction:
+ case attr::ExclusiveTrylockFunction:
+ case attr::SharedTrylockFunction:
+ case attr::GuardedBy:
+ case attr::PtGuardedBy:
+ case attr::AcquiredBefore:
+ case attr::AcquiredAfter:
+ return false;
+ default:
+ ;
+ }
+
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
@@ -1908,6 +1953,19 @@ 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;
+}
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -1976,6 +2034,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// later declared or defined without one, the second decl assumes 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
@@ -1989,10 +2050,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
bool RequiresAdjustment = false;
- if (OldTypeInfo.getCC() != CC_Default &&
- NewTypeInfo.getCC() == CC_Default) {
+ 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.
+ } else if (OldTypeInfo.getCC() == CC_Default &&
+ isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) {
+ NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
+ RequiresAdjustment = true;
+
} else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
NewTypeInfo.getCC())) {
// Calling conventions really aren't compatible, so complain.
@@ -2398,7 +2471,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
}
if (MergedT.isNull()) {
Diag(New->getLocation(), diag::err_redefinition_different_type)
- << New->getDeclName();
+ << New->getDeclName() << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
@@ -2551,8 +2624,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS) {
- return ParsedFreeStandingDeclSpec(S, AS, DS,
- MultiTemplateParamsArg(*this, 0, 0));
+ return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -2565,6 +2637,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
+ DS.getTypeSpecType() == DeclSpec::TST_interface ||
DS.getTypeSpecType() == DeclSpec::TST_union ||
DS.getTypeSpecType() == DeclSpec::TST_enum) {
TagD = DS.getRepAsDecl();
@@ -2603,7 +2676,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
<< (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
- DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3);
+ DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+ DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4);
else
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
// Don't emit warnings after this error.
@@ -2724,16 +2798,17 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec::TST TypeSpecType = DS.getTypeSpecType();
if (TypeSpecType == DeclSpec::TST_class ||
TypeSpecType == DeclSpec::TST_struct ||
+ TypeSpecType == DeclSpec::TST_interface ||
TypeSpecType == DeclSpec::TST_union ||
TypeSpecType == DeclSpec::TST_enum) {
AttributeList* attrs = DS.getAttributes().getList();
while (attrs) {
- Diag(attrs->getScopeLoc(),
- diag::warn_declspec_attribute_ignored)
+ Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored)
<< attrs->getName()
<< (TypeSpecType == DeclSpec::TST_class ? 0 :
TypeSpecType == DeclSpec::TST_struct ? 1 :
- TypeSpecType == DeclSpec::TST_union ? 2 : 3);
+ TypeSpecType == DeclSpec::TST_union ? 2 :
+ TypeSpecType == DeclSpec::TST_interface ? 3 : 4);
attrs = attrs->getNext();
}
}
@@ -3353,7 +3428,6 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_decltype:
case DeclSpec::TST_underlyingType:
case DeclSpec::TST_atomic: {
// Grab the type from the parser.
@@ -3377,6 +3451,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
break;
}
+ case DeclSpec::TST_decltype:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
ExprResult Result = S.RebuildExprInCurrentInstantiation(E);
@@ -3411,7 +3486,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
D.setFunctionDefinitionKind(FDK_Declaration);
- Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
+ Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg());
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
Dcl && Dcl->getDeclContext()->isFileContext())
@@ -3476,7 +3551,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
// void X::f();
// };
if (Cur->Equals(DC)) {
- Diag(Loc, diag::warn_member_extra_qualification)
+ Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification
+ : diag::err_member_extra_qualification)
<< Name << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
return false;
@@ -3710,11 +3786,11 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous);
} else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous,
- move(TemplateParamLists),
+ TemplateParamLists,
AddToScope);
} else {
New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
- move(TemplateParamLists));
+ TemplateParamLists);
}
if (New == 0)
@@ -3729,9 +3805,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
return New;
}
-/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array
-/// types into constant array types in certain situations which would otherwise
-/// be errors (for GCC compatibility).
+/// Helper method to turn variable array types into constant array
+/// types in certain situations which would otherwise be errors (for
+/// GCC compatibility).
static QualType TryToFixInvalidVariablyModifiedType(QualType T,
ASTContext &Context,
bool &SizeIsNegative,
@@ -3799,6 +3875,52 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
Res, ArrayType::Normal, 0);
}
+static void
+FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) {
+ if (PointerTypeLoc* SrcPTL = dyn_cast<PointerTypeLoc>(&SrcTL)) {
+ PointerTypeLoc* DstPTL = cast<PointerTypeLoc>(&DstTL);
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(),
+ DstPTL->getPointeeLoc());
+ DstPTL->setStarLoc(SrcPTL->getStarLoc());
+ return;
+ }
+ if (ParenTypeLoc* SrcPTL = dyn_cast<ParenTypeLoc>(&SrcTL)) {
+ ParenTypeLoc* DstPTL = cast<ParenTypeLoc>(&DstTL);
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(),
+ DstPTL->getInnerLoc());
+ DstPTL->setLParenLoc(SrcPTL->getLParenLoc());
+ DstPTL->setRParenLoc(SrcPTL->getRParenLoc());
+ return;
+ }
+ ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL);
+ ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL);
+ TypeLoc SrcElemTL = SrcATL->getElementLoc();
+ TypeLoc DstElemTL = DstATL->getElementLoc();
+ DstElemTL.initializeFullCopy(SrcElemTL);
+ DstATL->setLBracketLoc(SrcATL->getLBracketLoc());
+ DstATL->setSizeExpr(SrcATL->getSizeExpr());
+ DstATL->setRBracketLoc(SrcATL->getRBracketLoc());
+}
+
+/// Helper method to turn variable array types into constant array
+/// types in certain situations which would otherwise be errors (for
+/// GCC compatibility).
+static TypeSourceInfo*
+TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
+ ASTContext &Context,
+ bool &SizeIsNegative,
+ llvm::APSInt &Oversized) {
+ QualType FixedTy
+ = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context,
+ SizeIsNegative, Oversized);
+ if (FixedTy.isNull())
+ return 0;
+ TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy);
+ FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(),
+ FixedTInfo->getTypeLoc());
+ return FixedTInfo;
+}
+
/// \brief Register the given locally-scoped external C declaration so
/// that it can be found later for redeclarations
void
@@ -3926,19 +4048,21 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
// that redeclarations will match.
- QualType T = NewTD->getUnderlyingType();
+ TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo();
+ QualType T = TInfo->getType();
if (T->isVariablyModifiedType()) {
getCurFunction()->setHasBranchProtectedScope();
if (S->getFnParent() == 0) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
- Oversized);
- if (!FixedTy.isNull()) {
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative,
+ Oversized);
+ if (FixedTInfo) {
Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size);
- NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy));
+ NewTD->setTypeSourceInfo(FixedTInfo);
} else {
if (SizeIsNegative)
Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size);
@@ -4203,7 +4327,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
- TemplateParamLists.get(),
+ TemplateParamLists.data(),
TemplateParamLists.size(),
/*never a friend*/ false,
isExplicitSpecialization,
@@ -4244,7 +4368,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) {
NewVD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
if (D.getDeclSpec().isConstexprSpecified())
@@ -4281,6 +4405,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
+ if (getLangOpts().CUDA) {
+ // CUDA B.2.5: "__shared__ and __constant__ variables have implied static
+ // storage [duration]."
+ if (SC == SC_None && S->getFnParent() != 0 &&
+ (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>()))
+ NewVD->setStorageClass(SC_Static);
+ }
+
// In auto-retain/release, infer strong retension for variables of
// retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
@@ -4490,7 +4622,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (NewVD->isInvalidDecl())
return false;
- QualType T = NewVD->getType();
+ TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo();
+ QualType T = TInfo->getType();
if (T->isObjCObjectType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
@@ -4522,8 +4655,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
&& !NewVD->hasAttr<BlocksAttr>()) {
if (getLangOpts().getGC() != LangOptions::NonGC)
Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
- else
+ else {
+ assert(!getLangOpts().ObjCAutoRefCount);
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ }
}
bool isVM = T->isVariablyModifiedType();
@@ -4535,11 +4670,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy =
- TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
- Oversized);
-
- if (FixedTy.isNull() && T->isVariableArrayType()) {
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative, Oversized);
+ if (FixedTInfo == 0 && T->isVariableArrayType()) {
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
// FIXME: This won't give the correct result for
// int a[10][n];
@@ -4558,7 +4692,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false;
}
- if (FixedTy.isNull()) {
+ if (FixedTInfo == 0) {
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
else
@@ -4568,7 +4702,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
- NewVD->setType(FixedTy);
+ NewVD->setType(FixedTInfo->getType());
+ NewVD->setTypeSourceInfo(FixedTInfo);
}
if (Previous.empty() && NewVD->isExternC()) {
@@ -4655,6 +4790,31 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
return false;
}
+namespace {
+ enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted };
+}
+/// \brief Report an error regarding overriding, along with any relevant
+/// overriden methods.
+///
+/// \param DiagID the primary error to report.
+/// \param MD the overriding method.
+/// \param OEK which overrides to include as notes.
+static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
+ OverrideErrorKind OEK = OEK_All) {
+ S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I) {
+ // This check (& the OEK parameter) could be replaced by a predicate, but
+ // without lambdas that would be overkill. This is still nicer than writing
+ // out the diag loop 3 times.
+ if ((OEK == OEK_All) ||
+ (OEK == OEK_NonDeleted && !(*I)->isDeleted()) ||
+ (OEK == OEK_Deleted && (*I)->isDeleted()))
+ S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ }
+}
+
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4663,6 +4823,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
FindOverriddenMethodData Data;
Data.Method = MD;
Data.S = this;
+ bool hasDeletedOverridenMethods = false;
+ bool hasNonDeletedOverridenMethods = false;
bool AddedAny = false;
if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) {
for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
@@ -4672,12 +4834,21 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
+ hasDeletedOverridenMethods |= OldMD->isDeleted();
+ hasNonDeletedOverridenMethods |= !OldMD->isDeleted();
AddedAny = true;
}
}
}
}
-
+
+ if (hasDeletedOverridenMethods && !MD->isDeleted()) {
+ ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted);
+ }
+ if (hasNonDeletedOverridenMethods && MD->isDeleted()) {
+ ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted);
+ }
+
return AddedAny;
}
@@ -4837,6 +5008,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
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())
@@ -5072,6 +5247,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
}
+void Sema::checkVoidParamDecl(ParmVarDecl *Param) {
+ // In C++, the empty parameter-type-list must be spelled "void"; a
+ // typedef of void is not permitted.
+ if (getLangOpts().CPlusPlus &&
+ Param->getType().getUnqualifiedType() != Context.VoidTy) {
+ bool IsTypeAlias = false;
+ if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
+ IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ Param->getType()->getAs<TemplateSpecializationType>())
+ IsTypeAlias = TST->isTypeAlias();
+ Diag(Param->getLocation(), diag::err_param_typedef_of_void)
+ << IsTypeAlias;
+ }
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -5138,6 +5329,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setImplicitlyInline();
}
+ // If this is a method defined in an __interface, and is not a constructor
+ // or an overloaded operator, then set the pure flag (isVirtual will already
+ // return true).
+ if (const CXXRecordDecl *Parent =
+ dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) {
+ if (Parent->isInterface() && cast<CXXMethodDecl>(NewFD)->isUserProvided())
+ NewFD->setPure(true);
+ }
+
SetNestedNameSpecifier(NewFD, D);
isExplicitSpecialization = false;
isFunctionTemplateSpecialization = false;
@@ -5157,7 +5357,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
- TemplateParamLists.get(),
+ TemplateParamLists.data(),
TemplateParamLists.size(),
isFriend,
isExplicitSpecialization,
@@ -5196,7 +5396,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size() - 1,
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
} else {
// This is a function template specialization.
@@ -5204,7 +5404,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store all the template param lists.
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -5236,7 +5436,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store all the template param lists.
NewFD->setTemplateParameterListsInfo(Context,
TemplateParamLists.size(),
- TemplateParamLists.release());
+ TemplateParamLists.data());
}
if (Invalid) {
@@ -5376,6 +5576,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
+
+ // C++11 [except.spec]p15:
+ // A deallocation function with no exception-specification is treated
+ // as if it were specified with noexcept(true).
+ const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
+ if ((Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
+ getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpecType = EST_BasicNoexcept;
+ NewFD->setType(Context.getFunctionType(FPT->getResultType(),
+ FPT->arg_type_begin(),
+ FPT->getNumArgs(), EPI));
+ }
}
// Filter out previous declarations that don't match the scope.
@@ -5413,21 +5627,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FTI.ArgInfo[0].Param &&
cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
// Empty arg list, don't push any params.
- ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[0].Param);
-
- // In C++, the empty parameter-type-list must be spelled "void"; a
- // typedef of void is not permitted.
- if (getLangOpts().CPlusPlus &&
- Param->getType().getUnqualifiedType() != Context.VoidTy) {
- bool IsTypeAlias = false;
- if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
- IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
- else if (const TemplateSpecializationType *TST =
- Param->getType()->getAs<TemplateSpecializationType>())
- IsTypeAlias = TST->isTypeAlias();
- Diag(Param->getLocation(), diag::err_param_typedef_of_void)
- << IsTypeAlias;
- }
+ checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
@@ -5500,6 +5700,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isExplicitSpecialization));
}
+ // Make graceful recovery from an invalid redeclaration.
+ else if (!Previous.empty())
+ D.setRedeclaration(true);
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
@@ -5510,12 +5713,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr,
TemplateArgs);
- TemplateArgsPtr.release();
HasExplicitTemplateArgs = true;
@@ -5969,20 +6170,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Find any virtual functions that this function overrides.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) {
if (!Method->isFunctionTemplateSpecialization() &&
- !Method->getDescribedFunctionTemplate()) {
+ !Method->getDescribedFunctionTemplate() &&
+ Method->isCanonicalDecl()) {
if (AddOverriddenMethods(Method->getParent(), Method)) {
// If the function was marked as "static", we have a problem.
if (NewFD->getStorageClass() == SC_Static) {
- Diag(NewFD->getLocation(), diag::err_static_overrides_virtual)
- << NewFD->getDeclName();
- for (CXXMethodDecl::method_iterator
- Overridden = Method->begin_overridden_methods(),
- OverriddenEnd = Method->end_overridden_methods();
- Overridden != OverriddenEnd;
- ++Overridden) {
- Diag((*Overridden)->getLocation(),
- diag::note_overridden_virtual_function);
- }
+ ReportOverrides(*this, diag::err_static_overrides_virtual, Method);
}
}
}
@@ -6191,28 +6384,12 @@ namespace {
}
}
- // Sometimes, the expression passed in lacks the casts that are used
- // to determine which DeclRefExpr's to check. Assume that the casts
- // are present and continue visiting the expression.
- void HandleExpr(Expr *E) {
- // Skip checking T a = a where T is not a record or reference type.
- // Doing so is a way to silence uninitialized warnings.
- if (isRecordType || isReferenceType)
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- HandleDeclRefExpr(DRE);
-
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- HandleValue(CO->getTrueExpr());
- HandleValue(CO->getFalseExpr());
- }
-
- Visit(E);
- }
-
// For most expressions, the cast is directly above the DeclRefExpr.
// For conditional operators, the cast can be outside the conditional
// operator if both expressions are DeclRefExpr's.
void HandleValue(Expr *E) {
+ if (isReferenceType)
+ return;
E = E->IgnoreParenImpCasts();
if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) {
HandleDeclRefExpr(DRE);
@@ -6222,11 +6399,32 @@ namespace {
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
HandleValue(CO->getTrueExpr());
HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (isa<MemberExpr>(E)) {
+ Expr *Base = E->IgnoreParenImpCasts();
+ while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+ // Check for static member variables and don't warn on them.
+ if (!isa<FieldDecl>(ME->getMemberDecl()))
+ return;
+ Base = ME->getBase()->IgnoreParenImpCasts();
+ }
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base))
+ HandleDeclRefExpr(DRE);
+ return;
}
}
+ // Reference types are handled here since all uses of references are
+ // bad, not just r-value uses.
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (isReferenceType)
+ HandleDeclRefExpr(E);
+ }
+
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) ||
+ if (E->getCastKind() == CK_LValueToRValue ||
(isRecordType && E->getCastKind() == CK_NoOp))
HandleValue(E->getSubExpr());
@@ -6237,22 +6435,36 @@ namespace {
// Don't warn on arrays since they can be treated as pointers.
if (E->getType()->canDecayToPointerType()) return;
- ValueDecl *VD = E->getMemberDecl();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD);
- if (isa<FieldDecl>(VD) || (MD && !MD->isStatic()))
- if (DeclRefExpr *DRE
- = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
+ // Warn when a non-static method call is followed by non-static member
+ // field accesses, which is followed by a DeclRefExpr.
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl());
+ bool Warn = (MD && !MD->isStatic());
+ Expr *Base = E->getBase()->IgnoreParenImpCasts();
+ while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+ if (!isa<FieldDecl>(ME->getMemberDecl()))
+ Warn = false;
+ Base = ME->getBase()->IgnoreParenImpCasts();
+ }
+
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (Warn)
HandleDeclRefExpr(DRE);
- return;
- }
+ return;
+ }
- Inherited::VisitMemberExpr(E);
+ // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr.
+ // Visit that expression.
+ Visit(Base);
}
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
- if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType &&
- isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return;
+ if (E->getOpcode() == UO_AddrOf && isRecordType &&
+ isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) {
+ if (!isPODType)
+ HandleValue(E->getSubExpr());
+ return;
+ }
Inherited::VisitUnaryOperator(E);
}
@@ -6261,20 +6473,38 @@ namespace {
void HandleDeclRefExpr(DeclRefExpr *DRE) {
Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
- LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::NotForRedeclaration);
+ unsigned diag = isReferenceType
+ ? diag::warn_uninit_self_reference_in_reference_init
+ : diag::warn_uninit_self_reference_in_init;
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
- S.PDiag(diag::warn_uninit_self_reference_in_init)
- << Result.getLookupName()
+ S.PDiag(diag)
+ << DRE->getNameInfo().getName()
<< OrigDecl->getLocation()
<< DRE->getSourceRange());
}
};
-}
-/// CheckSelfReference - Warns if OrigDecl is used in expression E.
-void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) {
- SelfReferenceChecker(*this, OrigDecl).HandleExpr(E);
+ /// CheckSelfReference - Warns if OrigDecl is used in expression E.
+ static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E,
+ bool DirectInit) {
+ // Parameters arguments are occassionially constructed with itself,
+ // for instance, in recursive functions. Skip them.
+ if (isa<ParmVarDecl>(OrigDecl))
+ return;
+
+ E = E->IgnoreParens();
+
+ // Skip checking T a = a where T is not a record or reference type.
+ // Doing so is a way to silence uninitialized warnings.
+ if (!DirectInit && !cast<VarDecl>(OrigDecl)->getType()->isRecordType())
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getCastKind() == CK_LValueToRValue)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()))
+ if (DRE->getDecl() == OrigDecl)
+ return;
+
+ SelfReferenceChecker(S, OrigDecl).Visit(E);
+ }
}
/// AddInitializerToDecl - Adds the initializer Init to the
@@ -6311,15 +6541,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
- // Check for self-references within variable initializers.
- // Variables declared within a function/method body (except for references)
- // are handled by a dataflow analysis.
- // Record types initialized by initializer list are handled here.
- // Initialization by constructors are handled in TryConstructorInitialization.
- if ((!VDecl->hasLocalStorage() || VDecl->getType()->isReferenceType()) &&
- (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType()))
- CheckSelfReference(RealDecl, Init);
-
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
@@ -6495,8 +6716,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, Args,NumArgs),
- &DclT);
+ MultiExprArg(Args, NumArgs), &DclT);
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
return;
@@ -6505,6 +6725,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
Init = Result.takeAs<Expr>();
}
+ // Check for self-references within variable initializers.
+ // Variables declared within a function/method body (except for references)
+ // are handled by a dataflow analysis.
+ if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
+ VDecl->getType()->isReferenceType()) {
+ CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ }
+
// If the type changed, it means we had an incomplete type that was
// completed by the initializer. For example:
// int ary[] = { 1, 3, 5 };
@@ -6515,9 +6743,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
- if (!VDecl->isInvalidDecl())
+ if (!VDecl->isInvalidDecl()) {
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+ if (VDecl->hasAttr<BlocksAttr>())
+ checkRetainCycles(VDecl, Init);
+
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ Init->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(Init);
+ }
+ }
+
Init = MaybeCreateExprWithCleanups(Init);
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -6758,8 +7005,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
AbstractVariableType))
Var->setInvalidDecl();
if (!Type->isDependentType() && !Var->isInvalidDecl() &&
- Var->getStorageClass() == SC_PrivateExtern)
+ Var->getStorageClass() == SC_PrivateExtern) {
Diag(Var->getLocation(), diag::warn_private_extern);
+ Diag(Var->getLocation(), diag::note_private_extern);
+ }
return;
@@ -6881,8 +7130,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
= InitializationKind::CreateDefault(Var->getLocation());
InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg());
if (Init.isInvalid())
Var->setInvalidDecl();
else if (Init.get()) {
@@ -6957,11 +7205,22 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
}
+ if (var->isThisDeclarationADefinition() &&
+ var->getLinkage() == ExternalLinkage) {
+ // Find a previous declaration that's not a definition.
+ VarDecl *prev = var->getPreviousDecl();
+ while (prev && prev->isThisDeclarationADefinition())
+ prev = prev->getPreviousDecl();
+
+ if (!prev)
+ Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var;
+ }
+
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
- QualType baseType = Context.getBaseElementType(var->getType());
- if (baseType->isDependentType()) return;
+ QualType type = var->getType();
+ if (type->isDependentType()) return;
// __block variables might require us to capture a copy-initializer.
if (var->hasAttr<BlocksAttr>()) {
@@ -6970,8 +7229,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
- QualType type = var->getType();
-
if (type->isStructureOrClassType()) {
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
@@ -6989,8 +7246,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Expr *Init = var->getInit();
bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
+ QualType baseType = Context.getBaseElementType(type);
- if (!var->getDeclContext()->isDependentContext() && Init) {
+ if (!var->getDeclContext()->isDependentContext() &&
+ Init && !Init->isValueDependent()) {
if (IsGlobal && !var->isConstexpr() &&
getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
var->getLocation())
@@ -7178,7 +7437,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
// the lookahead in the lexer: we've consumed the semicolon and looked
// ahead through comments.
for (unsigned i = 0; i != NumDecls; ++i)
- Context.getCommentForDecl(Group[i]);
+ Context.getCommentForDecl(Group[i], &PP);
}
}
@@ -7450,6 +7709,9 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
unsigned DiagID; // unused
DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
PrevSpec, DiagID);
+ // Use the identifier location for the type source range.
+ DS.SetRangeStart(FTI.ArgInfo[i].IdentLoc);
+ DS.SetRangeEnd(FTI.ArgInfo[i].IdentLoc);
Declarator ParamD(DS, Declarator::KNRTypeListContext);
ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
@@ -7464,8 +7726,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
Scope *ParentScope = FnBodyScope->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
- Decl *DP = HandleDeclarator(ParentScope, D,
- MultiTemplateParamsArg(*this));
+ Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg());
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
@@ -7707,7 +7968,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
- return ActOnFinishFunctionBody(D, move(BodyArg), false);
+ return ActOnFinishFunctionBody(D, BodyArg, false);
}
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
@@ -7765,22 +8026,16 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (Body)
computeNRVO(Body, getCurFunction());
}
- if (getCurFunction()->ObjCShouldCallSuperDealloc) {
- Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
- getCurFunction()->ObjCShouldCallSuperDealloc = false;
- }
- if (getCurFunction()->ObjCShouldCallSuperFinalize) {
- Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize);
- getCurFunction()->ObjCShouldCallSuperFinalize = false;
+ if (getCurFunction()->ObjCShouldCallSuper) {
+ Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call)
+ << MD->getSelector().getAsString();
+ getCurFunction()->ObjCShouldCallSuper = false;
}
} else {
return 0;
}
- assert(!getCurFunction()->ObjCShouldCallSuperDealloc &&
- "This should only be set for ObjC methods, which should have been "
- "handled in the block above.");
- assert(!getCurFunction()->ObjCShouldCallSuperFinalize &&
+ assert(!getCurFunction()->ObjCShouldCallSuper &&
"This should only be set for ObjC methods, which should have been "
"handled in the block above.");
@@ -7916,13 +8171,28 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
+ SourceLocation NoLoc;
Declarator D(DS, Declarator::BlockContext);
- D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false,
- SourceLocation(), 0, 0, 0, true,
- SourceLocation(), SourceLocation(),
- SourceLocation(), SourceLocation(),
- EST_None, SourceLocation(),
- 0, 0, 0, 0, Loc, Loc, D),
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
+ /*IsAmbiguous=*/false,
+ /*RParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ Loc, Loc, D),
DS.getAttributes(),
SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -8071,6 +8341,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
switch (D.getDeclSpec().getTypeSpecType()) {
case TST_enum:
case TST_struct:
+ case TST_interface:
case TST_union:
case TST_class: {
TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
@@ -8146,6 +8417,29 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
return false;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// redeclaration diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for redecl diagnostic!");
+ }
+}
+
+/// \brief Determine if tag kind is a class-key compatible with
+/// class for redeclaration (class, struct, or __interface).
+///
+/// \returns true iff the tag kind is compatible.
+static bool isClassCompatTagKind(TagTypeKind Tag)
+{
+ return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface;
+}
+
/// \brief Determine whether a tag with a given kind is acceptable
/// as a redeclaration of the given tag declaration.
///
@@ -8168,12 +8462,11 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
TagTypeKind OldTag = Previous->getTagKind();
- if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
+ if (!isDefinition || !isClassCompatTagKind(NewTag))
if (OldTag == NewTag)
return true;
- if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
- (NewTag == TTK_Struct || NewTag == TTK_Class)) {
+ if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) {
// Warn about the struct/class tag mismatch.
bool isTemplate = false;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
@@ -8183,7 +8476,8 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// In a template instantiation, do not offer fix-its for tag mismatches
// since they usually mess up the template instead of fixing the problem.
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TTK_Class) << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(OldTag);
return true;
}
@@ -8202,13 +8496,13 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (!previousMismatch) {
previousMismatch = true;
Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
- << (NewTag == TTK_Class) << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(I->getTagKind());
}
Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
- << (NewTag == TTK_Class)
+ << getRedeclDiagFromTagKind(NewTag)
<< FixItHint::CreateReplacement(I->getInnerLocStart(),
- NewTag == TTK_Class?
- "class" : "struct");
+ TypeWithKeyword::getTagTypeKindName(NewTag));
}
}
return true;
@@ -8224,16 +8518,16 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
}
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
- << (NewTag == TTK_Class)
- << isTemplate << &Name;
+ << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+ << getRedeclDiagFromTagKind(OldTag);
Diag(Redecl->getLocation(), diag::note_previous_use);
// If there is a previous defintion, suggest a fix-it.
if (Previous->getDefinition()) {
Diag(NewTagLoc, diag::note_struct_class_suggestion)
- << (Redecl->getTagKind() == TTK_Class)
+ << getRedeclDiagFromTagKind(Redecl->getTagKind())
<< FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- Redecl->getTagKind() == TTK_Class? "class" : "struct");
+ TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind()));
}
return true;
@@ -8276,7 +8570,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
- TemplateParameterLists.get(),
+ TemplateParameterLists.data(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
isExplicitSpecialization,
@@ -8293,8 +8587,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SS, Name, NameLoc, Attr,
TemplateParams, AS,
ModulePrivateLoc,
- TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.size()-1,
+ TemplateParameterLists.data());
return Result.get();
} else {
// The "template<>" header is extraneous.
@@ -8843,7 +9137,7 @@ CreateNewDecl:
if (TemplateParameterLists.size() > 0) {
New->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
}
else
@@ -9298,12 +9592,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
if (!InvalidDecl && T->isVariablyModifiedType()) {
bool SizeIsNegative;
llvm::APSInt Oversized;
- QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context,
- SizeIsNegative,
- Oversized);
- if (!FixedTy.isNull()) {
+
+ TypeSourceInfo *FixedTInfo =
+ TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
+ SizeIsNegative,
+ Oversized);
+ if (FixedTInfo) {
Diag(Loc, diag::warn_illegal_constant_array_size);
- T = FixedTy;
+ TInfo = FixedTInfo;
+ T = FixedTInfo->getType();
} else {
if (SizeIsNegative)
Diag(Loc, diag::err_typecheck_negative_array_size);
@@ -9460,12 +9757,12 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
return false;
}
-/// If the given constructor is user-provided, produce a diagnostic explaining
+/// If the given constructor is user-declared, produce a diagnostic explaining
/// that it makes the class non-trivial.
-static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT,
+static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
CXXConstructorDecl *CD,
Sema::CXXSpecialMember CSM) {
- if (!CD->isUserProvided())
+ if (CD->isImplicit())
return false;
SourceLocation CtorLoc = CD->getLocation();
@@ -9488,17 +9785,17 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
- if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member))
+ if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
return;
- // No user-provided constructors; look for constructor templates.
+ // No user-delcared constructors; look for constructor templates.
typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
tmpl_iter;
for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
TI != TE; ++TI) {
CXXConstructorDecl *CD =
dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
- if (CD && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member))
+ if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
return;
}
}
@@ -10025,42 +10322,6 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
- // Objective-C Automatic Reference Counting:
- // If a class has a non-static data member of Objective-C pointer
- // type (or array thereof), it is a non-POD type and its
- // default constructor (if any), copy constructor, copy assignment
- // operator, and destructor are non-trivial.
- //
- // This rule is also handled by CXXRecordDecl::completeDefinition().
- // However, here we check whether this particular class is only
- // non-POD because of the presence of an Objective-C pointer member.
- // If so, objects of this type cannot be shared between code compiled
- // with ARC and code compiled with manual retain/release.
- if (getLangOpts().ObjCAutoRefCount &&
- CXXRecord->hasObjectMember() &&
- CXXRecord->getLinkage() == ExternalLinkage) {
- if (CXXRecord->isPOD()) {
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_non_pod_class_with_object_member)
- << CXXRecord;
- } else {
- // FIXME: Fix-Its would be nice here, but finding a good location
- // for them is going to be tricky.
- if (CXXRecord->hasTrivialCopyConstructor())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 0;
- if (CXXRecord->hasTrivialCopyAssignment())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 1;
- if (CXXRecord->hasTrivialDestructor())
- Diag(CXXRecord->getLocation(),
- diag::warn_arc_trivial_member_function_with_object_member)
- << CXXRecord << 2;
- }
- }
-
// Adjust user-defined destructor exception spec.
if (getLangOpts().CPlusPlus0x &&
CXXRecord->hasUserDeclaredDestructor())
@@ -10092,7 +10353,7 @@ void Sema::ActOnFields(Scope* S,
// class subobject has more than one final overrider the
// program is ill-formed.
Diag(Record->getLocation(), diag::err_multiple_final_overriders)
- << (NamedDecl *)M->first << Record;
+ << (const NamedDecl *)M->first << Record;
Diag(M->first->getLocation(),
diag::note_overridden_virtual_function);
for (OverridingMethods::overriding_iterator
@@ -10100,7 +10361,7 @@ void Sema::ActOnFields(Scope* S,
OMEnd = SO->second.end();
OM != OMEnd; ++OM)
Diag(OM->Method->getLocation(), diag::note_final_overrider)
- << (NamedDecl *)M->first << OM->Method->getParent();
+ << (const NamedDecl *)M->first << OM->Method->getParent();
Record->setInvalidDecl();
}
@@ -10461,57 +10722,6 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
return New;
}
-// Emits a warning if every element in the enum is the same value and if
-// every element is initialized with a integer or boolean literal.
-static void CheckForUniqueEnumValues(Sema &S, Decl **Elements,
- unsigned NumElements, EnumDecl *Enum,
- QualType EnumType) {
- if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values,
- Enum->getLocation()) ==
- DiagnosticsEngine::Ignored)
- return;
-
- if (NumElements < 2)
- return;
-
- if (!Enum->getIdentifier())
- return;
-
- llvm::APSInt FirstVal;
-
- for (unsigned i = 0; i != NumElements; ++i) {
- EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
- if (!ECD)
- return;
-
- Expr *InitExpr = ECD->getInitExpr();
- if (!InitExpr)
- return;
- InitExpr = InitExpr->IgnoreImpCasts();
- if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr))
- return;
-
- if (i == 0) {
- FirstVal = ECD->getInitVal();
- continue;
- }
-
- if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal()))
- return;
- }
-
- S.Diag(Enum->getLocation(), diag::warn_identical_enum_values)
- << EnumType << FirstVal.toString(10)
- << Enum->getSourceRange();
-
- EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]),
- *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]);
-
- S.Diag(Last->getLocation(), diag::note_identical_enum_values)
- << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(),
- Next->getName());
-}
-
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10734,8 +10944,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// it needs to go into the function scope.
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
-
- CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
@@ -10834,10 +11042,6 @@ Decl *Sema::getObjCDeclContext() const {
}
AvailabilityResult Sema::getCurContextAvailability() const {
- const Decl *D = cast<Decl>(getCurLexicalContext());
- // A category implicitly has the availability of the interface.
- if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
- D = CatD->getClassInterface();
-
+ const Decl *D = cast<Decl>(getCurObjCLexicalContext());
return D->getAvailability();
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index caa7b2f65a9d..e326a20c87d0 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -415,14 +415,19 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
}
if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
- // Ignore empty strings without warnings
- if (StrLit->getLength() == 0)
+ if (StrLit->getLength() == 0 ||
+ StrLit->getString() == StringRef("*")) {
+ // Pass empty strings to the analyzer without warnings.
+ // Treat "*" as the universal lock.
+ Args.push_back(ArgExp);
continue;
+ }
// We allow constant strings to be used as a placeholder for expressions
// that are not valid C++ syntax, but warn that they are ignored.
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) <<
Attr.getName();
+ Args.push_back(ArgExp);
continue;
}
@@ -859,7 +864,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
if (!checkAttributeNumArgs(S, Attr, 1))
return;
- Expr *Arg = Attr.getArg(0);
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
@@ -867,9 +871,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
return;
}
- if (Arg->isTypeDependent())
- return;
-
// check that the argument is lockable object
SmallVector<Expr*, 1> Args;
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
@@ -962,7 +963,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
// If the alignment is less than or equal to 8 bits, the packed attribute
// has no effect.
- if (!FD->getType()->isIncompleteType() &&
+ if (!FD->getType()->isDependentType() &&
+ !FD->getType()->isIncompleteType() &&
S.Context.getTypeAlign(FD->getType()) <= 8)
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
@@ -973,8 +975,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (TagDecl *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ RD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -1522,6 +1524,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
+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;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) MinSizeAttr(Attr.getRange(), S.Context));
+}
+
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -2268,16 +2284,14 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
- if (!T->isPointerType() ||
- !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ if (!T->isCARCBridgableType()) {
S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
return;
}
}
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
QualType T = PD->getType();
- if (!T->isPointerType() ||
- !T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
+ if (!T->isCARCBridgableType()) {
S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
return;
}
@@ -3583,7 +3597,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
+ return;
}
+ case AttributeList::AT_PnaclCall:
+ D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context));
+ return;
+
default:
llvm_unreachable("unexpected attribute kind");
}
@@ -3636,9 +3655,17 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
Diag(attr.getLoc(), diag::err_invalid_pcs);
return true;
}
+ case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break;
default: llvm_unreachable("unexpected attribute kind");
}
+ const TargetInfo &TI = Context.getTargetInfo();
+ TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
+ if (A == TargetInfo::CCCR_Warning) {
+ Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
+ CC = TI.getDefaultCallingConv();
+ }
+
return false;
}
@@ -3878,11 +3905,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
returnType = MD->getResultType();
- else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
- returnType = PD->getType();
else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
(Attr.getKind() == AttributeList::AT_NSReturnsRetained))
return; // ignore: was handled as a type attribute
+ else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ returnType = PD->getType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
returnType = FD->getResultType();
else {
@@ -3971,6 +3998,33 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
}
+static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
+ const AttributeList &attr) {
+ SourceLocation loc = attr.getLoc();
+ 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;
+ }
+ DeclContext *DC = method->getDeclContext();
+ if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
+ S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
+ << attr.getName() << 0;
+ S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
+ return;
+ }
+ if (method->getMethodFamily() == OMF_dealloc) {
+ S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
+ << attr.getName() << 1;
+ return;
+ }
+
+ method->addAttr(
+ ::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context));
+}
+
/// Handle cf_audited_transfer and cf_unknown_transfer.
static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
if (!isa<FunctionDecl>(D)) {
@@ -4149,19 +4203,21 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.MicrosoftExt) {
- AttributeList::Kind Kind = Attr.getKind();
- if (Kind == AttributeList::AT_SingleInheritance)
- D->addAttr(
- ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
- else if (Kind == AttributeList::AT_MultipleInheritance)
- D->addAttr(
- ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
- else if (Kind == AttributeList::AT_VirtualInheritance)
- D->addAttr(
- ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
- } else
+ if (!S.LangOpts.MicrosoftExt) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return;
+ }
+
+ AttributeList::Kind Kind = Attr.getKind();
+ if (Kind == AttributeList::AT_SingleInheritance)
+ D->addAttr(
+ ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_MultipleInheritance)
+ D->addAttr(
+ ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
+ else if (Kind == AttributeList::AT_VirtualInheritance)
+ D->addAttr(
+ ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
}
static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -4246,6 +4302,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
+ case AttributeList::AT_MinSize:
+ handleMinSizeAttr(S, D, Attr);
+ break;
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;
@@ -4278,6 +4337,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+ case AttributeList::AT_ObjCRequiresSuper:
+ handleObjCRequiresSuperAttr(S, D, Attr); break;
+
case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;
@@ -4360,6 +4422,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ThisCall:
case AttributeList::AT_Pascal:
case AttributeList::AT_Pcs:
+ case AttributeList::AT_PnaclCall:
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
@@ -4774,18 +4837,25 @@ static bool isDeclDeprecated(Decl *D) {
static void
DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message,
SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCPropery) {
DeclarationName Name = D->getDeclName();
if (!Message.empty()) {
S.Diag(Loc, diag::warn_deprecated_message) << Name << Message;
S.Diag(D->getLocation(),
isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
: diag::note_previous_decl) << Name;
+ if (ObjCPropery)
+ S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
+ << ObjCPropery->getDeclName() << 0;
} else if (!UnknownObjCClass) {
S.Diag(Loc, diag::warn_deprecated) << D->getDeclName();
S.Diag(D->getLocation(),
isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
: diag::note_previous_decl) << Name;
+ if (ObjCPropery)
+ S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
+ << ObjCPropery->getDeclName() << 0;
} else {
S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name;
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
@@ -4800,16 +4870,19 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
DD.Triggered = true;
DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(),
DD.getDeprecationMessage(), DD.Loc,
- DD.getUnknownObjCClass());
+ DD.getUnknownObjCClass(),
+ DD.getObjCProperty());
}
void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D,
UnknownObjCClass,
+ ObjCProperty,
Message));
return;
}
@@ -4817,5 +4890,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
// Otherwise, don't warn if our current context is deprecated.
if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
return;
- DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass);
+ DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index eeac9b8e8d70..16eddf80ae5b 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -246,8 +246,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(),
EqualLoc);
InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &Arg, 1));
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg);
if (Result.isInvalid())
return true;
Arg = Result.takeAs<Expr>();
@@ -374,10 +373,10 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
}
}
-// 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
-// error, false otherwise.
+/// 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
+/// error, false otherwise.
bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Scope *S) {
bool Invalid = false;
@@ -676,6 +675,20 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
return true;
}
+/// \brief Get diagnostic %select index for tag kind for
+/// record diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for record diagnostic!");
+ }
+}
+
// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
// the requirements of a constexpr function definition or a constexpr
// constructor definition. If so, return true. If not, produce appropriate
@@ -692,8 +705,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
- << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
- << RD->getNumVBases();
+ << isa<CXXConstructorDecl>(NewFD)
+ << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getLocStart(),
@@ -1005,6 +1018,41 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
+/// \brief Determine whether the given class is a base class of the given
+/// class, including looking at dependent bases.
+static bool findCircularInheritance(const CXXRecordDecl *Class,
+ const CXXRecordDecl *Current) {
+ SmallVector<const CXXRecordDecl*, 8> Queue;
+
+ Class = Class->getCanonicalDecl();
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator I = Current->bases_begin(),
+ E = Current->bases_end();
+ I != E; ++I) {
+ CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ if (!Base)
+ continue;
+
+ Base = Base->getDefinition();
+ if (!Base)
+ continue;
+
+ if (Base->getCanonicalDecl() == Class)
+ return true;
+
+ Queue.push_back(Base);
+ }
+
+ if (Queue.empty())
+ return false;
+
+ Current = Queue.back();
+ Queue.pop_back();
+ }
+
+ return false;
+}
+
/// \brief Check the validity of a C++ base class specifier.
///
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
@@ -1031,13 +1079,32 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
<< TInfo->getTypeLoc().getSourceRange();
EllipsisLoc = SourceLocation();
}
-
- if (BaseType->isDependentType())
+
+ SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc();
+
+ if (BaseType->isDependentType()) {
+ // Make sure that we don't have circular inheritance among our dependent
+ // bases. For non-dependent bases, the check for completeness below handles
+ // this.
+ if (CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl()) {
+ if (BaseDecl->getCanonicalDecl() == Class->getCanonicalDecl() ||
+ ((BaseDecl = BaseDecl->getDefinition()) &&
+ findCircularInheritance(Class, BaseDecl))) {
+ Diag(BaseLoc, diag::err_circular_inheritance)
+ << BaseType << Context.getTypeDeclType(Class);
+
+ if (BaseDecl->getCanonicalDecl() != Class->getCanonicalDecl())
+ Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+ << BaseType;
+
+ return 0;
+ }
+ }
+
return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual,
Class->getTagKind() == TTK_Class,
Access, TInfo, EllipsisLoc);
-
- SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc();
+ }
// Base specifiers must be record types.
if (!BaseType->isRecordType()) {
@@ -1165,10 +1232,21 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
// Okay, add this new base class.
KnownBase = Bases[idx];
Bases[NumGoodBases++] = Bases[idx];
- if (const RecordType *Record = NewBaseType->getAs<RecordType>())
- if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()))
- if (RD->hasAttr<WeakAttr>())
- Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
+ if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (Class->isInterface() &&
+ (!RD->isInterface() ||
+ KnownBase->getAccessSpecifier() != AS_public)) {
+ // The Microsoft extension __interface does not permit bases that
+ // are not themselves public interfaces.
+ Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface)
+ << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName()
+ << RD->getSourceRange();
+ Invalid = true;
+ }
+ if (RD->hasAttr<WeakAttr>())
+ Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
+ }
}
}
@@ -1407,6 +1485,9 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
/// CheckOverrideControl - Check C++11 override control semantics.
void Sema::CheckOverrideControl(Decl *D) {
+ if (D->isInvalidDecl())
+ return;
+
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
// Do we know which functions this declaration might be overriding?
@@ -1496,6 +1577,50 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
bool isFunc = D.isDeclarationOfFunction();
+ if (cast<CXXRecordDecl>(CurContext)->isInterface()) {
+ // The Microsoft extension __interface only permits public member functions
+ // and prohibits constructors, destructors, operators, non-public member
+ // functions, static methods and data members.
+ unsigned InvalidDecl;
+ bool ShowDeclName = true;
+ if (!isFunc)
+ InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1;
+ else if (AS != AS_public)
+ InvalidDecl = 2;
+ else if (DS.getStorageClassSpec() == DeclSpec::SCS_static)
+ InvalidDecl = 3;
+ else switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ InvalidDecl = 4;
+ ShowDeclName = false;
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ InvalidDecl = 5;
+ ShowDeclName = false;
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXConversionFunctionName:
+ InvalidDecl = 6;
+ break;
+
+ default:
+ InvalidDecl = 0;
+ break;
+ }
+
+ if (InvalidDecl) {
+ if (ShowDeclName)
+ Diag(Loc, diag::err_invalid_member_in_interface)
+ << (InvalidDecl-1) << Name;
+ else
+ Diag(Loc, diag::err_invalid_member_in_interface)
+ << (InvalidDecl-1) << "";
+ return 0;
+ }
+ }
+
// C++ 9.2p6: A member shall not be declared to have automatic storage
// duration (auto, register) or with the extern storage-class-specifier.
// C++ 7.1.1p8: The mutable specifier can be applied only to names of class
@@ -1548,7 +1673,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// Member field could not be with "template" keyword.
// So TemplateParameterLists should be empty in this case.
if (TemplateParameterLists.size()) {
- TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0];
+ TemplateParameterList* TemplateParams = TemplateParameterLists[0];
if (TemplateParams->size()) {
// There is no such thing as a member field template.
Diag(D.getIdentifierLoc(), diag::err_template_member)
@@ -1588,7 +1713,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
} else {
assert(InitStyle == ICIS_NoInit);
- Member = HandleDeclarator(S, D, move(TemplateParameterLists));
+ Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member) {
return 0;
}
@@ -1662,6 +1787,99 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return Member;
}
+namespace {
+ class UninitializedFieldVisitor
+ : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
+ Sema &S;
+ ValueDecl *VD;
+ public:
+ typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
+ UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
+ S(S), VD(VD) {
+ }
+
+ void HandleExpr(Expr *E) {
+ if (!E) return;
+
+ // Expressions like x(x) sometimes lack the surrounding expressions
+ // but need to be checked anyways.
+ HandleValue(E);
+ Visit(E);
+ }
+
+ void HandleValue(Expr *E) {
+ E = E->IgnoreParens();
+
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (isa<EnumConstantDecl>(ME->getMemberDecl()))
+ return;
+ Expr *Base = E;
+ while (isa<MemberExpr>(Base)) {
+ ME = dyn_cast<MemberExpr>(Base);
+ if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
+ if (VarD->hasGlobalStorage())
+ return;
+ Base = ME->getBase();
+ }
+
+ if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
+ unsigned diag = VD->getType()->isReferenceType()
+ ? diag::warn_reference_field_is_uninit
+ : diag::warn_field_is_uninit;
+ S.Diag(ME->getExprLoc(), diag) << ME->getMemberNameInfo().getName();
+ return;
+ }
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ HandleValue(CO->getTrueExpr());
+ HandleValue(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ HandleValue(BCO->getCommon());
+ HandleValue(BCO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+ default:
+ return;
+ case(BO_PtrMemD):
+ case(BO_PtrMemI):
+ HandleValue(BO->getLHS());
+ return;
+ case(BO_Comma):
+ HandleValue(BO->getRHS());
+ return;
+ }
+ }
+ }
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ HandleValue(E->getSubExpr());
+
+ Inherited::VisitImplicitCastExpr(E);
+ }
+
+ void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ Expr *Callee = E->getCallee();
+ if (isa<MemberExpr>(Callee))
+ HandleValue(Callee);
+
+ Inherited::VisitCXXMemberCallExpr(E);
+ }
+ };
+ static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
+ ValueDecl *VD) {
+ UninitializedFieldVisitor(S, VD).HandleExpr(E);
+ }
+} // namespace
+
/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
/// in-class initializer for a non-static C++ class member, and after
/// instantiating an in-class initializer in a class template. Such actions
@@ -1685,8 +1903,17 @@ 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 (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent() &&
+ !FD->getDeclContext()->isDependentContext()) {
+ // Note: We don't type-check when we're in a dependent context, because
+ // the initialization-substitution code does not properly handle direct
+ // list initialization. We have the same hackaround for ctor-initializers.
if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
<< /*at end of ctor*/1 << InitExpr->getSourceRange();
@@ -1795,7 +2022,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc) {
- Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ Expr *List = new (Context) ParenListExpr(Context, LParenLoc,
+ llvm::makeArrayRef(Args, NumArgs),
RParenLoc);
return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
DS, IdLoc, List, EllipsisLoc);
@@ -2044,96 +2272,6 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
<< (unsigned)IsPointer;
}
-namespace {
- class UninitializedFieldVisitor
- : public EvaluatedExprVisitor<UninitializedFieldVisitor> {
- Sema &S;
- ValueDecl *VD;
- public:
- typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
- UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
- S(S), VD(VD) {
- }
-
- void HandleExpr(Expr *E) {
- if (!E) return;
-
- // Expressions like x(x) sometimes lack the surrounding expressions
- // but need to be checked anyways.
- HandleValue(E);
- Visit(E);
- }
-
- void HandleValue(Expr *E) {
- E = E->IgnoreParens();
-
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (isa<EnumConstantDecl>(ME->getMemberDecl()))
- return;
- Expr *Base = E;
- while (isa<MemberExpr>(Base)) {
- ME = dyn_cast<MemberExpr>(Base);
- if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
- if (VarD->hasGlobalStorage())
- return;
- Base = ME->getBase();
- }
-
- if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
- S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit);
- return;
- }
- }
-
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
- HandleValue(CO->getTrueExpr());
- HandleValue(CO->getFalseExpr());
- return;
- }
-
- if (BinaryConditionalOperator *BCO =
- dyn_cast<BinaryConditionalOperator>(E)) {
- HandleValue(BCO->getCommon());
- HandleValue(BCO->getFalseExpr());
- return;
- }
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- switch (BO->getOpcode()) {
- default:
- return;
- case(BO_PtrMemD):
- case(BO_PtrMemI):
- HandleValue(BO->getLHS());
- return;
- case(BO_Comma):
- HandleValue(BO->getRHS());
- return;
- }
- }
- }
-
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- if (E->getCastKind() == CK_LValueToRValue)
- HandleValue(E->getSubExpr());
-
- Inherited::VisitImplicitCastExpr(E);
- }
-
- void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- Expr *Callee = E->getCallee();
- if (isa<MemberExpr>(Callee))
- HandleValue(Callee);
-
- Inherited::VisitCXXMemberCallExpr(E);
- }
- };
- static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E,
- ValueDecl *VD) {
- UninitializedFieldVisitor(S, VD).HandleExpr(E);
- }
-} // namespace
-
MemInitResult
Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
SourceLocation IdLoc) {
@@ -2167,11 +2305,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
!= DiagnosticsEngine::Ignored)
for (unsigned i = 0; i < NumArgs; ++i)
// FIXME: Warn about the case when other fields are used before being
- // uninitialized. For example, let this field be the i'th field. When
+ // 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();
@@ -2204,7 +2344,7 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind,
- MultiExprArg(*this, Args, NumArgs),
+ MultiExprArg(Args, NumArgs),
0);
if (MemberInit.isInvalid())
return true;
@@ -2273,7 +2413,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
InitRange.getEnd());
InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
- MultiExprArg(*this, Args,NumArgs),
+ MultiExprArg(Args, NumArgs),
0);
if (DelegationInit.isInvalid())
return true;
@@ -2411,8 +2551,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
InitRange.getEnd());
InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind,
- MultiExprArg(*this, Args, NumArgs),
- 0);
+ MultiExprArg(Args, NumArgs), 0);
if (BaseInit.isInvalid())
return true;
@@ -2480,8 +2619,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
- MultiExprArg(SemaRef, 0, 0));
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg());
break;
}
@@ -2936,7 +3074,11 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
NumInitializers * sizeof(CXXCtorInitializer*));
Constructor->setCtorInitializers(baseOrMemberInitializers);
}
-
+
+ // Let template instantiation know whether we had errors.
+ if (AnyErrors)
+ Constructor->setInvalidDecl();
+
return false;
}
@@ -3324,11 +3466,10 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
} else {
assert(Init->isDelegatingInitializer());
// This must be the only initializer
- if (i != 0 || NumMemInits > 1) {
- Diag(MemInits[0]->getSourceLocation(),
+ if (NumMemInits != 1) {
+ Diag(Init->getSourceLocation(),
diag::err_delegating_initializer_alone)
- << MemInits[0]->getSourceRange();
- HadError = true;
+ << Init->getSourceRange() << MemInits[i ? 0 : 1]->getSourceRange();
// We will treat this as being the only initializer.
}
SetDelegatingInitializer(Constructor, MemInits[i]);
@@ -3812,6 +3953,11 @@ 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);
+ }
+
// See if a method overloads virtual methods in a base
/// class without overriding any.
if (!Record->isDependentType()) {
@@ -4065,7 +4211,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// Compute argument constness, constexpr, and triviality.
bool CanHaveConstParam = false;
- bool Trivial;
+ bool Trivial = false;
switch (CSM) {
case CXXDefaultConstructor:
Trivial = RD->hasTrivialDefaultConstructor();
@@ -4304,7 +4450,7 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
/// If we're operating on a base class, the object type is the
/// type of this special member.
QualType objectTy;
- AccessSpecifier access = target->getAccess();;
+ AccessSpecifier access = target->getAccess();
if (CXXBaseSpecifier *base = Subobj.dyn_cast<CXXBaseSpecifier*>()) {
objectTy = S.Context.getTypeDeclType(MD->getParent());
access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access);
@@ -4647,6 +4793,19 @@ namespace {
};
}
+/// \brief Check whether any most overriden method from MD in Methods
+static bool CheckMostOverridenMethods(const CXXMethodDecl *MD,
+ const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ if (MD->size_overridden_methods() == 0)
+ return Methods.count(MD->getCanonicalDecl());
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I)
+ if (CheckMostOverridenMethods(*I, Methods))
+ return true;
+ return false;
+}
+
/// \brief Member lookup function that determines whether a given C++
/// method overloads virtual methods in a base class without overriding any,
/// to be used with CXXRecordDecl::lookupInBases().
@@ -4678,7 +4837,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
if (!Data.S->IsOverload(Data.Method, MD, false))
return true;
// Collect the overload only if its hidden.
- if (!Data.OverridenAndUsingBaseMethods.count(MD))
+ if (!CheckMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods))
overloadedMethods.push_back(MD);
}
}
@@ -4689,6 +4848,17 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
return foundSameNameMethod;
}
+/// \brief Add the most overriden methods from MD to Methods
+static void AddMostOverridenMethods(const CXXMethodDecl *MD,
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) {
+ if (MD->size_overridden_methods() == 0)
+ Methods.insert(MD->getCanonicalDecl());
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I)
+ AddMostOverridenMethods(*I, Methods);
+}
+
/// \brief See if a method overloads virtual methods in a base class without
/// overriding any.
void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -4709,14 +4879,11 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
// by 'using' in a set. A base method not in this set is hidden.
for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName());
res.first != res.second; ++res.first) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*res.first))
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I)
- Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl());
+ NamedDecl *ND = *res.first;
if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first))
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(shad->getTargetDecl()))
- Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl());
+ ND = shad->getTargetDecl();
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+ AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
}
if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) &&
@@ -5307,7 +5474,47 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// Namespace Handling
//===----------------------------------------------------------------------===//
+/// \brief Diagnose a mismatch in 'inline' qualifiers when a namespace is
+/// reopened.
+static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
+ SourceLocation Loc,
+ IdentifierInfo *II, bool *IsInline,
+ NamespaceDecl *PrevNS) {
+ assert(*IsInline != PrevNS->isInline());
+
+ // HACK: Work around a bug in libstdc++4.6's <atomic>, where
+ // std::__atomic[0,1,2] are defined as non-inline namespaces, then reopened as
+ // inline namespaces, with the intention of bringing names into namespace std.
+ //
+ // We support this just well enough to get that case working; this is not
+ // sufficient to support reopening namespaces as inline in general.
+ if (*IsInline && II && II->getName().startswith("__atomic") &&
+ S.getSourceManager().isInSystemHeader(Loc)) {
+ // Mark all prior declarations of the namespace as inline.
+ for (NamespaceDecl *NS = PrevNS->getMostRecentDecl(); NS;
+ NS = NS->getPreviousDecl())
+ NS->setInline(*IsInline);
+ // Patch up the lookup table for the containing namespace. This isn't really
+ // correct, but it's good enough for this particular case.
+ for (DeclContext::decl_iterator I = PrevNS->decls_begin(),
+ E = PrevNS->decls_end(); I != E; ++I)
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*I))
+ PrevNS->getParent()->makeDeclVisibleInContext(ND);
+ return;
+ }
+
+ if (PrevNS->isInline())
+ // The user probably just forgot the 'inline', so suggest that it
+ // be added back.
+ S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
+ << FixItHint::CreateInsertion(KeywordLoc, "inline ");
+ else
+ S.Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
+ S.Diag(PrevNS->getLocation(), diag::note_previous_definition);
+ *IsInline = PrevNS->isInline();
+}
/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
@@ -5357,21 +5564,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
if (PrevNS) {
// This is an extended namespace definition.
- if (IsInline != PrevNS->isInline()) {
- // inline-ness must match
- if (PrevNS->isInline()) {
- // The user probably just forgot the 'inline', so suggest that it
- // be added back.
- Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
- << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
- } else {
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- }
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- IsInline = PrevNS->isInline();
- }
+ if (IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II,
+ &IsInline, PrevNS);
} else if (PrevDecl) {
// This is an invalid name redefinition.
Diag(Loc, diag::err_redefinition_different_kind)
@@ -5402,15 +5597,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevNS = ND->getAnonymousNamespace();
}
- if (PrevNS && IsInline != PrevNS->isInline()) {
- // inline-ness must match
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- // Recover by ignoring the new namespace's inline status.
- IsInline = PrevNS->isInline();
- }
+ if (PrevNS && IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II,
+ &IsInline, PrevNS);
}
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
@@ -5460,15 +5649,15 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
if (!PrevNS) {
UsingDirectiveDecl* UD
- = UsingDirectiveDecl::Create(Context, CurContext,
+ = UsingDirectiveDecl::Create(Context, Parent,
/* 'using' */ LBrace,
/* 'namespace' */ SourceLocation(),
/* qualifier */ NestedNameSpecifierLoc(),
/* identifier */ SourceLocation(),
Namespc,
- /* Ancestor */ CurContext);
+ /* Ancestor */ Parent);
UD->setImplicit();
- CurContext->addDecl(UD);
+ Parent->addDecl(UD);
}
}
@@ -5697,7 +5886,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
if (DeclContext *DC = S.computeDeclContext(SS, false))
S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
<< Ident << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
S.Diag(IdentLoc, diag::err_using_directive_suggest)
<< Ident << CorrectedQuotedStr
@@ -6562,10 +6752,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (TemplateParamLists.size() != 1) {
Diag(UsingLoc, diag::err_alias_template_extra_headers)
- << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
- TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
+ << SourceRange(TemplateParamLists[1]->getTemplateLoc(),
+ TemplateParamLists[TemplateParamLists.size()-1]->getRAngleLoc());
}
- TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
+ TemplateParameterList *TemplateParams = TemplateParamLists[0];
// Only consider previous declarations in the same scope.
FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
@@ -6696,28 +6886,6 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
return AliasDecl;
}
-namespace {
- /// \brief Scoped object used to handle the state changes required in Sema
- /// to implicitly define the body of a C++ member function;
- class ImplicitlyDefinedFunctionScope {
- Sema &S;
- Sema::ContextRAII SavedContext;
-
- public:
- ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method)
- : S(S), SavedContext(S, Method)
- {
- S.PushFunctionScope();
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
- }
-
- ~ImplicitlyDefinedFunctionScope() {
- S.PopExpressionEvaluationContext();
- S.PopFunctionScopeInfo();
- }
- };
-}
-
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
CXXMethodDecl *MD) {
@@ -6861,7 +7029,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
+ SynthesizedFunctionScope Scope(*this, Constructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
@@ -7173,7 +7341,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
if (Destructor->isInvalidDecl())
return;
- ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
+ SynthesizedFunctionScope Scope(*this, Destructor);
DiagnosticErrorTrap Trap(Diags);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
@@ -7412,7 +7580,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
= new (S.Context) BinaryOperator(IterationVarRefRVal,
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
- VK_RValue, OK_Ordinary, Loc);
+ VK_RValue, OK_Ordinary, Loc, false);
// Create the pre-increment of the iteration variable.
Expr *Increment
@@ -7654,7 +7822,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+ SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
DiagnosticErrorTrap Trap(Diags);
// C++0x [class.copy]p30:
@@ -7666,7 +7834,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// which they were declared in the class definition.
// The statements that form the synthesized function body.
- ASTOwningVector<Stmt*> Statements(*this);
+ SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are copying from.
ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
@@ -7846,8 +8014,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- CollectableMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
}
}
@@ -7866,12 +8034,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- BuiltinMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
}
- ASTOwningVector<Expr*> CallArgs(*this);
+ SmallVector<Expr*, 8> CallArgs;
CallArgs.push_back(To.takeAs<Expr>());
CallArgs.push_back(From.takeAs<Expr>());
CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
@@ -7879,12 +8047,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (NeedsCollectableMemCpy)
Call = ActOnCallExpr(/*Scope=*/0,
CollectableMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
else
Call = ActOnCallExpr(/*Scope=*/0,
BuiltinMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
@@ -7934,7 +8102,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
StmtResult Body;
{
CompoundScopeRAII CompoundScope(*this);
- Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ Body = ActOnCompoundStmt(Loc, Loc, Statements,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
@@ -8040,7 +8208,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
// reference types, are supposed to return false here, but that appears
// to be a standard defect.
CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
- if (!ClassDecl || !ClassDecl->getDefinition())
+ if (!ClassDecl || !ClassDecl->getDefinition() || ClassDecl->isInvalidDecl())
return true;
if (Type.isTriviallyCopyableType(S.Context))
@@ -8195,7 +8363,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator);
+ SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
DiagnosticErrorTrap Trap(Diags);
// C++0x [class.copy]p28:
@@ -8207,7 +8375,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// definition.
// The statements that form the synthesized function body.
- ASTOwningVector<Stmt*> Statements(*this);
+ SmallVector<Stmt*, 8> Statements;
// The parameter for the "other" object, which we are move from.
ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
@@ -8395,8 +8563,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- CollectableMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(CollectableMemCpyRef && "Builtin reference cannot fail");
}
}
@@ -8415,12 +8583,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- BuiltinMemCpy->getType(),
- VK_LValue, Loc, 0).take();
+ Context.BuiltinFnTy,
+ VK_RValue, Loc, 0).take();
assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
}
- ASTOwningVector<Expr*> CallArgs(*this);
+ SmallVector<Expr*, 8> CallArgs;
CallArgs.push_back(To.takeAs<Expr>());
CallArgs.push_back(From.takeAs<Expr>());
CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
@@ -8428,12 +8596,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
if (NeedsCollectableMemCpy)
Call = ActOnCallExpr(/*Scope=*/0,
CollectableMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
else
Call = ActOnCallExpr(/*Scope=*/0,
BuiltinMemCpyRef,
- Loc, move_arg(CallArgs),
+ Loc, CallArgs,
Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
@@ -8483,7 +8651,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
StmtResult Body;
{
CompoundScopeRAII CompoundScope(*this);
- Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ Body = ActOnCompoundStmt(Loc, Loc, Statements,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
@@ -8691,7 +8859,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
+ SynthesizedFunctionScope Scope(*this, CopyConstructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
@@ -8703,7 +8871,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
CopyConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
CopyConstructor->setImplicitlyDefined(true);
@@ -8874,7 +9042,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
- ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor);
+ SynthesizedFunctionScope Scope(*this, MoveConstructor);
DiagnosticErrorTrap Trap(Diags);
if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) ||
@@ -8886,7 +9054,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(),
MoveConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
MoveConstructor->setImplicitlyDefined(true);
@@ -8926,7 +9094,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
Conv->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
// Return the address of the __invoke function.
@@ -8959,7 +9127,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
{
Conv->setUsed();
- ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
// Copy-initialize the lambda object as needed to capture it.
@@ -9014,12 +9182,12 @@ static bool hasOneRealArgument(MultiExprArg Args) {
return false;
default:
- if (!Args.get()[1]->isDefaultArgument())
+ if (!Args[1]->isDefaultArgument())
return false;
// fall through
case 1:
- return !Args.get()[0]->isDefaultArgument();
+ return !Args[0]->isDefaultArgument();
}
return false;
@@ -9047,12 +9215,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// directly into the target of the omitted copy/move
if (ConstructKind == CXXConstructExpr::CK_Complete &&
Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
- Expr *SubExpr = ((Expr **)ExprArgs.get())[0];
+ Expr *SubExpr = ExprArgs[0];
Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), HadMultipleCandidates,
+ Elidable, ExprArgs, HadMultipleCandidates,
RequiresZeroInit, ConstructKind, ParenRange);
}
@@ -9066,12 +9234,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
- unsigned NumExprs = ExprArgs.size();
- Expr **Exprs = (Expr **)ExprArgs.release();
-
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
- Constructor, Elidable, Exprs, NumExprs,
+ Constructor, Elidable, ExprArgs,
HadMultipleCandidates, /*FIXME*/false,
RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
@@ -9085,7 +9250,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
// FIXME: Provide the correct paren SourceRange when available.
ExprResult TempResult =
BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- move(Exprs), HadMultipleCandidates, false,
+ Exprs, HadMultipleCandidates, false,
CXXConstructExpr::CK_Complete, SourceRange());
if (TempResult.isInvalid())
return true;
@@ -9135,11 +9300,11 @@ bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
- ASTOwningVector<Expr*> &ConvertedArgs,
+ SmallVectorImpl<Expr*> &ConvertedArgs,
bool AllowExplicit) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
unsigned NumArgs = ArgsPtr.size();
- Expr **Args = (Expr **)ArgsPtr.get();
+ Expr **Args = ArgsPtr.data();
const FunctionProtoType *Proto
= Constructor->getType()->getAs<FunctionProtoType>();
@@ -9268,7 +9433,7 @@ CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
}
static bool
-CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.deallocation]p1:
// A program is ill-formed if deallocation functions are declared in a
// namespace scope other than global scope or declared static in global
@@ -9825,7 +9990,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
/// \brief Perform semantic analysis of the given friend type declaration.
///
/// \returns A friend declaration that.
-FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
@@ -9864,7 +10029,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
diag::warn_cxx98_compat_nonclass_type_friend :
diag::ext_nonclass_type_friend)
<< T
- << SourceRange(FriendLoc, TypeRange.getEnd());
+ << TypeRange;
}
} else if (T->getAs<EnumType>()) {
Diag(FriendLoc,
@@ -9872,18 +10037,22 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
diag::warn_cxx98_compat_enum_friend :
diag::ext_enum_friend)
<< T
- << SourceRange(FriendLoc, TypeRange.getEnd());
+ << TypeRange;
}
- // C++0x [class.friend]p3:
+ // C++11 [class.friend]p3:
+ // A friend declaration that does not declare a function shall have one
+ // of the following forms:
+ // friend elaborated-type-specifier ;
+ // friend simple-type-specifier ;
+ // friend typename-specifier ;
+ if (getLangOpts().CPlusPlus0x && LocStart != FriendLoc)
+ Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T;
+
// If the type specifier in a friend declaration designates a (possibly
- // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
// the friend declaration is ignored.
-
- // FIXME: C++0x has some syntactic restrictions on friend type declarations
- // in [class.friend]p3 that we do not implement.
-
- return FriendDecl::Create(Context, CurContext, Loc, TSInfo, FriendLoc);
+ return FriendDecl::Create(Context, CurContext, LocStart, TSInfo, FriendLoc);
}
/// Handle a friend tag declaration where the scope specifier was
@@ -9901,7 +10070,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
- TempParamLists.get(),
+ TempParamLists.data(),
TempParamLists.size(),
/*friend*/ true,
isExplicitSpecialization,
@@ -9916,7 +10085,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
TempParamLists.size() - 1,
- (TemplateParameterList**) TempParamLists.release()).take();
+ TempParamLists.data()).take();
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
@@ -9929,7 +10098,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
- if (TempParamLists.get()[I]->size()) {
+ if (TempParamLists[I]->size()) {
isAllExplicitSpecializations = false;
break;
}
@@ -10076,7 +10245,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (unsigned NumTempParamLists = TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
NumTempParamLists,
- TempParams.release(),
+ TempParams.data(),
TSI,
DS.getFriendSpecLoc());
else
@@ -10318,7 +10487,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
- move(TemplateParams), AddToScope);
+ TemplateParams, AddToScope);
if (!ND) return 0;
assert(ND->getDeclContext() == DC);
@@ -10435,10 +10604,10 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// If this definition appears within the record, do the checking when
// the record is complete.
const FunctionDecl *Primary = MD;
- if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
// Find the uninstantiated declaration that actually had the '= default'
// on it.
- MD->getTemplateInstantiationPattern()->isDefined(Primary);
+ Pattern->isDefined(Primary);
if (Primary == Primary->getCanonicalDecl())
return;
@@ -10963,14 +11132,16 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
if (Ctor->isInvalidDecl())
return;
- const FunctionDecl *FNTarget = 0;
- CXXConstructorDecl *Target;
-
- // We ignore the result here since if we don't have a body, Target will be
- // null below.
- (void)Ctor->getTargetConstructor()->hasBody(FNTarget);
- Target
-= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget));
+ CXXConstructorDecl *Target = Ctor->getTargetConstructor();
+
+ // Target may not be determinable yet, for instance if this is a dependent
+ // call in an uninstantiated template.
+ if (Target) {
+ const FunctionDecl *FNTarget = 0;
+ (void)Target->hasBody(FNTarget);
+ Target = const_cast<CXXConstructorDecl*>(
+ cast_or_null<CXXConstructorDecl>(FNTarget));
+ }
CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
// Avoid dereferencing a null pointer here.
@@ -10994,17 +11165,18 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
diag::warn_delegating_ctor_cycle)
<< Ctor;
- // Don't add a note for a function delegating directo to itself.
+ // Don't add a note for a function delegating directly to itself.
if (TCanonical != Canonical)
S.Diag(Target->getLocation(), diag::note_it_delegates_to);
CXXConstructorDecl *C = Target;
while (C->getCanonicalDecl() != Canonical) {
+ const FunctionDecl *FNTarget = 0;
(void)C->getTargetConstructor()->hasBody(FNTarget);
assert(FNTarget && "Ctor cycle through bodiless function");
- C
- = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget));
+ C = const_cast<CXXConstructorDecl*>(
+ cast<CXXConstructorDecl>(FNTarget));
S.Diag(C->getLocation(), diag::note_which_delegates_to);
}
}
@@ -11027,9 +11199,8 @@ void Sema::CheckDelegatingCtorCycles() {
for (DelegatingCtorDeclsType::iterator
I = DelegatingCtorDecls.begin(ExternalSource),
E = DelegatingCtorDecls.end();
- I != E; ++I) {
- DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
- }
+ I != E; ++I)
+ DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
(*CI)->setInvalidDecl();
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 9da4d69382ef..c4e91e85015f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -282,6 +282,25 @@ void Sema::AddAnyMethodToGlobalPool(Decl *D) {
AddFactoryMethodToGlobalPool(MDecl, true);
}
+/// HasExplicitOwnershipAttr - returns true when pointer to ObjC pointer
+/// has explicit ownership attribute; false otherwise.
+static bool
+HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) {
+ QualType T = Param->getType();
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ T = PT->getPointeeType();
+ } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ T = RT->getPointeeType();
+ } else {
+ return true;
+ }
+
+ // If we have a lifetime qualifier, but it's local, we must have
+ // inferred it. So, it is implicit.
+ return !T.getLocalQualifiers().hasObjCLifetime();
+}
+
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
@@ -313,6 +332,12 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
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) <<
+ Param->getType();
+
if ((*PI)->getIdentifier())
PushOnScopeChains(*PI, FnBodyScope);
}
@@ -345,8 +370,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Warn on deprecated methods under -Wdeprecated-implementations,
// and prepare for warning on missing super calls.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) {
- if (ObjCMethodDecl *IMD =
- IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod()))
+ ObjCMethodDecl *IMD =
+ IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod());
+
+ if (IMD)
DiagnoseObjCImplementedDeprecations(*this,
dyn_cast<NamedDecl>(IMD),
MDecl->getLocation(), 0);
@@ -356,13 +383,23 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
// Only do this if the current class actually has a superclass.
if (IC->getSuperClass()) {
- getCurFunction()->ObjCShouldCallSuperDealloc =
- !(Context.getLangOpts().ObjCAutoRefCount ||
- Context.getLangOpts().getGC() == LangOptions::GCOnly) &&
- MDecl->getMethodFamily() == OMF_dealloc;
- getCurFunction()->ObjCShouldCallSuperFinalize =
- Context.getLangOpts().getGC() != LangOptions::NonGC &&
- MDecl->getMethodFamily() == OMF_finalize;
+ ObjCMethodFamily Family = MDecl->getMethodFamily();
+ if (Family == OMF_dealloc) {
+ if (!(getLangOpts().ObjCAutoRefCount ||
+ getLangOpts().getGC() == LangOptions::GCOnly))
+ getCurFunction()->ObjCShouldCallSuper = true;
+
+ } else if (Family == OMF_finalize) {
+ if (Context.getLangOpts().getGC() != LangOptions::NonGC)
+ getCurFunction()->ObjCShouldCallSuper = true;
+
+ } else {
+ const ObjCMethodDecl *SuperMethod =
+ IC->getSuperClass()->lookupMethod(MDecl->getSelector(),
+ MDecl->isInstanceMethod());
+ getCurFunction()->ObjCShouldCallSuper =
+ (SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
+ }
}
}
}
@@ -510,7 +547,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Check then save referenced protocols.
if (NumProtoRefs) {
- IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ IDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
IDecl->setEndOfDefinitionLoc(EndProtoLoc);
}
@@ -652,7 +689,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
- PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ PDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
}
@@ -819,11 +856,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
CurContext->addDecl(CDecl);
if (NumProtoRefs) {
- CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
// Protocols in the class extension belong to the class.
if (CDecl->IsClassExtension())
- IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
+ IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl*const*)ProtoRefs,
NumProtoRefs, Context);
}
@@ -1545,9 +1582,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
- !method->isSynthesized() && !InsMap.count(method->getSelector()) &&
- (!Super ||
- !Super->lookupInstanceMethod(method->getSelector()))) {
+ !method->isPropertyAccessor() &&
+ !InsMap.count(method->getSelector()) &&
+ (!Super || !Super->lookupInstanceMethod(method->getSelector()))) {
// If a method is not implemented in the category implementation but
// has been declared in its primary class, superclass,
// or in one of their protocols, no need to issue the warning.
@@ -1560,7 +1597,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector(),
true /*shallowCategoryLookup*/))
- if (C || MethodInClass->isSynthesized())
+ if (C || MethodInClass->isPropertyAccessor())
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
@@ -1621,7 +1658,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (InsMapSeen.count((*I)->getSelector()))
continue;
InsMapSeen.insert((*I)->getSelector());
- if (!(*I)->isSynthesized() &&
+ if (!(*I)->isPropertyAccessor() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
@@ -1638,7 +1675,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
- else if (!MethodDecl->isSynthesized())
+ else if (!MethodDecl->isPropertyAccessor())
WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
}
@@ -1672,14 +1709,26 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
}
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
- // Also methods in class extensions need be looked at next.
- for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
- MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false,
- WarnCategoryMethodImpl);
+ // when checking that methods in implementation match their declaration,
+ // i.e. when WarnCategoryMethodImpl is false, check declarations in class
+ // extension; as well as those in categories.
+ if (!WarnCategoryMethodImpl)
+ for (const ObjCCategoryDecl *CDeclChain = I->getCategoryList();
+ CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ const_cast<ObjCCategoryDecl *>(CDeclChain),
+ IncompleteImpl, false,
+ WarnCategoryMethodImpl);
+ else
+ // Also methods in class extensions need be looked at next.
+ for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
+ ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ IMPDecl,
+ const_cast<ObjCCategoryDecl *>(ClsExtDecl),
+ IncompleteImpl, false,
+ WarnCategoryMethodImpl);
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -2339,11 +2388,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) {
if (ObjCMethodDecl *GetterMethod =
CExtDecl->getInstanceMethod(Property->getGetterName()))
- GetterMethod->setSynthesized(true);
+ GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
if (ObjCMethodDecl *SetterMethod =
CExtDecl->getInstanceMethod(Property->getSetterName()))
- SetterMethod->setSynthesized(true);
+ SetterMethod->setPropertyAccessor(true);
}
}
}
@@ -2435,26 +2484,49 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
}
static inline
+unsigned countAlignAttr(const AttrVec &A) {
+ unsigned count=0;
+ for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i)
+ if ((*i)->getKind() == attr::Aligned)
+ ++count;
+ return count;
+}
+
+static inline
bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
const AttrVec &A) {
// If method is only declared in implementation (private method),
// No need to issue any diagnostics on method definition with attributes.
if (!IMD)
return false;
-
+
// method declared in interface has no attribute.
- // But implementation has attributes. This is invalid
+ // But implementation has attributes. This is invalid.
+ // Except when implementation has 'Align' attribute which is
+ // immaterial to method declared in interface.
if (!IMD->hasAttrs())
- return true;
+ return (A.size() > countAlignAttr(A));
const AttrVec &D = IMD->getAttrs();
- if (D.size() != A.size())
- return true;
+ unsigned countAlignOnImpl = countAlignAttr(A);
+ if (!countAlignOnImpl && (A.size() != D.size()))
+ return true;
+ else if (countAlignOnImpl) {
+ unsigned countAlignOnDecl = countAlignAttr(D);
+ if (countAlignOnDecl && (A.size() != D.size()))
+ return true;
+ else if (!countAlignOnDecl &&
+ ((A.size()-countAlignOnImpl) != D.size()))
+ return true;
+ }
+
// attributes on method declaration and definition must match exactly.
// Note that we have at most a couple of attributes on methods, so this
// n*n search is good enough.
for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) {
+ if ((*i)->getKind() == attr::Aligned)
+ continue;
bool match = false;
for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) {
if ((*i)->getKind() == (*i1)->getKind()) {
@@ -2465,6 +2537,7 @@ bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
if (!match)
return true;
}
+
return false;
}
@@ -2525,7 +2598,7 @@ public:
// with this selector before.
Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector);
if (it == S.MethodPool.end()) {
- if (!S.ExternalSource) return;
+ if (!S.getExternalSource()) return;
S.ReadMethodPool(selector);
it = S.MethodPool.find(selector);
@@ -2767,7 +2840,7 @@ Decl *Sema::ActOnMethodDeclaration(
ResultTInfo,
CurContext,
MethodType == tok::minus, isVariadic,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional
? ObjCMethodDecl::Optional
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e6266fb0863a..e1f4888d632f 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -120,6 +120,24 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
+/// Determine whether a function has an implicitly-generated exception
+/// specification.
+static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
+ if (!isa<CXXDestructorDecl>(Decl) &&
+ Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
+
+ // If the user didn't declare the function, its exception specification must
+ // be implicit.
+ if (!Decl->getTypeSourceInfo())
+ return true;
+
+ const FunctionProtoType *Ty =
+ Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
+ return !Ty->hasExceptionSpec();
+}
+
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
@@ -129,25 +147,35 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
- if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
- PDiag(diag::note_previous_declaration),
- Old->getType()->getAs<FunctionProtoType>(),
- Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(),
- New->getLocation(),
- &MissingExceptionSpecification,
- &MissingEmptyExceptionSpecification,
- /*AllowNoexceptAllMatchWithNoSpec=*/true,
- IsOperatorNew))
+ // Check the types as written: they must match before any exception
+ // specification adjustment is applied.
+ if (!CheckEquivalentExceptionSpec(
+ PDiag(DiagID), PDiag(diag::note_previous_declaration),
+ Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
+ &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
+ /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
+ // C++11 [except.spec]p4 [DR1492]:
+ // If a declaration of a function has an implicit
+ // exception-specification, other declarations of the function shall
+ // not specify an exception-specification.
+ if (getLangOpts().CPlusPlus0x &&
+ hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
+ Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
+ << hasImplicitExceptionSpec(Old);
+ if (!Old->getLocation().isInvalid())
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
return false;
+ }
// The failure was something other than an empty exception
// specification; return an error.
if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
return true;
- const FunctionProtoType *NewProto
- = New->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *NewProto =
+ New->getType()->getAs<FunctionProtoType>();
// The new function declaration is only missing an empty exception
// specification "throw()". If the throw() specification came from a
@@ -172,8 +200,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
}
if (MissingExceptionSpecification && NewProto) {
- const FunctionProtoType *OldProto
- = Old->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *OldProto =
+ Old->getType()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
@@ -290,14 +318,17 @@ bool Sema::CheckEquivalentExceptionSpec(
unsigned DiagID = diag::err_mismatched_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
- return CheckEquivalentExceptionSpec(
- PDiag(DiagID),
+ return CheckEquivalentExceptionSpec(PDiag(DiagID),
PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}
/// CheckEquivalentExceptionSpec - Check if the two types have compatible
/// exception specifications. See C++ [except.spec]p3.
+///
+/// \return \c false if the exception specifications match, \c true if there is
+/// a problem. If \c true is returned, either a diagnostic has already been
+/// produced or \c *MissingExceptionSpecification is set to \c true.
bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
const PartialDiagnostic & NoteID,
const FunctionProtoType *Old,
@@ -1029,6 +1060,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::PseudoObjectExprClass:
case Expr::SubstNonTypeTemplateParmExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::FunctionParmPackExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3875ba171366..bf4abfcb7460 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -66,6 +66,15 @@ bool Sema::CanUseDecl(NamedDecl *D) {
return true;
}
+static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
+ // Warn if this is used but marked unused.
+ if (D->hasAttr<UnusedAttr>()) {
+ const Decl *DC = cast<Decl>(S.getCurObjCLexicalContext());
+ if (!DC->hasAttr<UnusedAttr>())
+ S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ }
+}
+
static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass) {
@@ -78,6 +87,17 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
Result = TheEnumDecl->getAvailability(&Message);
}
+
+ const ObjCPropertyDecl *ObjCPDecl = 0;
+ if (Result == AR_Deprecated || Result == AR_Unavailable) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+ AvailabilityResult PDeclResult = PD->getAvailability(0);
+ if (PDeclResult == Result)
+ ObjCPDecl = PD;
+ }
+ }
+ }
switch (Result) {
case AR_Available:
@@ -85,23 +105,30 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
break;
case AR_Deprecated:
- S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass);
+ S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass, ObjCPDecl);
break;
case AR_Unavailable:
if (S.getCurContextAvailability() != AR_Unavailable) {
if (Message.empty()) {
- if (!UnknownObjCClass)
+ if (!UnknownObjCClass) {
S.Diag(Loc, diag::err_unavailable) << D->getDeclName();
+ if (ObjCPDecl)
+ S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
+ << ObjCPDecl->getDeclName() << 1;
+ }
else
S.Diag(Loc, diag::warn_unavailable_fwdclass_message)
<< D->getDeclName();
}
- else
+ else
S.Diag(Loc, diag::err_unavailable_message)
<< D->getDeclName() << Message;
- S.Diag(D->getLocation(), diag::note_unavailable_here)
- << isa<FunctionDecl>(D) << false;
+ S.Diag(D->getLocation(), diag::note_unavailable_here)
+ << isa<FunctionDecl>(D) << false;
+ if (ObjCPDecl)
+ S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
+ << ObjCPDecl->getDeclName() << 1;
}
break;
}
@@ -250,9 +277,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
- // Warn if this is used but marked unused.
- if (D->hasAttr<UnusedAttr>())
- Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ DiagnoseUnusedOfDecl(*this, D, Loc);
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
@@ -502,7 +527,7 @@ ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
Res = DefaultLvalueConversion(Res.take());
if (Res.isInvalid())
return ExprError();
- return move(Res);
+ return Res;
}
@@ -1098,8 +1123,8 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
unsigned NumAssocs = ArgTypes.size();
assert(NumAssocs == ArgExprs.size());
- ParsedType *ParsedTypes = ArgTypes.release();
- Expr **Exprs = ArgExprs.release();
+ ParsedType *ParsedTypes = ArgTypes.data();
+ Expr **Exprs = ArgExprs.data();
TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
@@ -1185,8 +1210,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
if (IsResultDependent)
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- Types, Exprs, NumAssocs, DefaultLoc,
- RParenLoc, ContainsUnexpandedParameterPack));
+ llvm::makeArrayRef(Types, NumAssocs),
+ llvm::makeArrayRef(Exprs, NumAssocs),
+ DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack));
SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
@@ -1240,8 +1266,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
- Types, Exprs, NumAssocs, DefaultLoc,
- RParenLoc, ContainsUnexpandedParameterPack,
+ llvm::makeArrayRef(Types, NumAssocs),
+ llvm::makeArrayRef(Exprs, NumAssocs),
+ DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack,
ResultIndex));
}
@@ -1402,6 +1429,15 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
MarkDeclRefReferenced(E);
+ if (getLangOpts().ObjCARCWeak && isa<VarDecl>(D) &&
+ Ty.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ E->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(E);
+ }
+
// Just in case we're building an illegal pointer-to-member.
FieldDecl *FD = dyn_cast<FieldDecl>(D);
if (FD && FD->isBitField())
@@ -1428,11 +1464,9 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc);
Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- Id.TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(Id.TemplateId->getTemplateArgs(),
Id.TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr, Buffer);
- TemplateArgsPtr.release();
TemplateName TName = Id.TemplateId->Template.get();
SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc;
@@ -1606,7 +1640,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << CorrectedQuotedStr
<< SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
if (ND)
Diag(ND->getLocation(), diag::note_previous_decl)
<< CorrectedQuotedStr;
@@ -1797,7 +1832,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// lookup fails and no expression will be built to reference it.
if (!E.isInvalid() && !E.get())
return ExprError();
- return move(E);
+ return E;
}
}
}
@@ -1860,9 +1895,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
/// this path.
ExprResult
Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo) {
- DeclContext *DC;
- if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
+ const DeclarationNameInfo &NameInfo,
+ bool IsAddressOfOperand) {
+ DeclContext *DC = computeDeclContext(SS, false);
+ if (!DC)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
NameInfo, /*TemplateArgs=*/0);
@@ -1875,13 +1911,26 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
if (R.isAmbiguous())
return ExprError();
+ if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/0);
+
if (R.empty()) {
Diag(NameInfo.getLoc(), diag::err_no_member)
<< NameInfo.getName() << DC << SS.getRange();
return ExprError();
}
- return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
+ // Defend against this resolving to an implicit member access. We usually
+ // won't get here if this might be a legitimate a class member (we end up in
+ // BuildMemberReferenceExpr instead), but this can be valid if we're forming
+ // a pointer-to-member or in an unevaluated context in C++11.
+ if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand)
+ return BuildPossibleImplicitMemberExpr(SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ R, /*TemplateArgs=*/0);
+
+ return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
/// LookupInObjCMethod - The parser has read a name in, and Sema has
@@ -1965,9 +2014,25 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCMethodFamily MF = CurMethod->getMethodFamily();
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize)
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
- return Owned(new (Context)
- ObjCIvarRefExpr(IV, IV->getType(), Loc,
- SelfExpr.take(), true, true));
+
+ ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ Loc,
+ SelfExpr.take(),
+ true, true);
+
+ if (getLangOpts().ObjCAutoRefCount) {
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ if (CurContext->isClosure())
+ Diag(Loc, diag::warn_implicitly_retains_self)
+ << FixItHint::CreateInsertion(Loc, "self->");
+ }
+
+ return Owned(Result);
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2416,6 +2481,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
case Decl::Function: {
+ if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+ type = Context.BuiltinFnTy;
+ valueKind = VK_RValue;
+ break;
+ }
+ }
+
const FunctionType *fty = type->castAs<FunctionType>();
// If we're referring to a function with an __unknown_anytype
@@ -2615,19 +2688,20 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
return ActOnIntegerConstant(Tok.getLocation(), Val-'0');
}
- SmallString<512> IntegerBuffer;
- // Add padding so that NumericLiteralParser can overread by one character.
- IntegerBuffer.resize(Tok.getLength()+1);
- const char *ThisTokBegin = &IntegerBuffer[0];
+ SmallString<128> SpellingBuffer;
+ // NumericLiteralParser wants to overread by one character. Add padding to
+ // the buffer in case the token is copied to the buffer. If getSpelling()
+ // returns a StringRef to the memory buffer, it should have a null char at
+ // the EOF, so it is also safe.
+ SpellingBuffer.resize(Tok.getLength() + 1);
// Get the spelling of the token, which eliminates trigraphs, etc.
bool Invalid = false;
- unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid);
+ StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid);
if (Invalid)
return ExprError();
- NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength,
- Tok.getLocation(), PP);
+ NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP);
if (Literal.hadError)
return ExprError();
@@ -2693,7 +2767,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Context.CharTy, llvm::APInt(32, Length + 1),
ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
- Context, StringRef(ThisTokBegin, Length), StringLiteral::Ascii,
+ Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
return BuildLiteralOperatorCall(R, OpNameInfo,
llvm::makeArrayRef(&Lit, 1), TokLoc);
@@ -2709,7 +2783,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType();
llvm::APSInt Value(CharBits, CharIsUnsigned);
for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
- Value = ThisTokBegin[I];
+ Value = TokSpelling[I];
TemplateArgument Arg(Context, Value, Context.CharTy);
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
@@ -2747,11 +2821,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
QualType Ty;
- // long long is a C99 feature.
- if (!getLangOpts().C99 && Literal.isLongLong)
- Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!getLangOpts().C99 && Literal.isLongLong) {
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ Diag(Tok.getLocation(), diag::ext_c99_longlong);
+ }
// Get the value in the widest-possible width.
unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
@@ -3140,7 +3218,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
Expr *ArgEx = (Expr *)TyOrEx;
ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind);
- return move(Result);
+ return Result;
}
static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
@@ -3167,7 +3245,7 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
ExprResult PR = S.CheckPlaceholderExpr(V.get());
if (PR.isInvalid()) return QualType();
if (PR.get() != V.get()) {
- V = move(PR);
+ V = PR;
return CheckRealImagOperand(S, V, Loc, IsReal);
}
@@ -3442,8 +3520,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *ResultE = Result.takeAs<Expr>();
InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1);
- Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &ResultE, 1));
+ Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
if (Result.isInvalid())
return ExprError();
@@ -3776,28 +3853,25 @@ ExprResult
Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig) {
- unsigned NumArgs = ArgExprs.size();
-
// Since this might be a postfix expression, get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn);
if (Result.isInvalid()) return ExprError();
Fn = Result.take();
- Expr **Args = ArgExprs.release();
-
if (getLangOpts().CPlusPlus) {
// If this is a pseudo-destructor expression, build the call immediately.
if (isa<CXXPseudoDestructorExpr>(Fn)) {
- if (NumArgs > 0) {
+ if (!ArgExprs.empty()) {
// Pseudo-destructor calls should not have any arguments.
Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
<< FixItHint::CreateRemoval(
- SourceRange(Args[0]->getLocStart(),
- Args[NumArgs-1]->getLocEnd()));
+ SourceRange(ArgExprs[0]->getLocStart(),
+ ArgExprs.back()->getLocEnd()));
}
- return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
- VK_RValue, RParenLoc));
+ return Owned(new (Context) CallExpr(Context, Fn, MultiExprArg(),
+ Context.VoidTy, VK_RValue,
+ RParenLoc));
}
// Determine whether this is a dependent call inside a C++ template,
@@ -3807,17 +3881,16 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
bool Dependent = false;
if (Fn->isTypeDependent())
Dependent = true;
- else if (Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Args, NumArgs)))
+ else if (Expr::hasAnyTypeDependentArguments(ArgExprs))
Dependent = true;
if (Dependent) {
if (ExecConfig) {
return Owned(new (Context) CUDAKernelCallExpr(
- Context, Fn, cast<CallExpr>(ExecConfig), Args, NumArgs,
+ Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs,
Context.DependentTy, VK_RValue, RParenLoc));
} else {
- return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs,
+ return Owned(new (Context) CallExpr(Context, Fn, ArgExprs,
Context.DependentTy, VK_RValue,
RParenLoc));
}
@@ -3825,8 +3898,9 @@ 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, Args, NumArgs,
- RParenLoc));
+ return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc,
+ ArgExprs.data(),
+ ArgExprs.size(), RParenLoc));
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
@@ -3835,8 +3909,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
}
if (Fn->getType() == Context.BoundMemberTy) {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc);
}
}
@@ -3849,11 +3923,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, Args, NumArgs,
- RParenLoc, ExecConfig);
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc, ExecConfig);
} else {
- return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- RParenLoc);
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc);
}
}
}
@@ -3877,8 +3951,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
else if (isa<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
- return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc,
- ExecConfig, IsExecConfig);
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs.data(),
+ ArgExprs.size(), RParenLoc, ExecConfig,
+ IsExecConfig);
}
ExprResult
@@ -3932,9 +4007,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
SourceLocation RParenLoc,
Expr *Config, bool IsExecConfig) {
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+ unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
// Promote the function operand.
- ExprResult Result = UsualUnaryConversions(Fn);
+ // We special-case function promotion here because we only allow promoting
+ // builtin functions to function pointers in the callee of a call.
+ ExprResult Result;
+ if (BuiltinID &&
+ Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) {
+ Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()),
+ CK_BuiltinFnToFnPtr).take();
+ } else {
+ Result = UsualUnaryConversions(Fn);
+ }
if (Result.isInvalid())
return ExprError();
Fn = Result.take();
@@ -3945,19 +4030,17 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Config)
TheCall = new (Context) CUDAKernelCallExpr(Context, Fn,
cast<CallExpr>(Config),
- Args, NumArgs,
+ llvm::makeArrayRef(Args,NumArgs),
Context.BoolTy,
VK_RValue,
RParenLoc);
else
TheCall = new (Context) CallExpr(Context, Fn,
- Args, NumArgs,
+ llvm::makeArrayRef(Args, NumArgs),
Context.BoolTy,
VK_RValue,
RParenLoc);
- unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
-
// Bail out early if calling a builtin with custom typechecking.
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
@@ -4143,9 +4226,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
SourceRange(LParenLoc, RParenLoc),
/*InitList=*/true);
InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &LiteralExpr, 1),
- &literalType);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr,
+ &literalType);
if (Result.isInvalid())
return ExprError();
LiteralExpr = Result.get();
@@ -4167,28 +4249,25 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
- unsigned NumInit = InitArgList.size();
- Expr **InitList = InitArgList.release();
-
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
- for (unsigned I = 0; I != NumInit; ++I) {
- if (InitList[I]->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(InitList[I]);
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (InitArgList[I]->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(InitArgList[I]);
// Ignore failures; dropping the entire initializer list because
// of one failure would be terrible for indexing/etc.
if (result.isInvalid()) continue;
- InitList[I] = result.take();
+ InitArgList[I] = result.take();
}
}
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
- InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList,
- NumInit, RBraceLoc);
+ InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
+ RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@@ -4575,8 +4654,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc,
- &initExprs[0],
- initExprs.size(), RParenLoc);
+ initExprs, RParenLoc);
initE->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
}
@@ -4603,10 +4681,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
- unsigned nexprs = Val.size();
- Expr **exprs = reinterpret_cast<Expr**>(Val.release());
- assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
- Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
+ assert(Val.data() != 0 && "ActOnParenOrParenListExpr() missing expr list");
+ Expr *expr = new (Context) ParenListExpr(Context, L, Val, R);
return Owned(expr);
}
@@ -4884,11 +4960,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult LHSResult = CheckPlaceholderExpr(LHS.get());
if (!LHSResult.isUsable()) return QualType();
- LHS = move(LHSResult);
+ LHS = LHSResult;
ExprResult RHSResult = CheckPlaceholderExpr(RHS.get());
if (!RHSResult.isUsable()) return QualType();
- RHS = move(RHSResult);
+ RHS = RHSResult;
// C++ is sufficiently different to merit its own checker.
if (getLangOpts().CPlusPlus)
@@ -5247,7 +5323,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
<< BinaryOperator::getOpcodeStr(CondOpcode);
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_conditional_silence)
+ Self.PDiag(diag::note_precedence_silence)
<< BinaryOperator::getOpcodeStr(CondOpcode),
SourceRange(Condition->getLocStart(), Condition->getLocEnd()));
@@ -5811,8 +5887,7 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C,
// of the transparent union.
Expr *E = EResult.take();
InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
- &E, 1,
- SourceLocation());
+ E, SourceLocation());
Initializer->setType(UnionType);
Initializer->setInitializedFieldInUnion(Field);
@@ -5910,7 +5985,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
!CheckObjCARCUnavailableWeakConversion(LHSType,
RHS.get()->getType()))
result = IncompatibleObjCWeakRef;
- RHS = move(Res);
+ RHS = Res;
return result;
}
@@ -6708,7 +6783,7 @@ static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc,
}
static bool isObjCObjectLiteral(ExprResult &E) {
- switch (E.get()->getStmtClass()) {
+ switch (E.get()->IgnoreParenImpCasts()->getStmtClass()) {
case Stmt::ObjCArrayLiteralClass:
case Stmt::ObjCDictionaryLiteralClass:
case Stmt::ObjCStringLiteralClass:
@@ -6800,6 +6875,7 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
LK_String
} LiteralKind;
+ Literal = Literal->IgnoreParenImpCasts();
switch (Literal->getStmtClass()) {
case Stmt::ObjCStringLiteralClass:
// "string literal"
@@ -7202,7 +7278,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
(LHSType->isIntegerType() && RHSType->isAnyPointerType())) {
unsigned DiagID = 0;
bool isError = false;
- if ((LHSIsNull && LHSType->isIntegerType()) ||
+ if (LangOpts.DebuggerSupport) {
+ // Under a debugger, allow the comparison of pointers to integers,
+ // since users tend to want to compare addresses.
+ } else if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
@@ -7419,12 +7498,12 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
if (LHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
- LHS = move(LHSRes);
+ LHS = LHSRes;
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
if (RHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
- RHS = move(RHSRes);
+ RHS = RHSRes;
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
@@ -7683,10 +7762,31 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
}
if (ConvTy == Compatible) {
- if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
- checkRetainCycles(LHSExpr, RHS.get());
- else if (getLangOpts().ObjCAutoRefCount)
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Warn about retain cycles where a block captures the LHS, but
+ // not if the LHS is a simple variable into which the block is
+ // being stored...unless that variable can be captured by reference!
+ const Expr *InnerLHS = LHSExpr->IgnoreParenCasts();
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS);
+ if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>())
+ checkRetainCycles(LHSExpr, RHS.get());
+
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ RHS.get()->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(RHS.get());
+
+ } else if (getLangOpts().ObjCAutoRefCount) {
checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
+ }
}
} else {
// Compound assignment "x += y"
@@ -7972,8 +8072,16 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
- S.Diag(OpLoc, diag::err_unqualified_pointer_member_function)
- << op->getSourceRange();
+ if (MD->getParent()->getName().empty())
+ S.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)
+ << op->getSourceRange()
+ << FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual);
+ }
}
return S.Context.getMemberPointerType(op->getType(),
@@ -8216,8 +8324,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(LHSExpr->getType());
InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(&RHSExpr, 1));
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr);
if (Init.isInvalid())
return Init;
RHSExpr = Init.take();
@@ -8340,7 +8447,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
- ResultTy, VK, OK, OpLoc));
+ ResultTy, VK, OK, OpLoc,
+ FPFeatures.fp_contract));
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
@@ -8348,7 +8456,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, CompLHSTy,
- CompResultTy, OpLoc));
+ CompResultTy, OpLoc,
+ FPFeatures.fp_contract));
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -8383,8 +8492,8 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(),
OpLoc)
: SourceRange(OpLoc, RHSExpr->getLocEnd());
- std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
- : BinOp::getOpcodeStr(RHSopc);
+ StringRef OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
+ : BinOp::getOpcodeStr(RHSopc);
SourceRange ParensRange = isLeftComp ?
SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(),
RHSExpr->getLocEnd())
@@ -8394,7 +8503,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
<< DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr,
+ Self.PDiag(diag::note_precedence_silence) << OpStr,
(isLeftComp ? LHSExpr : RHSExpr)->getSourceRange());
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
@@ -8411,7 +8520,8 @@ EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc,
Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or)
<< Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence),
+ Self.PDiag(diag::note_precedence_silence)
+ << Bop->getOpcodeStr(),
Bop->getSourceRange());
}
@@ -8425,7 +8535,8 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or)
<< Bop->getSourceRange() << OpLoc;
SuggestParentheses(Self, Bop->getOperatorLoc(),
- Self.PDiag(diag::note_logical_and_in_logical_or_silence),
+ Self.PDiag(diag::note_precedence_silence)
+ << Bop->getOpcodeStr(),
Bop->getSourceRange());
}
@@ -8489,6 +8600,20 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc,
}
}
+static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc,
+ Expr *SubExpr, StringRef Shift) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(SubExpr)) {
+ if (Bop->getOpcode() == BO_Add || Bop->getOpcode() == BO_Sub) {
+ StringRef Op = Bop->getOpcodeStr();
+ S.Diag(Bop->getOperatorLoc(), diag::warn_addition_in_bitshift)
+ << Bop->getSourceRange() << OpLoc << Shift << Op;
+ SuggestParentheses(S, Bop->getOperatorLoc(),
+ S.PDiag(diag::note_precedence_silence) << Op,
+ Bop->getSourceRange());
+ }
+ }
+}
+
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
/// precedence.
static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
@@ -8510,6 +8635,13 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr);
DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr);
}
+
+ if ((Opc == BO_Shl && LHSExpr->getType()->isIntegralType(Self.getASTContext()))
+ || Opc == BO_Shr) {
+ StringRef Shift = BinaryOperator::getOpcodeStr(Opc);
+ DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift);
+ DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift);
+ }
}
// Binary Operators. 'Tok' is the token for the operator.
@@ -8647,6 +8779,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ if (Input.isInvalid()) return ExprError();
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
}
@@ -9147,8 +9280,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
}
return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc,
- TInfo, Comps.data(), Comps.size(),
- Exprs.data(), Exprs.size(), RParenLoc));
+ TInfo, Comps, Exprs, RParenLoc));
}
ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
@@ -9526,6 +9658,16 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
if (Result.isInvalid())
return ExprError();
E = Result.take();
+ } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
+ // If va_list is a record type and we are compiling in C++ mode,
+ // check the argument using reference binding.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context,
+ Context.getLValueReferenceType(VaListType), false);
+ ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
+ if (Init.isInvalid())
+ return ExprError();
+ E = Init.takeAs<Expr>();
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
@@ -10094,6 +10236,14 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
+void
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ ReuseLambdaContextDecl_t,
+ bool IsDecltype) {
+ Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+ PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype);
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
@@ -10191,15 +10341,44 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
Func->setReferenced();
- // Don't mark this function as used multiple times, unless it's a constexpr
- // function which we need to instantiate.
- if (Func->isUsed(false) &&
- !(Func->isConstexpr() && !Func->getBody() &&
- Func->isImplicitlyInstantiable()))
- return;
-
- if (!IsPotentiallyEvaluatedContext(*this))
- return;
+ // C++11 [basic.def.odr]p3:
+ // A function whose name appears as a potentially-evaluated expression is
+ // odr-used if it is the unique lookup result or the selected member of a
+ // set of overloaded functions [...].
+ //
+ // We (incorrectly) mark overload resolution as an unevaluated context, so we
+ // can just check that here. Skip the rest of this function if we've already
+ // marked the function as used.
+ if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) {
+ // C++11 [temp.inst]p3:
+ // Unless a function template specialization has been explicitly
+ // instantiated or explicitly specialized, the function template
+ // specialization is implicitly instantiated when the specialization is
+ // referenced in a context that requires a function definition to exist.
+ //
+ // We consider constexpr function templates to be referenced in a context
+ // that requires a definition to exist whenever they are referenced.
+ //
+ // FIXME: This instantiates constexpr functions too frequently. If this is
+ // really an unevaluated context (and we're not just in the definition of a
+ // function template or overload resolution or other cases which we
+ // incorrectly consider to be unevaluated contexts), and we're not in a
+ // subexpression which we actually need to evaluate (for instance, a
+ // template argument, array bound or an expression in a braced-init-list),
+ // we are not permitted to instantiate this constexpr function definition.
+ //
+ // FIXME: This also implicitly defines special members too frequently. They
+ // are only supposed to be implicitly defined if they are odr-used, but they
+ // are not odr-used from constant expressions in unevaluated contexts.
+ // However, they cannot be referenced if they are deleted, and they are
+ // deleted whenever the implicit definition of the special member would
+ // fail.
+ if (!Func->isConstexpr() || Func->getBody())
+ return;
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
+ if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided()))
+ return;
+ }
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
@@ -10469,8 +10648,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1);
ExprResult Result(true);
if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1))
- Result = Init.Perform(S, Entities.back(), InitKind,
- MultiExprArg(S, &Ref, 1));
+ Result = Init.Perform(S, Entities.back(), InitKind, Ref);
// If this initialization requires any cleanups (e.g., due to a
// default argument to a copy constructor), note that for the
@@ -10886,20 +11064,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
- // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
- // an object that satisfies the requirements for appearing in a
- // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
+ // 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)
// is immediately applied." We check the first part here, and
// Sema::UpdateMarkingForLValueToRValue deals with the second part.
// Note that we use the C++11 definition everywhere because nothing in
- // C++03 depends on whether we get the C++03 version correct. This does not
- // apply to references, since they are not objects.
+ // 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->getType()->isReferenceType() &&
+ if (E && !isa<ParmVarDecl>(Var) &&
Var->isUsableInConstantExpressions(SemaRef.Context) &&
- Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
- SemaRef.MaybeODRUseExprs.insert(E);
- else
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {
+ if (!Var->getType()->isReferenceType())
+ SemaRef.MaybeODRUseExprs.insert(E);
+ } else
MarkVarDeclODRUsed(SemaRef, Var, Loc);
}
@@ -11205,7 +11384,9 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
IsOrAssign = Op->getOperator() == OO_PipeEqual;
Loc = Op->getOperatorLoc();
- } else {
+ } else if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ return DiagnoseAssignmentAsCondition(POE->getSyntacticForm());
+ else {
// Not an assignment.
return;
}
@@ -11759,6 +11940,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::PseudoObject:
return checkPseudoObjectRValue(E);
+ case BuiltinType::BuiltinFn:
+ Diag(E->getLocStart(), diag::err_builtin_fn_use);
+ return ExprError();
+
// Everything else should be impossible.
#define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id:
@@ -11783,6 +11968,18 @@ ExprResult
Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) &&
"Unknown Objective-C Boolean value!");
+ QualType BoolT = Context.ObjCBuiltinBoolTy;
+ if (!Context.getBOOLDecl()) {
+ LookupResult Result(*this, &Context.Idents.get("BOOL"), OpLoc,
+ Sema::LookupOrdinaryName);
+ if (LookupName(Result, getCurScope()) && Result.isSingleResult()) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+ Context.setBOOLDecl(TD);
+ }
+ }
+ if (Context.getBOOLDecl())
+ BoolT = Context.getBOOLType();
return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes,
- Context.ObjCBuiltinBoolTy, OpLoc));
+ BoolT, OpLoc));
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 27402599a401..0919bc5b6fa4 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -410,33 +410,13 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc);
}
-/// Retrieve the UuidAttr associated with QT.
-static UuidAttr *GetUuidAttrOfType(QualType QT) {
- // 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();
-
- // Loop all record redeclaration looking for an uuid attribute.
- CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
- if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
- return Uuid;
- }
-
- return 0;
-}
-
/// \brief Build a Microsoft __uuidof expression with a type operand.
ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
if (!Operand->getType()->isDependentType()) {
- if (!GetUuidAttrOfType(Operand->getType()))
+ if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType()))
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
}
@@ -452,7 +432,7 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
Expr *E,
SourceLocation RParenLoc) {
if (!E->getType()->isDependentType()) {
- if (!GetUuidAttrOfType(E->getType()) &&
+ if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType()) &&
!E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
}
@@ -808,21 +788,18 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
MultiExprArg exprs,
SourceLocation RParenLoc) {
QualType Ty = TInfo->getType();
- unsigned NumExprs = exprs.size();
- Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
- if (Ty->isDependentType() ||
- CallExpr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Exprs, NumExprs))) {
- exprs.release();
-
+ if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(exprs)) {
return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo,
LParenLoc,
- Exprs, NumExprs,
+ exprs,
RParenLoc));
}
+ unsigned NumExprs = exprs.size();
+ Expr **Exprs = exprs.data();
+
bool ListInitialization = LParenLoc.isInvalid();
assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0])))
&& "List initialization must have initializer list as expression.");
@@ -835,7 +812,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// corresponding cast expression.
if (NumExprs == 1 && !ListInitialization) {
Expr *Arg = Exprs[0];
- exprs.release();
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
}
@@ -865,7 +841,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
: InitializationKind::CreateValue(TyBeginLoc,
LParenLoc, RParenLoc);
InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs));
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, exprs);
if (!Result.isInvalid() && ListInitialization &&
isa<InitListExpr>(Result.get())) {
@@ -881,7 +857,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
}
// FIXME: Improve AST representation?
- return move(Result);
+ return Result;
}
/// doesUsualArrayDeleteWantSize - Answers whether the usual
@@ -1011,9 +987,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
- return BuildCXXNew(StartLoc, UseGlobal,
+ return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ PlacementArgs,
PlacementRParen,
TypeIdParens,
AllocType,
@@ -1044,7 +1020,7 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
}
ExprResult
-Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
+Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
@@ -1056,6 +1032,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
Expr *Initializer,
bool TypeMayContainAuto) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
+ SourceLocation StartLoc = Range.getBegin();
CXXNewExpr::InitializationStyle initStyle;
if (DirectInitRange.isValid()) {
@@ -1279,21 +1256,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- // ARC: warn about ABI issues.
- if (getLangOpts().ObjCAutoRefCount) {
- QualType BaseAllocType = Context.getBaseElementType(AllocType);
- if (BaseAllocType.hasStrongOrWeakObjCLifetime())
- Diag(StartLoc, diag::warn_err_new_delete_object_array)
- << 0 << BaseAllocType;
- }
-
// Note that we do *not* convert the argument in any way. It can
// be signed, larger than size_t, whatever.
}
FunctionDecl *OperatorNew = 0;
FunctionDecl *OperatorDelete = 0;
- Expr **PlaceArgs = (Expr**)PlacementArgs.get();
+ Expr **PlaceArgs = PlacementArgs.data();
unsigned NumPlaceArgs = PlacementArgs.size();
if (!AllocType->isDependentType() &&
@@ -1432,15 +1401,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- PlacementArgs.release();
-
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
OperatorDelete,
UsualArrayDeleteWantsSize,
- PlaceArgs, NumPlaceArgs, TypeIdParens,
+ llvm::makeArrayRef(PlaceArgs, NumPlaceArgs),
+ TypeIdParens,
ArraySize, initStyle, Initializer,
ResultType, AllocTypeInfo,
- StartLoc, DirectInitRange));
+ Range, DirectInitRange));
}
/// \brief Checks that a type is suitable as the allocated type
@@ -1638,7 +1606,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
= dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
// Perform template argument deduction to try to match the
// expected function type.
- TemplateDeductionInfo Info(Context, StartLoc);
+ TemplateDeductionInfo Info(StartLoc);
if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info))
continue;
} else
@@ -2100,7 +2068,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
ObjectPtrConversions.front()->getConversionType(),
AA_Converting);
if (Res.isUsable()) {
- Ex = move(Res);
+ Ex = Res;
Type = Ex.get()->getType();
}
}
@@ -2211,13 +2179,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
}
- } else if (getLangOpts().ObjCAutoRefCount &&
- PointeeElem->isObjCLifetimeType() &&
- (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
- PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
- ArrayForm) {
- Diag(StartLoc, diag::warn_err_new_delete_object_array)
- << 1 << PointeeElem;
}
if (!OperatorDelete) {
@@ -2287,7 +2248,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
return ExprError();
}
- return move(Condition);
+ return Condition;
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
@@ -2354,11 +2315,9 @@ static ExprResult BuildCXXCastArgument(Sema &S,
default: llvm_unreachable("Unhandled cast kind!");
case CK_ConstructorConversion: {
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method);
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
- if (S.CompleteConstructorCall(Constructor,
- MultiExprArg(&From, 1),
- CastLoc, ConstructorArgs))
+ if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs))
return ExprError();
S.CheckConstructorAccess(CastLoc, Constructor,
@@ -2367,7 +2326,7 @@ static ExprResult BuildCXXCastArgument(Sema &S,
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
@@ -2511,15 +2470,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
if (SCS.Second == ICK_Derived_To_Base) {
- ASTOwningVector<Expr*> ConstructorArgs(*this);
+ SmallVector<Expr*, 8> ConstructorArgs;
if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor),
- MultiExprArg(*this, &From, 1),
- /*FIXME:ConstructLoc*/SourceLocation(),
+ From, /*FIXME:ConstructLoc*/SourceLocation(),
ConstructorArgs))
return ExprError();
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
/*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -2527,8 +2485,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
- MultiExprArg(*this, &From, 1),
- /*HadMultipleCandidates*/ false,
+ From, /*HadMultipleCandidates*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -2602,8 +2559,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- From = ImpCastExprToType(From, ToType, CK_IntegralCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ if (ToType->isBooleanType()) {
+ assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+ SCS.Second == ICK_Integral_Promotion &&
+ "only enums with fixed underlying type can promote to bool");
+ From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ } else {
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ }
break;
case ICK_Floating_Promotion:
@@ -2943,6 +2908,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_IsEmpty:
case UTT_IsPolymorphic:
case UTT_IsAbstract:
+ case UTT_IsInterfaceClass:
// Fall-through
// These traits require a complete type.
@@ -3007,7 +2973,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsUnion:
return T->isUnionType();
case UTT_IsClass:
- return T->isClassType() || T->isStructureType();
+ return T->isClassType() || T->isStructureType() || T->isInterfaceType();
case UTT_IsFunction:
return T->isFunctionType();
@@ -3073,6 +3039,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->isAbstract();
return false;
+ case UTT_IsInterfaceClass:
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->isInterface();
+ return false;
case UTT_IsFinal:
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->hasAttr<FinalAttr>();
@@ -3417,9 +3387,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (Init.Failed())
return false;
- ExprResult Result = Init.Perform(S, To, InitKind,
- MultiExprArg(ArgExprs.data(),
- ArgExprs.size()));
+ ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
@@ -3577,7 +3545,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
if (Init.Failed())
return false;
- ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
+ ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
@@ -3774,7 +3742,7 @@ ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
- return move(Result);
+ return Result;
}
static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
@@ -4056,14 +4024,14 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
Best->Conversions[0], Sema::AA_Converting);
if (LHSRes.isInvalid())
break;
- LHS = move(LHSRes);
+ LHS = LHSRes;
ExprResult RHSRes =
Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], Sema::AA_Converting);
if (RHSRes.isInvalid())
break;
- RHS = move(RHSRes);
+ RHS = RHSRes;
if (Best->Function)
Self.MarkFunctionReferenced(QuestionLoc, Best->Function);
return false;
@@ -4104,7 +4072,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
SourceLocation());
Expr *Arg = E.take();
InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1);
- ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&Arg, 1));
+ ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg);
if (Result.isInvalid())
return true;
@@ -4129,7 +4097,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
if (CondRes.isInvalid())
return QualType();
- Cond = move(CondRes);
+ Cond = CondRes;
}
// Assume r-value.
@@ -4160,6 +4128,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &NonVoid = LVoid ? RHS : LHS;
if (NonVoid.get()->getType()->isRecordType() &&
NonVoid.get()->isGLValue()) {
+ if (RequireNonAbstractType(QuestionLoc, NonVoid.get()->getType(),
+ diag::err_allocation_of_abstract_type))
+ return QualType();
InitializedEntity Entity =
InitializedEntity::InitializeTemporary(NonVoid.get()->getType());
NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid);
@@ -4302,7 +4273,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
if (LTy->isRecordType()) {
// The operands have class type. Make a temporary copy.
+ if (RequireNonAbstractType(QuestionLoc, LTy,
+ diag::err_allocation_of_abstract_type))
+ return QualType();
InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
+
ExprResult LHSCopy = PerformCopyInitialization(Entity,
SourceLocation(),
LHS);
@@ -4566,14 +4541,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// Convert E1 to Composite1
ExprResult E1Result
- = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E1,1));
+ = E1ToC1.Perform(*this, Entity1, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.takeAs<Expr>();
// Convert E2 to Composite1
ExprResult E2Result
- = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E2,1));
+ = E2ToC1.Perform(*this, Entity1, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.takeAs<Expr>();
@@ -4591,14 +4566,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// Convert E1 to Composite2
ExprResult E1Result
- = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1));
+ = E1ToC2.Perform(*this, Entity2, Kind, E1);
if (E1Result.isInvalid())
return QualType();
E1 = E1Result.takeAs<Expr>();
// Convert E2 to Composite2
ExprResult E2Result
- = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1));
+ = E2ToC2.Perform(*this, Entity2, Kind, E2);
if (E2Result.isInvalid())
return QualType();
E2 = E2Result.takeAs<Expr>();
@@ -4839,7 +4814,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
BO_Comma, BO->getType(),
BO->getValueKind(),
BO->getObjectKind(),
- BO->getOperatorLoc()));
+ BO->getOperatorLoc(),
+ BO->isFPContractable()));
}
}
@@ -4991,7 +4967,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
// type C (or of pointer to a class type C), the unqualified-id is looked
// up in the scope of class C. [...]
ObjectType = ParsedType::make(BaseType);
- return move(Base);
+ return Base;
}
ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
@@ -5056,7 +5032,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
return ExprError();
- if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
+ if (!ObjectType->isDependentType() && !ObjectType->isScalarType() &&
+ !ObjectType->isVectorType()) {
if (getLangOpts().MicrosoftMode && ObjectType->isVoidType())
Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange();
else
@@ -5203,8 +5180,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
} else {
// Resolve the template-id to a type.
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
@@ -5253,8 +5229,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
} else {
// Resolve the template-id to a type.
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
@@ -5353,7 +5328,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
- new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
+ new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK,
Exp.get()->getLocEnd());
return CE;
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 8f445e28648d..a7fd47183a16 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -353,7 +354,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
// Now look up the TypeDefDecl from the vector type. Without this,
// diagostics look bad. We want extended vector types to appear built-in.
for (Sema::ExtVectorDeclsType::iterator
- I = S.ExtVectorDecls.begin(S.ExternalSource),
+ I = S.ExtVectorDecls.begin(S.getExternalSource()),
E = S.ExtVectorDecls.end();
I != E; ++I) {
if ((*I)->getUnderlyingType() == VT)
@@ -605,7 +606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
R.addDecl(ND);
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
}
@@ -656,7 +658,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
}
if (Result.get())
- return move(Result);
+ return Result;
// LookupMemberExpr can modify Base, and thus change BaseType
BaseType = Base->getType();
@@ -1021,7 +1023,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
// Do the substitution as long as the redefinition type isn't just a
// possibly-qualified pointer to builtin-id or builtin-Class again.
opty = redef->getAs<ObjCObjectPointerType>();
- if (opty && !opty->getObjectType()->getInterface() != 0)
+ if (opty && !opty->getObjectType()->getInterface())
return false;
base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
@@ -1272,9 +1274,23 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (warn)
Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
- return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr.take(),
- IsArrow));
+
+ ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+ MemberLoc,
+ BaseExpr.take(),
+ IsArrow);
+
+ if (getLangOpts().ObjCAutoRefCount) {
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ MemberLoc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ }
+
+ return Owned(Result);
}
// Objective-C property access.
@@ -1550,7 +1566,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
Id.getKind() == UnqualifiedId::IK_DestructorName)
return DiagnoseDtorReference(NameInfo.getLoc(), Result.get());
- return move(Result);
+ return Result;
}
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl, HasTrailingLParen};
@@ -1560,7 +1576,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
false, &ExtraArgs);
}
- return move(Result);
+ return Result;
}
static ExprResult
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 0aabf8b634d1..e43b6bff5586 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -229,7 +229,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberPointer, ResultTInfo,
S.NSNumberDecl,
/*isInstance=*/false, /*isVariadic=*/false,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required,
@@ -345,7 +345,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
SourceLocation());
InitializationSequence Seq(S, Entity, Kind, &Element, 1);
if (!Seq.Failed())
- return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1));
+ return Seq.Perform(S, Entity, Kind, Element);
}
Expr *OrigElement = Element;
@@ -477,7 +477,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
stringWithUTF8String, NSStringPointer,
ResultTInfo, NSStringDecl,
/*isInstance=*/false, /*isVariadic=*/false,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
ObjCMethodDecl::Required,
@@ -646,7 +646,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ResultTInfo,
Context.getTranslationUnitDecl(),
false /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -708,7 +708,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
// Check that each of the elements provided is valid in a collection literal,
// performing conversions as necessary.
- Expr **ElementsBuffer = Elements.get();
+ Expr **ElementsBuffer = Elements.data();
for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
ElementsBuffer[I],
@@ -724,10 +724,8 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context.getObjCInterfaceType(NSArrayDecl));
return MaybeBindToTemporary(
- ObjCArrayLiteral::Create(Context,
- llvm::makeArrayRef(Elements.get(),
- Elements.size()),
- Ty, ArrayWithObjectsMethod, SR));
+ ObjCArrayLiteral::Create(Context, Elements, Ty,
+ ArrayWithObjectsMethod, SR));
}
ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
@@ -766,7 +764,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
0 /*TypeSourceInfo */,
Context.getTranslationUnitDecl(),
false /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1125,7 +1123,9 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Expr **Args, unsigned NumArgs,
- Selector Sel, ObjCMethodDecl *Method,
+ Selector Sel,
+ ArrayRef<SourceLocation> SelectorLocs,
+ ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
QualType &ReturnType, ExprValueKind &VK) {
@@ -1149,7 +1149,8 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
: diag::warn_inst_method_not_found;
if (!getLangOpts().DebuggerSupport)
Diag(lbrac, DiagID)
- << Sel << isClassMessage << SourceRange(lbrac, rbrac);
+ << Sel << isClassMessage << SourceRange(SelectorLocs.front(),
+ SelectorLocs.back());
// In debuggers, we want to use __unknown_anytype for these
// results so that clients can cast them.
@@ -1304,8 +1305,8 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
Expr *RExpr = Receiver->IgnoreParenImpCasts();
SourceLocation Loc = RExpr->getLocStart();
QualType T = RExpr->getType();
- ObjCPropertyDecl *PDecl = 0;
- ObjCMethodDecl *GDecl = 0;
+ const ObjCPropertyDecl *PDecl = 0;
+ const ObjCMethodDecl *GDecl = 0;
if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) {
RExpr = POE->getSyntacticForm();
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) {
@@ -1327,34 +1328,29 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
// See if receiver is a method which envokes a synthesized getter
// backing a 'weak' property.
ObjCMethodDecl *Method = ME->getMethodDecl();
- if (Method && Method->isSynthesized()) {
- Selector Sel = Method->getSelector();
- if (Sel.getNumArgs() == 0) {
- const DeclContext *Container = Method->getDeclContext();
- PDecl =
- S.LookupPropertyDecl(cast<ObjCContainerDecl>(Container),
- Sel.getIdentifierInfoForSlot(0));
- }
+ if (Method && Method->getSelector().getNumArgs() == 0) {
+ PDecl = Method->findPropertyDecl();
if (PDecl)
T = PDecl->getType();
}
}
- if (T.getObjCLifetime() == Qualifiers::OCL_Weak) {
- S.Diag(Loc, diag::warn_receiver_is_weak)
- << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
- if (PDecl)
- S.Diag(PDecl->getLocation(), diag::note_property_declare);
- else if (GDecl)
- S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
- return;
+ if (T.getObjCLifetime() != Qualifiers::OCL_Weak) {
+ if (!PDecl)
+ return;
+ if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak))
+ return;
}
-
- if (PDecl &&
- (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) {
- S.Diag(Loc, diag::warn_receiver_is_weak) << 1;
+
+ S.Diag(Loc, diag::warn_receiver_is_weak)
+ << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2));
+
+ if (PDecl)
S.Diag(PDecl->getLocation(), diag::note_property_declare);
- }
+ else if (GDecl)
+ S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl;
+
+ S.Diag(Loc, diag::note_arc_assign_to_strong);
}
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
@@ -1776,19 +1772,17 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// We are in a method whose class has a superclass, so 'super'
// is acting as a keyword.
- if (Method->isInstanceMethod()) {
- if (Sel.getMethodFamily() == OMF_dealloc)
- getCurFunction()->ObjCShouldCallSuperDealloc = false;
- if (Sel.getMethodFamily() == OMF_finalize)
- getCurFunction()->ObjCShouldCallSuperFinalize = false;
+ if (Method->getSelector() == Sel)
+ getCurFunction()->ObjCShouldCallSuper = false;
+ if (Method->isInstanceMethod()) {
// Since we are in an instance method, this is an instance
// message to the superclass instance.
QualType SuperTy = Context.getObjCInterfaceType(Super);
SuperTy = Context.getObjCObjectPointerType(SuperTy);
return BuildInstanceMessage(0, SuperTy, SuperLoc,
Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
// Since we are in a class method, this is a class message to
@@ -1796,7 +1790,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
return BuildClassMessage(/*ReceiverTypeInfo=*/0,
Context.getObjCInterfaceType(Super),
SuperLoc, Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
@@ -1911,7 +1905,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// If the receiver type is dependent, we can't type-check anything
// at this point. Build a dependent expression.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
VK_RValue, LBracLoc, ReceiverTypeInfo,
@@ -1965,8 +1959,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
ExprValueKind VK = VK_RValue;
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true,
+ Expr **Args = ArgsIn.data();
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, SelectorLocs,
+ Method, true,
SuperLoc.isValid(), LBracLoc, RBracLoc,
ReturnType, VK))
return ExprError();
@@ -2016,7 +2011,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
@@ -2095,7 +2090,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If the receiver is type-dependent, we can't type-check anything
// at this point. Build a dependent expression.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
VK_RValue, LBracLoc, Receiver, Sel,
@@ -2282,7 +2277,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
LBracLoc,
SelectorLocs,
RBracLoc,
- move(ArgsIn));
+ ArgsIn);
} else {
// Reject other random receiver types (e.g. structs).
Diag(Loc, diag::err_bad_receiver_type)
@@ -2295,12 +2290,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Check the message arguments.
unsigned NumArgs = ArgsIn.size();
- Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ Expr **Args = ArgsIn.data();
QualType ReturnType;
ExprValueKind VK = VK_RValue;
bool ClassMessage = (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method,
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel,
+ SelectorLocs, Method,
ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
@@ -2428,6 +2424,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// In ARC, check for message sends which are likely to introduce
// retain cycles.
checkRetainCycles(Result);
+
+ if (!isImplicit && Method) {
+ if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
+ bool IsWeak =
+ Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak;
+ if (!IsWeak && Sel.isUnarySelector())
+ IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
+
+ if (IsWeak) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ LBracLoc);
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->recordUseOfWeak(Result, Prop);
+
+ }
+ }
+ }
}
return MaybeBindToTemporary(Result);
@@ -2448,7 +2462,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
return BuildInstanceMessage(Receiver, Receiver->getType(),
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, move(Args));
+ LBracLoc, SelectorLocs, RBracLoc, Args);
}
enum ARCConversionTypeClass {
@@ -3079,8 +3093,8 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(),
gse->getControllingExpr(),
- subTypes.data(), subExprs.data(),
- n, gse->getDefaultLoc(),
+ subTypes, subExprs,
+ gse->getDefaultLoc(),
gse->getRParenLoc(),
gse->containsUnexpandedParameterPack(),
gse->getResultIndex());
@@ -3101,8 +3115,8 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
canExprType->isObjCObjectPointerType()) {
if (const ObjCObjectPointerType *ObjT =
canExprType->getAs<ObjCObjectPointerType>())
- if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable())
- return false;
+ if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl())
+ return !ObjI->isArcWeakrefUnavailable();
}
return true;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 62ab1e645089..3596bbfc725a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1316,6 +1316,8 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
if (structDecl->isInvalidDecl()) {
+ // Assume it was supposed to consume a single initializer.
+ ++Index;
hadError = true;
return;
}
@@ -1503,11 +1505,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
/// corresponds to FieldName.
static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
IdentifierInfo *FieldName) {
+ if (!FieldName)
+ return 0;
+
assert(AnonField->isAnonymousStructOrUnion());
Decl *NextDecl = AnonField->getNextDeclInContext();
while (IndirectFieldDecl *IF =
dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) {
- if (FieldName && FieldName == IF->getAnonField()->getIdentifier())
+ if (FieldName == IF->getAnonField()->getIdentifier())
return IF;
NextDecl = NextDecl->getNextDeclInContext();
}
@@ -1521,8 +1526,8 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
for (unsigned I = 0; I < NumIndexExprs; ++I)
IndexExprs[I] = DIE->getSubExpr(I + 1);
return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(),
- DIE->size(), IndexExprs.data(),
- NumIndexExprs, DIE->getEqualOrColonLoc(),
+ DIE->size(), IndexExprs,
+ DIE->getEqualOrColonLoc(),
DIE->usesGNUSyntax(), DIE->getInit());
}
@@ -1562,7 +1567,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
///
/// @param DesigIdx The index of the current designator.
///
-/// @param DeclType The type of the "current object" (C99 6.7.8p17),
+/// @param CurrentObjectType The type of the "current object" (C99 6.7.8p17),
/// into which the designation in @p DIE should refer.
///
/// @param NextField If non-NULL and the first designator in @p DIE is
@@ -2068,7 +2073,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
- InitRange.getBegin(), 0, 0,
+ InitRange.getBegin(), MultiExprArg(),
InitRange.getEnd());
QualType ResultType = CurrentObjectType;
@@ -2261,8 +2266,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
DesignatedInitExpr *DIE
= DesignatedInitExpr::Create(Context,
Designators.data(), Designators.size(),
- InitExpressions.data(), InitExpressions.size(),
- Loc, GNUSyntax, Init.takeAs<Expr>());
+ InitExpressions, Loc, GNUSyntax,
+ Init.takeAs<Expr>());
if (!getLangOpts().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
@@ -2814,14 +2819,6 @@ static void TryConstructorInitialization(Sema &S,
assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) &&
"InitListSyntax must come with a single initializer list argument.");
- // Check constructor arguments for self reference.
- if (DeclaratorDecl *DD = Entity.getDecl())
- // Parameters arguments are occassionially constructed with itself,
- // for instance, in recursive functions. Skip them.
- if (!isa<ParmVarDecl>(DD))
- for (unsigned i = 0; i < NumArgs; ++i)
- S.CheckSelfReference(DD, Args[i]);
-
// The type we're constructing needs to be complete.
if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
Sequence.setIncompleteTypeFailure(DestType);
@@ -3614,8 +3611,8 @@ static void TryValueInitialization(Sema &S,
// user-provided or deleted default constructor, then the object is
// zero-initialized and, if T has a non-trivial default constructor,
// default-initialized;
- // FIXME: The 'non-union' here is a defect (not yet assigned an issue
- // number). Update the quotation when the defect is resolved.
+ // The 'non-union' here was removed by DR1502. The 'non-trivial default
+ // constructor' part was removed by DR1507.
if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
@@ -3703,8 +3700,14 @@ static void TryUserDefinedConversion(Sema &S,
// Try to complete the type we're converting to.
if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_iterator ConOrig, ConEndOrig;
+ llvm::tie(ConOrig, ConEndOrig) = S.LookupConstructors(DestRecordDecl);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating. To be safe we copy the lookup results
+ // to a new container.
+ SmallVector<NamedDecl*, 8> CopyOfCon(ConOrig, ConEndOrig);
+ for (SmallVector<NamedDecl*, 8>::iterator
+ Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -4413,7 +4416,7 @@ static ExprResult CopyObject(Sema &S,
if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
- return move(CurInit);
+ return CurInit;
// C++0x [class.copy]p32:
// When certain criteria are met, an implementation is allowed to
@@ -4435,7 +4438,7 @@ static ExprResult CopyObject(Sema &S,
// Make sure that the type we are copying is complete.
if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete))
- return move(CurInit);
+ return CurInit;
// Perform overload resolution using the class's copy/move constructors.
// Only consider constructors and constructor templates. Per
@@ -4460,7 +4463,7 @@ static ExprResult CopyObject(Sema &S,
CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
- return move(CurInit);
+ return CurInit;
case OR_Ambiguous:
S.Diag(Loc, diag::err_temp_copy_ambiguous)
@@ -4478,7 +4481,7 @@ static ExprResult CopyObject(Sema &S,
}
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
CurInit.release(); // Ownership transferred into MultiExprArg, below.
S.CheckConstructorAccess(Loc, Constructor, Entity,
@@ -4521,7 +4524,7 @@ static ExprResult CopyObject(Sema &S,
// Actually perform the constructor call.
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -4530,7 +4533,7 @@ static ExprResult CopyObject(Sema &S,
// If we're supposed to bind temporaries, do so.
if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
- return move(CurInit);
+ return CurInit;
}
/// \brief Check whether elidable copy construction for binding a reference to
@@ -4619,7 +4622,7 @@ PerformConstructorInitialization(Sema &S,
bool HadMultipleCandidates = Step.Function.HadMultipleCandidates;
// Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
? Kind.getEqualLoc()
: Kind.getLocation();
@@ -4648,7 +4651,7 @@ PerformConstructorInitialization(Sema &S,
// Determine the arguments required to actually perform the constructor
// call.
- if (S.CompleteConstructorCall(Constructor, move(Args),
+ if (S.CompleteConstructorCall(Constructor, Args,
Loc, ConstructorArgs,
AllowExplicitConv))
return ExprError();
@@ -4660,8 +4663,6 @@ PerformConstructorInitialization(Sema &S,
(Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value)))) {
// An explicitly-constructed temporary, e.g., X(1, 2).
- unsigned NumExprs = ConstructorArgs.size();
- Expr **Exprs = (Expr **)ConstructorArgs.take();
S.MarkFunctionReferenced(Loc, Constructor);
S.DiagnoseUseOfDecl(Constructor, Loc);
@@ -4675,8 +4676,7 @@ PerformConstructorInitialization(Sema &S,
CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
Constructor,
TSInfo,
- Exprs,
- NumExprs,
+ ConstructorArgs,
ParenRange,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit));
@@ -4702,7 +4702,7 @@ PerformConstructorInitialization(Sema &S,
if (Entity.allowsNRVO())
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor, /*Elidable=*/true,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
@@ -4710,7 +4710,7 @@ PerformConstructorInitialization(Sema &S,
else
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
ConstructorInitRequiresZeroInit,
ConstructKind,
@@ -4727,7 +4727,7 @@ PerformConstructorInitialization(Sema &S,
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
- return move(CurInit);
+ return CurInit;
}
/// Determine whether the specified InitializedEntity definitely has a lifetime
@@ -4775,7 +4775,7 @@ InitializationSequence::Perform(Sema &S,
QualType *ResultType) {
if (Failed()) {
unsigned NumArgs = Args.size();
- Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs);
+ Diagnose(S, Entity, Kind, Args.data(), NumArgs);
return ExprError();
}
@@ -4795,7 +4795,7 @@ InitializationSequence::Perform(Sema &S,
// introduced and such). So, we fall back to making the array
// type a dependently-sized array type with no specified
// bound.
- if (isa<InitListExpr>((Expr *)Args.get()[0])) {
+ if (isa<InitListExpr>((Expr *)Args[0])) {
SourceRange Brackets;
// Scavange the location of the brackets from the entity, if we can.
@@ -4823,12 +4823,12 @@ InitializationSequence::Perform(Sema &S,
// Rebuild the ParenListExpr.
SourceRange ParenRange = Kind.getParenRange();
return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(),
- move(Args));
+ Args);
}
assert(Kind.getKind() == InitializationKind::IK_Copy ||
Kind.isExplicitCast() ||
Kind.getKind() == InitializationKind::IK_DirectList);
- return ExprResult(Args.release()[0]);
+ return ExprResult(Args[0]);
}
// No steps means no initialization.
@@ -4836,22 +4836,22 @@ InitializationSequence::Perform(Sema &S,
return S.Owned((Expr *)0);
if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() &&
- Args.size() == 1 && isa<InitListExpr>(Args.get()[0]) &&
+ Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
Entity.getKind() != InitializedEntity::EK_Parameter) {
// Produce a C++98 compatibility warning if we are initializing a reference
// from an initializer list. For parameters, we produce a better warning
// elsewhere.
- Expr *Init = Args.get()[0];
+ Expr *Init = Args[0];
S.Diag(Init->getLocStart(), diag::warn_cxx98_compat_reference_list_init)
<< Init->getSourceRange();
}
// Diagnose cases where we initialize a pointer to an array temporary, and the
// pointer obviously outlives the temporary.
- if (Args.size() == 1 && Args.get()[0]->getType()->isArrayType() &&
+ if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&
Entity.getType()->isPointerType() &&
InitializedEntityOutlivesFullExpression(Entity)) {
- Expr *Init = Args.get()[0];
+ Expr *Init = Args[0];
Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
@@ -4897,7 +4897,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ProduceObjCObject:
case SK_StdInitializerList: {
assert(Args.size() == 1);
- CurInit = Args.get()[0];
+ CurInit = Args[0];
if (!CurInit.get()) return ExprError();
break;
}
@@ -4924,7 +4924,7 @@ InitializationSequence::Perform(Sema &S,
// initializer to reflect that choice.
S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl);
S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation());
- CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ CurInit = S.FixOverloadedFunctionReference(CurInit,
Step->Function.FoundDecl,
Step->Function.Function);
break;
@@ -5016,7 +5016,7 @@ InitializationSequence::Perform(Sema &S,
break;
case SK_ExtraneousCopyToTemporary:
- CurInit = CopyObject(S, Step->Type, Entity, move(CurInit),
+ CurInit = CopyObject(S, Step->Type, Entity, CurInit,
/*IsExtraneousCopy=*/true);
break;
@@ -5031,7 +5031,7 @@ InitializationSequence::Perform(Sema &S,
bool CreatedObject = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
+ SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = CurInit.get()->getLocStart();
CurInit.release(); // Ownership transferred into MultiExprArg, below.
@@ -5045,7 +5045,7 @@ InitializationSequence::Perform(Sema &S,
// Build an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
- move_arg(ConstructorArgs),
+ ConstructorArgs,
HadMultipleCandidates,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
@@ -5079,7 +5079,7 @@ InitializationSequence::Perform(Sema &S,
FoundFn, Conversion);
if(CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
// Build the actual call to the conversion function.
CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion,
@@ -5115,7 +5115,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
- move(CurInit), /*IsExtraneousCopy=*/false);
+ CurInit, /*IsExtraneousCopy=*/false);
break;
}
@@ -5144,7 +5144,7 @@ InitializationSequence::Perform(Sema &S,
getAssignmentAction(Entity), CCK);
if (CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
break;
}
@@ -5195,13 +5195,13 @@ InitializationSequence::Perform(Sema &S,
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
assert(Args.size() == 1 && "expected a single argument for list init");
- InitListExpr *InitList = cast<InitListExpr>(Args.get()[0]);
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init)
<< InitList->getSourceRange();
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
- Kind, move(Arg), *Step,
+ Kind, Arg, *Step,
ConstructorInitRequiresZeroInit);
break;
}
@@ -5214,7 +5214,7 @@ InitializationSequence::Perform(Sema &S,
Expr *E = CurInit.take();
InitListExpr *Syntactic = Step->WrappingSyntacticList;
InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
- Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc());
+ Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc());
ILE->setSyntacticForm(Syntactic);
ILE->setType(E->getType());
ILE->setValueKind(E->getValueKind());
@@ -5234,7 +5234,7 @@ InitializationSequence::Perform(Sema &S,
bool UseTemporary = Entity.getType()->isReferenceType();
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
: Entity,
- Kind, move(Args), *Step,
+ Kind, Args, *Step,
ConstructorInitRequiresZeroInit);
break;
}
@@ -5268,15 +5268,15 @@ InitializationSequence::Perform(Sema &S,
case SK_CAssignment: {
QualType SourceType = CurInit.get()->getType();
- ExprResult Result = move(CurInit);
+ ExprResult Result = CurInit;
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(Step->Type, Result);
if (Result.isInvalid())
return ExprError();
- CurInit = move(Result);
+ CurInit = Result;
// If this is a call, allow conversion to a transparent union.
- ExprResult CurInitExprRes = move(CurInit);
+ ExprResult CurInitExprRes = CurInit;
if (ConvTy != Sema::Compatible &&
Entity.getKind() == InitializedEntity::EK_Parameter &&
S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes)
@@ -5284,7 +5284,7 @@ InitializationSequence::Perform(Sema &S,
ConvTy = Sema::Compatible;
if (CurInitExprRes.isInvalid())
return ExprError();
- CurInit = move(CurInitExprRes);
+ CurInit = CurInitExprRes;
bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
@@ -5398,7 +5398,7 @@ InitializationSequence::Perform(Sema &S,
}
InitListExpr *Semantic = new (S.Context)
InitListExpr(S.Context, ILE->getLBraceLoc(),
- Converted.data(), NumInits, ILE->getRBraceLoc());
+ Converted, ILE->getRBraceLoc());
Semantic->setSyntacticForm(ILE);
Semantic->setType(Dest);
Semantic->setInitializesStdInitializerList();
@@ -5415,7 +5415,7 @@ InitializationSequence::Perform(Sema &S,
cast<FieldDecl>(Entity.getDecl()),
CurInit.get());
- return move(CurInit);
+ return CurInit;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 6414c6fbac97..15cd2a73e7f7 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -22,13 +22,14 @@ using namespace clang;
using namespace sema;
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
+ TypeSourceInfo *Info,
bool KnownDependent) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
// Start constructing the lambda class.
- CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC,
+ CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info,
IntroducerRange.getBegin(),
KnownDependent);
DC->addDecl(Class);
@@ -369,15 +370,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (!TmplScope->decl_empty())
KnownDependent = true;
- CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent);
-
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
bool ExplicitResultType = true;
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
- llvm::ArrayRef<ParmVarDecl *> Params;
+ llvm::SmallVector<ParmVarDecl *, 8> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -410,17 +409,25 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
!= Context.DependentTy;
-
- TypeLoc TL = MethodTyInfo->getTypeLoc();
- FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
- Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
- Proto.getNumArgs());
+
+ if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
+ // Empty arg list, don't push any params.
+ checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
+ } else {
+ Params.reserve(FTI.NumArgs);
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+ Params.push_back(cast<ParmVarDecl>(FTI.ArgInfo[i].Param));
+ }
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
}
-
+
+ CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
+ KnownDependent);
+
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
@@ -528,6 +535,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
+ // Ignore invalid decls; they'll just confuse the code later.
+ if (Var->isInvalidDecl())
+ continue;
+
if (!Var->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index dad196b410c4..f6987e7bfbe0 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -707,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// result), perform template argument deduction and place the
// specialization into the result set. We do this to avoid forcing all
// callers to perform special deduction for conversion functions.
- TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc());
+ TemplateDeductionInfo Info(R.getNameLoc());
FunctionDecl *Specialization = 0;
const FunctionProtoType *ConvProto
@@ -1725,15 +1725,17 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
namespace {
struct AssociatedLookup {
- AssociatedLookup(Sema &S,
+ AssociatedLookup(Sema &S, SourceLocation InstantiationLoc,
Sema::AssociatedNamespaceSet &Namespaces,
Sema::AssociatedClassSet &Classes)
- : S(S), Namespaces(Namespaces), Classes(Classes) {
+ : S(S), Namespaces(Namespaces), Classes(Classes),
+ InstantiationLoc(InstantiationLoc) {
}
Sema &S;
Sema::AssociatedNamespaceSet &Namespaces;
Sema::AssociatedClassSet &Classes;
+ SourceLocation InstantiationLoc;
};
}
@@ -1796,6 +1798,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
+ case TemplateArgument::NullPtr:
// [Note: non-type template arguments do not contribute to the set of
// associated namespaces. ]
break;
@@ -1864,8 +1867,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// Only recurse into base classes for complete types.
if (!Class->hasDefinition()) {
- // FIXME: we might need to instantiate templates here
- return;
+ QualType type = Result.S.Context.getTypeDeclType(Class);
+ if (Result.S.RequireCompleteType(Result.InstantiationLoc, type,
+ /*no diagnostic*/ 0))
+ return;
}
// Add direct and indirect base classes along with their associated
@@ -2069,13 +2074,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
void
-Sema::FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args,
+Sema::FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
+ llvm::ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
AssociatedClasses.clear();
- AssociatedLookup Result(*this, AssociatedNamespaces, AssociatedClasses);
+ AssociatedLookup Result(*this, InstantiationLoc,
+ AssociatedNamespaces, AssociatedClasses);
// C++ [basic.lookup.koenig]p2:
// For each argument type T in the function call, there is a set
@@ -2642,17 +2649,14 @@ void ADLResult::insert(NamedDecl *New) {
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
SourceLocation Loc,
llvm::ArrayRef<Expr *> Args,
- ADLResult &Result,
- bool StdNamespaceIsAssociated) {
+ ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
- FindAssociatedClassesAndNamespaces(Args,
+ FindAssociatedClassesAndNamespaces(Loc, Args,
AssociatedNamespaces,
AssociatedClasses);
- if (StdNamespaceIsAssociated && StdNamespace)
- AssociatedNamespaces.insert(getStdNamespace());
QualType T1, T2;
if (Operator) {
@@ -2661,13 +2665,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
T2 = Args[1]->getType();
}
- // Try to complete all associated classes, in case they contain a
- // declaration of a friend function.
- for (AssociatedClassSet::iterator C = AssociatedClasses.begin(),
- CEnd = AssociatedClasses.end();
- C != CEnd; ++C)
- RequireCompleteType(Loc, Context.getRecordType(*C), 0);
-
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
@@ -4056,7 +4053,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (IsUnqualifiedLookup)
UnqualifiedTyposCorrected[Typo] = Result;
- return Result;
+ TypoCorrection TC = Result;
+ TC.setCorrectionRange(SS, TypoName);
+ return TC;
}
else if (BestResults.size() > 1
// Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
@@ -4076,7 +4075,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (IsUnqualifiedLookup)
UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
- return BestResults["super"].front();
+ TypoCorrection TC = BestResults["super"].front();
+ TC.setCorrectionRange(SS, TypoName);
+ return TC;
}
// If this was an unqualified lookup and we believe the callback object did
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 27deab226f91..8d708607f6eb 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
@@ -43,7 +44,7 @@ static Qualifiers::ObjCLifetime getImpliedARCOwnership(
if (attrs & (ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_strong |
ObjCPropertyDecl::OBJC_PR_copy)) {
- return type->getObjCARCImplicitLifetime();
+ return Qualifiers::OCL_Strong;
} else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) {
return Qualifiers::OCL_Weak;
} else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
@@ -102,6 +103,15 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
<< propertyLifetime;
}
+static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
+ if ((S.getLangOpts().getGC() != LangOptions::NonGC &&
+ T.isObjCGCWeak()) ||
+ (S.getLangOpts().ObjCAutoRefCount &&
+ T.getObjCLifetime() == Qualifiers::OCL_Weak))
+ return ObjCDeclSpec::DQ_PR_weak;
+ return 0;
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
@@ -114,12 +124,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
unsigned Attributes = ODS.getPropertyAttributes();
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
QualType T = TSI->getType();
- if ((getLangOpts().getGC() != LangOptions::NonGC &&
- T.isObjCGCWeak()) ||
- (getLangOpts().ObjCAutoRefCount &&
- T.getObjCLifetime() == Qualifiers::OCL_Weak))
- Attributes |= ObjCDeclSpec::DQ_PR_weak;
-
+ Attributes |= deduceWeakPropertyFromType(*this, T);
+
bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
// default is readwrite!
!(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -236,6 +242,15 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
}
+static unsigned getOwnershipRule(unsigned attr) {
+ return attr & (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy |
+ ObjCPropertyDecl::OBJC_PR_weak |
+ ObjCPropertyDecl::OBJC_PR_strong |
+ ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+}
+
Decl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
@@ -335,6 +350,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc,
diag::err_type_mismatch_continuation_class) << PDecl->getType();
Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return 0;
}
}
@@ -342,13 +358,11 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// with continuation class's readwrite property attribute!
unsigned PIkind = PIDecl->getPropertyAttributesAsWritten();
if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
- unsigned retainCopyNonatomic =
- (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_nonatomic);
- if ((Attributes & retainCopyNonatomic) !=
- (PIkind & retainCopyNonatomic)) {
+ PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType());
+ unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
+ unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
+ if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
+ (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) {
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
@@ -397,6 +411,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc, diag)
<< CCPrimary->getDeclName();
Diag(PIDecl->getLocation(), diag::note_property_declare);
+ return 0;
}
*isOverridingProperty = true;
// Make sure setter decl is synthesized, and added to primary class's list.
@@ -405,7 +420,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
if (ASTMutationListener *L = Context.getASTMutationListener())
L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
- return 0;
+ return PDecl;
}
ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
@@ -543,6 +558,23 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
ivarLifetime == Qualifiers::OCL_Autoreleasing)
return;
+ // If the ivar is private, and it's implicitly __unsafe_unretained
+ // becaues of its type, then pretend it was actually implicitly
+ // __strong. This is only sound because we're processing the
+ // property implementation before parsing any method bodies.
+ if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
+ propertyLifetime == Qualifiers::OCL_Strong &&
+ ivar->getAccessControl() == ObjCIvarDecl::Private) {
+ SplitQualType split = ivarType.split();
+ if (split.Quals.hasObjCLifetime()) {
+ assert(ivarType->isObjCARCImplicitlyUnretainedType());
+ split.Quals.setObjCLifetime(Qualifiers::OCL_Strong);
+ ivarType = S.Context.getQualifiedType(split);
+ ivar->setType(ivarType);
+ return;
+ }
+ }
+
switch (propertyLifetime) {
case Qualifiers::OCL_Strong:
S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
@@ -632,7 +664,13 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
// property.
if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
if (!classExtPropertyAttr ||
- (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite))
+ (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;
@@ -857,13 +895,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (lifetime == Qualifiers::OCL_Weak) {
bool err = false;
if (const ObjCObjectPointerType *ObjT =
- PropertyIvarType->getAs<ObjCObjectPointerType>())
- if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) {
+ PropertyIvarType->getAs<ObjCObjectPointerType>()) {
+ const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl();
+ if (ObjI && ObjI->isArcWeakrefUnavailable()) {
Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property);
Diag(property->getLocation(), diag::note_property_declare);
err = true;
}
- if (!err && !getLangOpts().ObjCRuntimeHasWeak) {
+ }
+ if (!err && !getLangOpts().ObjCARCWeak) {
Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime);
Diag(property->getLocation(), diag::note_property_declare);
}
@@ -891,7 +931,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar);
- property->setPropertyIvarDecl(Ivar);
if (getLangOpts().ObjCRuntime.isFragile())
Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl)
@@ -907,14 +946,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
<< Ivar << Ivar->getName();
// Note! I deliberately want it to fall thru so more errors are caught.
}
+ property->setPropertyIvarDecl(Ivar);
+
QualType IvarType = Context.getCanonicalType(Ivar->getType());
// Check that type of property and its ivar are type compatible.
if (!Context.hasSameType(PropertyIvarType, IvarType)) {
- compat = false;
if (isa<ObjCObjectPointerType>(PropertyIvarType)
&& isa<ObjCObjectPointerType>(IvarType))
- compat =
+ compat =
Context.canAssignObjCInterfaces(
PropertyIvarType->getAs<ObjCObjectPointerType>(),
IvarType->getAs<ObjCObjectPointerType>());
@@ -988,19 +1028,21 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// For Objective-C++, need to synthesize the AST for the IVAR object to be
// returned by the getter as it must conform to C++'s copy-return rules.
// FIXME. Eventually we want to do this for Objective-C as well.
+ SynthesizedFunctionScope Scope(*this, getterMethod);
ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, SourceLocation());
+ VK_RValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(SelfExpr);
Expr *IvarRefExpr =
- new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
SelfExpr, true, true);
ExprResult Res =
PerformCopyInitialization(InitializedEntity::InitializeResult(
- SourceLocation(),
+ PropertyDiagLoc,
getterMethod->getResultType(),
/*NRVO=*/false),
- SourceLocation(),
+ PropertyDiagLoc,
Owned(IvarRefExpr));
if (!Res.isInvalid()) {
Expr *ResExpr = Res.takeAs<Expr>();
@@ -1021,19 +1063,22 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
+ SynthesizedFunctionScope Scope(*this, setterMethod);
ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, SourceLocation());
+ VK_RValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(SelfExpr);
Expr *lhs =
- new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
+ new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
QualType T = Param->getType().getNonReferenceType();
- Expr *rhs = new (Context) DeclRefExpr(Param, false, T,
- VK_LValue, SourceLocation());
- ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
+ DeclRefExpr *rhs = new (Context) DeclRefExpr(Param, false, T,
+ VK_LValue, PropertyDiagLoc);
+ MarkDeclRefReferenced(rhs);
+ ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
BO_Assign, lhs, rhs);
if (property->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_atomic) {
@@ -1043,7 +1088,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
if (!FuncDecl->isTrivial())
if (property->getType()->isReferenceType()) {
- Diag(PropertyLoc,
+ Diag(PropertyDiagLoc,
diag::err_atomic_property_nontrivial_assign_op)
<< property->getType();
Diag(FuncDecl->getLocStart(),
@@ -1395,8 +1440,8 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap) {
+ ObjCContainerDecl::PropertyMap &PropMap,
+ ObjCContainerDecl::PropertyMap &SuperPropMap) {
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
E = IDecl->prop_end(); P != E; ++P) {
@@ -1442,118 +1487,38 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
-/// CollectClassPropertyImplementations - This routine collects list of
-/// properties to be implemented in the class. This includes, class's
-/// and its conforming protocols' properties.
-static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- PropMap[Prop->getIdentifier()] = Prop;
- }
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); PI != E; ++PI)
- CollectClassPropertyImplementations((*PI), PropMap);
- }
- else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (!PropMap.count(Prop->getIdentifier()))
- PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CollectClassPropertyImplementations((*PI), PropMap);
- }
-}
-
/// CollectSuperClassPropertyImplementations - This routine collects list of
/// properties to be implemented in super class(s) and also coming from their
/// conforming protocols.
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
while (SDecl) {
- CollectClassPropertyImplementations(SDecl, PropMap);
+ SDecl->collectPropertiesToImplement(PropMap);
SDecl = SDecl->getSuperClass();
}
}
}
-/// LookupPropertyDecl - Looks up a property in the current class and all
-/// its protocols.
-ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
- IdentifierInfo *II) {
- if (const ObjCInterfaceDecl *IDecl =
- dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through class's protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- else if (const ObjCProtocolDecl *PDecl =
- dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->getIdentifier() == II)
- return Prop;
- }
- // scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI) {
- ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
- if (Prop)
- return Prop;
- }
- }
- return 0;
-}
-
-static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop,
- ASTContext &Ctx) {
- SmallString<128> ivarName;
- {
- llvm::raw_svector_ostream os(ivarName);
- os << '_' << Prop->getIdentifier()->getName();
- }
- return &Ctx.Idents.get(ivarName.str());
-}
-
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
- CollectClassPropertyImplementations(IDecl, PropMap);
+ ObjCInterfaceDecl::PropertyMap PropMap;
+ IDecl->collectPropertiesToImplement(PropMap);
if (PropMap.empty())
return;
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ for (ObjCInterfaceDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
// If property to be implemented in the super class, ignore.
if (SuperPropMap[Prop->getIdentifier()])
continue;
- // Is there a matching propery synthesize/dynamic?
+ // Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
@@ -1583,7 +1548,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(),
true,
/* property = */ Prop->getIdentifier(),
- /* ivar = */ getDefaultSynthIvarName(Prop, Context),
+ /* ivar = */ Prop->getDefaultSynthIvarName(Context),
Prop->getLocation()));
if (PIDecl) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
@@ -1606,11 +1571,11 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const SelectorSet &InsMap) {
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap;
+ ObjCContainerDecl::PropertyMap SuperPropMap;
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ ObjCContainerDecl::PropertyMap PropMap;
CollectImmediateProperties(CDecl, PropMap, SuperPropMap);
if (PropMap.empty())
return;
@@ -1621,7 +1586,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
EI = IMPDecl->propimpl_end(); I != EI; ++I)
PropImplMap.insert(I->getPropertyDecl());
- for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ for (ObjCContainerDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
// Is there a matching propery synthesize/dynamic?
@@ -1847,7 +1812,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
property->getType(), 0, CD, /*isInstance=*/true,
- /*isVariadic=*/false, /*isSynthesized=*/true,
+ /*isVariadic=*/false, /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
@@ -1867,7 +1832,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
- GetterMethod->setSynthesized(true);
+ GetterMethod->setPropertyAccessor(true);
property->setGetterMethodDecl(GetterMethod);
// Skip setter if property is read-only.
@@ -1885,7 +1850,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCMethodDecl::Create(Context, Loc, Loc,
property->getSetterName(), Context.VoidTy, 0,
CD, /*isInstance=*/true, /*isVariadic=*/false,
- /*isSynthesized=*/true,
+ /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -1916,7 +1881,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
- SetterMethod->setSynthesized(true);
+ SetterMethod->setPropertyAccessor(true);
property->setSetterMethodDecl(SetterMethod);
}
// Add any synthesized methods to the global pool. This allows us to
@@ -2121,7 +2086,9 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
// issue any warning.
if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
;
- else {
+ else if (propertyInPrimaryClass) {
+ // Don't issue warning on property with no life time in class
+ // extension as it is inherited from property in primary class.
// Skip this warning in gc-only mode.
if (getLangOpts().getGC() != LangOptions::GCOnly)
Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 9382f7dddc6c..911187857fe1 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -49,7 +49,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
return ExprError();
- return move(E);
+ return E;
}
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
@@ -555,6 +555,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
Result.Data = 0;
switch (TDK) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
@@ -597,6 +598,7 @@ static MakeDeductionFailureInfo(ASTContext &Context,
void OverloadCandidate::DeductionFailureInfo::Destroy() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -637,6 +639,7 @@ TemplateParameter
OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
@@ -664,6 +667,7 @@ TemplateArgumentList *
OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
@@ -688,6 +692,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -713,6 +718,7 @@ const TemplateArgument *
OverloadCandidate::DeductionFailureInfo::getSecondArg() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_Incomplete:
case Sema::TDK_TooManyArguments:
@@ -734,13 +740,17 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
return 0;
}
-void OverloadCandidateSet::clear() {
+void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
i->Conversions[ii].~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
+}
+
+void OverloadCandidateSet::clear() {
+ destroyCandidates();
NumInlineSequences = 0;
Candidates.clear();
Functions.clear();
@@ -1668,7 +1678,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
return To->getKind() == BuiltinType::UInt;
}
- // C++0x [conv.prom]p3:
+ // C++11 [conv.prom]p3:
// A prvalue of an unscoped enumeration type whose underlying type is not
// fixed (7.2) can be converted to an rvalue a prvalue of the first of the
// following types that can represent all the values of the enumeration
@@ -1680,12 +1690,26 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// with lowest integer conversion rank (4.13) greater than the rank of long
// long in which all the values of the enumeration can be represented. If
// there are two such extended types, the signed one is chosen.
+ // C++11 [conv.prom]p4:
+ // A prvalue of an unscoped enumeration type whose underlying type is fixed
+ // can be converted to a prvalue of its underlying type. Moreover, if
+ // integral promotion can be applied to its underlying type, a prvalue of an
+ // unscoped enumeration type whose underlying type is fixed can also be
+ // converted to a prvalue of the promoted underlying type.
if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
// C++0x 7.2p9: Note that this implicit enum to int conversion is not
// provided for a scoped enumeration.
if (FromEnumType->getDecl()->isScoped())
return false;
+ // We can perform an integral promotion to the underlying type of the enum,
+ // even if that's not the promoted type.
+ if (FromEnumType->getDecl()->isFixed()) {
+ QualType Underlying = FromEnumType->getDecl()->getIntegerType();
+ return Context.hasSameUnqualifiedType(Underlying, ToType) ||
+ IsIntegralPromotion(From, Underlying, ToType);
+ }
+
// We have already pre-calculated the promotion type, so this is trivial.
if (ToType->isIntegerType() &&
!RequireCompleteType(From->getLocStart(), FromType, 0))
@@ -2899,8 +2923,6 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
case OR_Success: {
// Record the standard conversion we used and the conversion function.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- S.MarkFunctionReferenced(From->getLocStart(), Constructor);
-
QualType ThisType = Constructor->getThisType(S.Context);
// Initializer lists don't have conversions as such.
User.Before.setAsIdentityConversion();
@@ -3081,8 +3103,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
- S.MarkFunctionReferenced(From->getLocStart(), Constructor);
-
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
// constructor (12.3.1), the initial standard conversion
@@ -3111,8 +3131,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
- S.MarkFunctionReferenced(From->getLocStart(), Conversion);
-
// C++ [over.ics.user]p1:
//
// [...] If the user-defined conversion is specified by a
@@ -4025,8 +4043,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!Best->FinalConversion.DirectBinding)
return false;
- if (Best->Function)
- S.MarkFunctionReferenced(DeclLoc, Best->Function);
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
@@ -5531,7 +5547,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
@@ -5581,7 +5597,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
@@ -5703,7 +5719,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
// allocator).
QualType CallResultType = ConversionType.getNonLValueExprType(Context);
- CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK,
+ CallExpr Call(Context, &ConversionFn, MultiExprArg(), CallResultType, VK,
From->getLocStart());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, &Call, ToType,
@@ -5765,7 +5781,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
- TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
+ TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
@@ -6770,17 +6786,16 @@ public:
// bool operator==(T, T);
// bool operator!=(T, T);
void addRelationalPointerOrEnumeralOverloads() {
- // C++ [over.built]p1:
- // If there is a user-written candidate with the same name and parameter
- // types as a built-in candidate operator function, the built-in operator
- // function is hidden and is not included in the set of candidate
- // functions.
+ // C++ [over.match.oper]p3:
+ // [...]the built-in candidates include all of the candidate operator
+ // functions defined in 13.6 that, compared to the given operator, [...]
+ // do not have the same parameter-type-list as any non-template non-member
+ // candidate.
//
- // The text is actually in a note, but if we don't implement it then we end
- // up with ambiguities when the user provides an overloaded operator for
- // an enumeration type. Note that only enumeration types have this problem,
- // so we track which enumeration types we've seen operators for. Also, the
- // only other overloaded operator with enumeration argumenst, operator=,
+ // Note that in practice, this only affects enumeration types because there
+ // aren't any built-in candidates of record type, and a user-defined operator
+ // must have an operand of record or enumeration type. Also, the only other
+ // overloaded operator with enumeration arguments, operator=,
// cannot be overloaded for enumeration types, so this is the only place
// where we must suppress candidates like this.
llvm::DenseSet<std::pair<CanQualType, CanQualType> >
@@ -6795,6 +6810,9 @@ public:
if (!C->Viable || !C->Function || C->Function->getNumParams() != 2)
continue;
+ if (C->Function->isFunctionTemplateSpecialization())
+ continue;
+
QualType FirstParamType =
C->Function->getParamDecl(0)->getType().getUnqualifiedType();
QualType SecondParamType =
@@ -7652,8 +7670,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
llvm::ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
- bool PartialOverloading,
- bool StdNamespaceIsAssociated) {
+ bool PartialOverloading) {
ADLResult Fns;
// FIXME: This approach for uniquing ADL results (and removing
@@ -7664,8 +7681,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Loc, Args, Fns,
- StdNamespaceIsAssociated);
+ ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -7976,10 +7992,20 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
const PartialDiagnostic &PDiag) const {
S.Diag(CaretLoc, PDiag)
<< Ambiguous.getFromType() << Ambiguous.getToType();
- for (AmbiguousConversionSequence::const_iterator
- I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
+ // FIXME: The note limiting machinery is borrowed from
+ // OverloadCandidateSet::NoteCandidates; there's an opportunity for
+ // refactoring here.
+ const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
+ unsigned CandsShown = 0;
+ AmbiguousConversionSequence::const_iterator I, E;
+ for (I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
+ if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
+ break;
+ ++CandsShown;
S.NoteOverloadCandidate(*I);
}
+ if (I != E)
+ S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
}
namespace {
@@ -8515,7 +8541,7 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
}
void NoteBuiltinOperatorCandidate(Sema &S,
- const char *Opc,
+ StringRef Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
@@ -8561,6 +8587,7 @@ RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
case Sema::TDK_Success:
llvm_unreachable("TDK_success while diagnosing bad deduction");
+ case Sema::TDK_Invalid:
case Sema::TDK_Incomplete:
return 1;
@@ -8783,7 +8810,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
void OverloadCandidateSet::NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
llvm::ArrayRef<Expr *> Args,
- const char *Opc,
+ StringRef Opc,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
// be prohibitive, so we make a set of pointers and sort those.
@@ -8807,8 +8834,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
bool ReportedAmbiguousConversions = false;
SmallVectorImpl<OverloadCandidate*>::iterator I, E;
- const DiagnosticsEngine::OverloadsShown ShowOverloads =
- S.Diags.getShowOverloads();
+ const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
unsigned CandsShown = 0;
for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
OverloadCandidate *Cand = *I;
@@ -8816,7 +8842,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
// Set an arbitrary limit on the number of candidate functions we'll spam
// the user with. FIXME: This limit should depend on details of the
// candidate list.
- if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) {
+ if (CandsShown >= 4 && ShowOverloads == Ovl_Best) {
break;
}
++CandsShown;
@@ -8979,7 +9005,7 @@ private:
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
+ TemplateDeductionInfo Info(OvlExpr->getNameLoc());
if (Sema::TemplateDeductionResult Result
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
@@ -9201,7 +9227,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
- MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn);
if (Complain)
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
@@ -9257,7 +9282,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, ovl->getNameLoc());
+ TemplateDeductionInfo Info(ovl->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
@@ -9457,8 +9482,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
- CandidateSet, PartialOverloading,
- ULE->isStdAssociatedNamespace());
+ CandidateSet, PartialOverloading);
}
/// Attempt to recover from an ill-formed use of a non-dependent name in a
@@ -9509,7 +9533,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
// declaring the function there instead.
Sema::AssociatedNamespaceSet AssociatedNamespaces;
Sema::AssociatedClassSet AssociatedClasses;
- SemaRef.FindAssociatedClassesAndNamespaces(Args,
+ SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args,
AssociatedNamespaces,
AssociatedClasses);
// Never suggest declaring a function within namespace 'std'.
@@ -9632,6 +9656,20 @@ class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
return false;
}
};
+
+class BuildRecoveryCallExprRAII {
+ Sema &SemaRef;
+public:
+ BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) {
+ assert(SemaRef.IsBuildingRecoveryCallExpr == false);
+ SemaRef.IsBuildingRecoveryCallExpr = true;
+ }
+
+ ~BuildRecoveryCallExprRAII() {
+ SemaRef.IsBuildingRecoveryCallExpr = false;
+ }
+};
+
}
/// Attempts to recover from a call where no functions were found.
@@ -9644,6 +9682,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
llvm::MutableArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool EmptyLookup, bool AllowTypoCorrection) {
+ // Do not try to recover if it is already building a recovery call.
+ // This stops infinite loops for template instantiations like
+ //
+ // template <typename T> auto foo(T t) -> decltype(foo(t)) {}
+ // template <typename T> auto foo(T t) -> decltype(foo(&t)) {}
+ //
+ if (SemaRef.IsBuildingRecoveryCallExpr)
+ return ExprError();
+ BuildRecoveryCallExprRAII RCE(SemaRef);
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
@@ -9695,20 +9742,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
RParenLoc);
}
-/// ResolveOverloadedCallFn - Given the call expression that calls Fn
-/// (which eventually refers to the declaration Func) and the call
-/// arguments Args/NumArgs, attempt to resolve the function call down
-/// to a specific function. If overload resolution succeeds, returns
-/// the function declaration produced by overload
-/// resolution. Otherwise, emits diagnostics, deletes all of the
-/// arguments and Fn, and returns NULL.
-ExprResult
-Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
- SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc,
- Expr *ExecConfig,
- bool AllowTypoCorrection) {
+/// \brief Constructs and populates an OverloadedCandidateSet from
+/// the given function.
+/// \returns true when an the ExprResult output parameter has been set.
+bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ OverloadCandidateSet *CandidateSet,
+ ExprResult *Result) {
#ifndef NDEBUG
if (ULE->requiresADL()) {
// To do ADL, we must have found an unqualified name.
@@ -9724,62 +9766,79 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// We don't perform ADL in C.
assert(getLangOpts().CPlusPlus && "ADL enabled in C");
- } else
- assert(!ULE->isStdAssociatedNamespace() &&
- "std is associated namespace but not doing ADL");
+ }
#endif
UnbridgedCastsSet UnbridgedCasts;
- if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
- return ExprError();
-
- OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, 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);
+ *CandidateSet);
// If we found nothing, try to recover.
// BuildRecoveryCallExpr diagnoses the error itself, so we just bail
// out if it fails.
- if (CandidateSet.empty()) {
+ if (CandidateSet->empty()) {
// In Microsoft mode, if we are inside a template class member function then
// create a type dependent CallExpr. The goal is to postpone name lookup
// to instantiation time to be able to search into type dependent base
// classes.
if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
(isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
- CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs,
- Context.DependentTy, VK_RValue,
- RParenLoc);
+ CallExpr *CE = new (Context) CallExpr(Context, Fn,
+ llvm::makeArrayRef(Args, NumArgs),
+ Context.DependentTy, VK_RValue,
+ RParenLoc);
CE->setTypeDependent(true);
- return Owned(CE);
+ *Result = Owned(CE);
+ return true;
}
- return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
- llvm::MutableArrayRef<Expr *>(Args, NumArgs),
- RParenLoc, /*EmptyLookup=*/true,
- AllowTypoCorrection);
+ return false;
}
UnbridgedCasts.restore();
+ return false;
+}
- OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
+/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns
+/// the completed call expression. If overload resolution fails, emits
+/// diagnostics and returns ExprError()
+static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ Expr *ExecConfig,
+ OverloadCandidateSet *CandidateSet,
+ OverloadCandidateSet::iterator *Best,
+ OverloadingResult OverloadResult,
+ bool AllowTypoCorrection) {
+ if (CandidateSet->empty())
+ return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
+ llvm::MutableArrayRef<Expr *>(Args, NumArgs),
+ RParenLoc, /*EmptyLookup=*/true,
+ AllowTypoCorrection);
+
+ switch (OverloadResult) {
case OR_Success: {
- FunctionDecl *FDecl = Best->Function;
- MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
- CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
- DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
- Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
- return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc,
- ExecConfig);
+ FunctionDecl *FDecl = (*Best)->Function;
+ SemaRef.MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
+ SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl);
+ SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
+ Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
+ return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
+ 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(*this, S, Fn, ULE, LParenLoc,
+ ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc,
llvm::MutableArrayRef<Expr *>(Args, NumArgs),
RParenLoc,
/*EmptyLookup=*/false,
@@ -9787,44 +9846,73 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
if (!Recovery.isInvalid())
return Recovery;
- Diag(Fn->getLocStart(),
+ SemaRef.Diag(Fn->getLocStart(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
}
case OR_Ambiguous:
- Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
+ SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
- case OR_Deleted:
- {
- Diag(Fn->getLocStart(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << ULE->getName()
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
- llvm::makeArrayRef(Args, NumArgs));
+ case OR_Deleted: {
+ SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_deleted_call)
+ << (*Best)->Function->isDeleted()
+ << ULE->getName()
+ << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function)
+ << Fn->getSourceRange();
+ CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
- // We emitted an error for the unvailable/deleted function call but keep
- // the call in the AST.
- FunctionDecl *FDecl = Best->Function;
- Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
- return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
- }
+ // 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);
+ }
}
// Overload resolution failed.
return ExprError();
}
+/// BuildOverloadedCallExpr - Given the call expression that calls Fn
+/// (which eventually refers to the declaration Func) and the call
+/// arguments Args/NumArgs, attempt to resolve the function call down
+/// to a specific function. If overload resolution succeeds, returns
+/// the call expression produced by overload resolution.
+/// Otherwise, emits diagnostics and returns ExprError.
+ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
+ UnresolvedLookupExpr *ULE,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc,
+ Expr *ExecConfig,
+ bool AllowTypoCorrection) {
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ ExprResult result;
+
+ if (buildOverloadedCallSet(S, Fn, ULE, Args, NumArgs, 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,
+ RParenLoc, ExecConfig, &CandidateSet,
+ &Best, OverloadResult,
+ AllowTypoCorrection);
+}
+
static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
return Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
@@ -9889,10 +9977,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- &Args[0], NumArgs,
+ llvm::makeArrayRef(Args, NumArgs),
Context.DependentTy,
VK_RValue,
- OpLoc));
+ OpLoc, false));
}
// Build an empty overload set.
@@ -9968,7 +10056,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Args[0] = Input;
CallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
- Args, NumArgs, ResultTy, VK, OpLoc);
+ llvm::makeArrayRef(Args, NumArgs),
+ ResultTy, VK, OpLoc, false);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
FnDecl))
@@ -10069,7 +10158,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
Context.DependentTy,
VK_RValue, OK_Ordinary,
- OpLoc));
+ OpLoc,
+ FPFeatures.fp_contract));
return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc,
Context.DependentTy,
@@ -10077,7 +10167,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
OK_Ordinary,
Context.DependentTy,
Context.DependentTy,
- OpLoc));
+ OpLoc,
+ FPFeatures.fp_contract));
}
// FIXME: save results of ADL from here?
@@ -10089,11 +10180,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- Args, 2,
- Context.DependentTy,
- VK_RValue,
- OpLoc));
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args,
+ Context.DependentTy, VK_RValue,
+ OpLoc, FPFeatures.fp_contract));
}
// Always do placeholder-like conversions on the RHS.
@@ -10208,7 +10297,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
- Args, 2, ResultTy, VK, OpLoc);
+ Args, ResultTy, VK, OpLoc,
+ FPFeatures.fp_contract);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
FnDecl))
@@ -10270,7 +10360,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Result.isInvalid())
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
- return move(Result);
+ return Result;
}
case OR_Ambiguous:
@@ -10337,10 +10427,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Can't add any actual overloads yet
return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn,
- Args, 2,
+ Args,
Context.DependentTy,
VK_RValue,
- RLoc));
+ RLoc, false));
}
// Handle placeholders on both operands.
@@ -10416,8 +10506,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr.take(), Args, 2,
- ResultTy, VK, RLoc);
+ FnExpr.take(), Args,
+ ResultTy, VK, RLoc,
+ false);
if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall,
FnDecl))
@@ -10534,7 +10625,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
CXXMemberCallExpr *call
- = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ = new (Context) CXXMemberCallExpr(Context, MemExprE,
+ llvm::makeArrayRef(Args, NumArgs),
resultType, valueKind, RParenLoc);
if (CheckCallReturnType(proto->getResultType(),
@@ -10676,7 +10768,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
assert(Method && "Member call to something that isn't a method?");
CXXMemberCallExpr *TheCall =
- new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ new (Context) CXXMemberCallExpr(Context, MemExprE,
+ llvm::makeArrayRef(Args, NumArgs),
ResultType, VK, RParenLoc);
// Check for a valid return type.
@@ -10904,6 +10997,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// that calls this method, using Object for the implicit object
// parameter and passing along the remaining arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+
+ // An error diagnostic has already been printed when parsing the declaration.
+ if (Method->isInvalidDecl())
+ return ExprError();
+
const FunctionProtoType *Proto =
Method->getType()->getAs<FunctionProtoType>();
@@ -10942,8 +11040,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
- MethodArgs, NumArgs + 1,
- ResultTy, VK, RParenLoc);
+ llvm::makeArrayRef(MethodArgs, NumArgs+1),
+ ResultTy, VK, RParenLoc, false);
delete [] MethodArgs;
if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall,
@@ -10966,7 +11064,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (ObjRes.isInvalid())
IsError = true;
else
- Object = move(ObjRes);
+ Object = ObjRes;
TheCall->setArg(0, Object.take());
// Check the argument types.
@@ -11116,7 +11214,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(),
- &Base, 1, ResultTy, VK, OpLoc);
+ Base, ResultTy, VK, OpLoc, false);
if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall,
Method))
@@ -11187,7 +11285,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL =
- new (Context) UserDefinedLiteral(Context, Fn.take(), ConvArgs, Args.size(),
+ new (Context) UserDefinedLiteral(Context, Fn.take(),
+ llvm::makeArrayRef(ConvArgs, Args.size()),
ResultTy, VK, LitEndLoc, UDSuffixLoc);
if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
@@ -11199,6 +11298,80 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
return MaybeBindToTemporary(UDL);
}
+/// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the
+/// given LookupResult is non-empty, it is assumed to describe a member which
+/// will be invoked. Otherwise, the function will be found via argument
+/// dependent lookup.
+/// CallExpr is set to a valid expression and FRS_Success returned on success,
+/// otherwise CallExpr is set to ExprError() and some non-success value
+/// is returned.
+Sema::ForRangeStatus
+Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
+ SourceLocation RangeLoc, VarDecl *Decl,
+ BeginEndFunction BEF,
+ const DeclarationNameInfo &NameInfo,
+ LookupResult &MemberLookup,
+ OverloadCandidateSet *CandidateSet,
+ Expr *Range, ExprResult *CallExpr) {
+ CandidateSet->clear();
+ if (!MemberLookup.empty()) {
+ ExprResult MemberRef =
+ BuildMemberReferenceExpr(Range, Range->getType(), Loc,
+ /*IsPtr=*/false, CXXScopeSpec(),
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/0,
+ MemberLookup,
+ /*TemplateArgs=*/0);
+ if (MemberRef.isInvalid()) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0);
+ if (CallExpr->isInvalid()) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ } else {
+ UnresolvedSet<0> FoundNames;
+ UnresolvedLookupExpr *Fn =
+ UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0,
+ NestedNameSpecifierLoc(), NameInfo,
+ /*NeedsADL=*/true, /*Overloaded=*/false,
+ FoundNames.begin(), FoundNames.end());
+
+ bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc,
+ CandidateSet, CallExpr);
+ if (CandidateSet->empty() || CandidateSetError) {
+ *CallExpr = ExprError();
+ return FRS_NoViableFunction;
+ }
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OverloadResult =
+ CandidateSet->BestViableFunction(*this, Fn->getLocStart(), Best);
+
+ if (OverloadResult == OR_No_Viable_Function) {
+ *CallExpr = ExprError();
+ return FRS_NoViableFunction;
+ }
+ *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, &Range, 1,
+ Loc, 0, CandidateSet, &Best,
+ OverloadResult,
+ /*AllowTypoCorrection=*/false);
+ if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
+ *CallExpr = ExprError();
+ Diag(Range->getLocStart(), diag::note_in_for_range)
+ << RangeLoc << BEF << Range->getType();
+ return FRS_DiagnosticIssued;
+ }
+ }
+ return FRS_Success;
+}
+
+
/// FixOverloadedFunctionReference - E is an expression that refers to
/// a C++ overloaded function (possibly with some parentheses and
/// perhaps a '&' around it). We have resolved the overloaded function
@@ -11358,6 +11531,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs,
type, valueKind, OK_Ordinary);
ME->setHadMultipleCandidates(true);
+ MarkMemberReferenced(ME);
return ME;
}
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 722ac19be533..a8d75b290f19 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -31,6 +31,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
@@ -91,9 +92,8 @@ namespace {
return new (S.Context) GenericSelectionExpr(S.Context,
gse->getGenericLoc(),
gse->getControllingExpr(),
- assocTypes.data(),
- assocs.data(),
- numAssocs,
+ assocTypes,
+ assocs,
gse->getDefaultLoc(),
gse->getRParenLoc(),
gse->containsUnexpandedParameterPack(),
@@ -187,7 +187,7 @@ namespace {
UnaryOperatorKind opcode,
Expr *op);
- ExprResult complete(Expr *syntacticForm);
+ virtual ExprResult complete(Expr *syntacticForm);
OpaqueValueExpr *capture(Expr *op);
OpaqueValueExpr *captureValueAsResult(Expr *op);
@@ -198,7 +198,14 @@ namespace {
}
/// Return true if assignments have a non-void result.
- virtual bool assignmentsHaveResult() { return true; }
+ bool CanCaptureValueOfType(QualType ty) {
+ assert(!ty->isIncompleteType());
+ assert(!ty->isDependentType());
+
+ if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl())
+ return ClassDecl->isTriviallyCopyable();
+ return true;
+ }
virtual Expr *rebuildAndCaptureObject(Expr *) = 0;
virtual ExprResult buildGet() = 0;
@@ -206,7 +213,7 @@ namespace {
bool captureSetValueAsResult) = 0;
};
- /// A PseudoOpBuilder for Objective-C @properties.
+ /// A PseudoOpBuilder for Objective-C \@properties.
class ObjCPropertyOpBuilder : public PseudoOpBuilder {
ObjCPropertyRefExpr *RefExpr;
ObjCPropertyRefExpr *SyntacticRefExpr;
@@ -239,6 +246,9 @@ namespace {
Expr *rebuildAndCaptureObject(Expr *syntacticBase);
ExprResult buildGet();
ExprResult buildSet(Expr *op, SourceLocation, bool);
+ ExprResult complete(Expr *SyntacticForm);
+
+ bool isWeakProperty() const;
};
/// A PseudoOpBuilder for Objective-C array/dictionary indexing.
@@ -292,7 +302,7 @@ OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) {
/// operation. This routine is safe against expressions which may
/// already be captured.
///
-/// \param Returns the captured expression, which will be the
+/// \returns the captured expression, which will be the
/// same as the input if the input was already captured
OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) {
assert(ResultIndex == PseudoObjectExpr::NoResult);
@@ -353,7 +363,7 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
opcode, capturedRHS->getType(),
capturedRHS->getValueKind(),
- OK_Ordinary, opcLoc);
+ OK_Ordinary, opcLoc, false);
} else {
ExprResult opLHS = buildGet();
if (opLHS.isInvalid()) return ExprError();
@@ -372,12 +382,12 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
OK_Ordinary,
opLHS.get()->getType(),
result.get()->getType(),
- opcLoc);
+ opcLoc, false);
}
// The result of the assignment, if not void, is the value set into
// the l-value.
- result = buildSet(result.take(), opcLoc, assignmentsHaveResult());
+ result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true);
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.take());
@@ -401,7 +411,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
QualType resultType = result.get()->getType();
// That's the postfix result.
- if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) {
+ if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) {
result = capture(result.take());
setResultToLastSemantic();
}
@@ -420,8 +430,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
// Store that back into the result. The value stored is the result
// of a prefix operation.
- result = buildSet(result.take(), opcLoc,
- UnaryOperator::isPrefix(opcode) && assignmentsHaveResult());
+ result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode));
if (result.isInvalid()) return ExprError();
addSemanticExpr(result.take());
@@ -472,6 +481,23 @@ static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
return S.LookupMethodInObjectType(sel, IT, false);
}
+bool ObjCPropertyOpBuilder::isWeakProperty() const {
+ QualType T;
+ if (RefExpr->isExplicitProperty()) {
+ const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ return true;
+
+ T = Prop->getType();
+ } else if (Getter) {
+ T = Getter->getResultType();
+ } else {
+ return false;
+ }
+
+ return T.getObjCLifetime() == Qualifiers::OCL_Weak;
+}
+
bool ObjCPropertyOpBuilder::findGetter() {
if (Getter) return true;
@@ -532,7 +558,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
// Do a normal method lookup first.
if (ObjCMethodDecl *setter =
LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
- if (setter->isSynthesized() && warn)
+ if (setter->isPropertyAccessor() && warn)
if (const ObjCInterfaceDecl *IFace =
dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
const StringRef thisPropertyName(prop->getName());
@@ -617,7 +643,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
/// Store to an Objective-C property reference.
///
-/// \param bindSetValueAsResult - If true, capture the actual
+/// \param captureSetValueAsResult If true, capture the actual
/// value being set as the value of the property operation.
ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
@@ -676,7 +702,8 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- msgExpr->setArg(0, captureValueAsResult(arg));
+ if (CanCaptureValueOfType(arg->getType()))
+ msgExpr->setArg(0, captureValueAsResult(arg));
}
return msg;
@@ -819,6 +846,19 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);
}
+ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) {
+ DiagnosticsEngine::Level Level =
+ S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ SyntacticForm->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr,
+ SyntacticRefExpr->isMessagingGetter());
+ }
+
+ return PseudoOpBuilder::complete(SyntacticForm);
+}
+
// ObjCSubscript build stuff.
//
@@ -1035,7 +1075,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
0 /*TypeSourceInfo */,
S.Context.getTranslationUnitDecl(),
true /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1151,7 +1191,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
ResultTInfo,
S.Context.getTranslationUnitDecl(),
true /*Instance*/, false/*isVariadic*/,
- /*isSynthesized=*/false,
+ /*isPropertyAccessor=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required,
false);
@@ -1255,7 +1295,7 @@ ExprResult ObjCSubscriptOpBuilder::buildGet() {
/// Store into the container the "op" object at "Index"'ed location
/// by building this messaging expression:
/// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
-/// \param bindSetValueAsResult - If true, capture the actual
+/// \param captureSetValueAsResult If true, capture the actual
/// value being set as the value of the property operation.
ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
@@ -1279,7 +1319,8 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- msgExpr->setArg(0, captureValueAsResult(arg));
+ if (CanCaptureValueOfType(arg->getType()))
+ msgExpr->setArg(0, captureValueAsResult(arg));
}
return msg;
@@ -1333,7 +1374,7 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc);
+ VK_RValue, OK_Ordinary, opcLoc, false);
// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1404,14 +1445,14 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
cop->getObjectKind(),
cop->getComputationLHSType(),
cop->getComputationResultType(),
- cop->getOperatorLoc());
+ cop->getOperatorLoc(), false);
} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
bop->getType(), bop->getValueKind(),
bop->getObjectKind(),
- bop->getOperatorLoc());
+ bop->getOperatorLoc(), false);
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 86884b787339..f55174e05cc1 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -28,27 +28,10 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/MC/MCParser/MCAsmLexer.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
using namespace clang;
using namespace sema;
@@ -177,6 +160,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
return;
+ // If this is a GNU statement expression expanded from a macro, it is probably
+ // unused because it is a function-like macro that can be used as either an
+ // expression or statement. Don't warn, because it is almost certainly a
+ // false positive.
+ if (isa<StmtExpr>(E) && Loc.isMacroID())
+ return;
+
// Okay, we have an unused result. Depending on what the base expression is,
// we might want to make a more specific diagnostic. Check for one of these
// cases now.
@@ -271,7 +261,7 @@ StmtResult
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg elts, bool isStmtExpr) {
unsigned NumElts = elts.size();
- Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
+ Stmt **Elts = elts.data();
// 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) {
@@ -381,8 +371,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
// Otherwise, things are good. Fill in the declaration and return it.
LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
TheDecl->setStmt(LS);
- if (!TheDecl->isGnuLocal())
+ if (!TheDecl->isGnuLocal()) {
+ TheDecl->setLocStart(IdentLoc);
TheDecl->setLocation(IdentLoc);
+ }
return Owned(LS);
}
@@ -1566,25 +1558,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
ForLoc, RParenLoc));
}
-namespace {
-
-enum BeginEndFunction {
- BEF_begin,
- BEF_end
-};
-
-/// Build a variable declaration for a for-range statement.
-static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
- QualType Type, const char *Name) {
- DeclContext *DC = SemaRef.CurContext;
- IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
- TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
- VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
- TInfo, SC_Auto, SC_None);
- Decl->setImplicit();
- return Decl;
-}
-
/// Finish building a variable declaration for a for-range statement.
/// \return true if an error occurs.
static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
@@ -1617,12 +1590,14 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
return false;
}
+namespace {
+
/// Produce a note indicating which begin/end function was implicitly called
-/// by a C++0x for-range statement. This is often not obvious from the code,
+/// by a C++11 for-range statement. This is often not obvious from the code,
/// nor from the diagnostics produced when analysing the implicit expressions
/// required in a for-range statement.
void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
- BeginEndFunction BEF) {
+ Sema::BeginEndFunction BEF) {
CallExpr *CE = dyn_cast<CallExpr>(E);
if (!CE)
return;
@@ -1643,56 +1618,16 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
<< BEF << IsTemplate << Description << E->getType();
}
-/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the
-/// given LookupResult is non-empty, it is assumed to describe a member which
-/// will be invoked. Otherwise, the function will be found via argument
-/// dependent lookup.
-static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
- SourceLocation Loc,
- VarDecl *Decl,
- BeginEndFunction BEF,
- const DeclarationNameInfo &NameInfo,
- LookupResult &MemberLookup,
- Expr *Range) {
- ExprResult CallExpr;
- if (!MemberLookup.empty()) {
- ExprResult MemberRef =
- SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc,
- /*IsPtr=*/false, CXXScopeSpec(),
- /*TemplateKWLoc=*/SourceLocation(),
- /*FirstQualifierInScope=*/0,
- MemberLookup,
- /*TemplateArgs=*/0);
- if (MemberRef.isInvalid())
- return ExprError();
- CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(),
- Loc, 0);
- if (CallExpr.isInvalid())
- return ExprError();
- } else {
- UnresolvedSet<0> FoundNames;
- // C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace
- // std is an associated namespace.
- UnresolvedLookupExpr *Fn =
- UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0,
- NestedNameSpecifierLoc(), NameInfo,
- /*NeedsADL=*/true, /*Overloaded=*/false,
- FoundNames.begin(), FoundNames.end(),
- /*LookInStdNamespace=*/true);
- CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc,
- 0, /*AllowTypoCorrection=*/false);
- if (CallExpr.isInvalid()) {
- SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type)
- << Range->getType();
- return ExprError();
- }
- }
- if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF);
- return ExprError();
- }
- return CallExpr;
+/// Build a variable declaration for a for-range statement.
+VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
+ QualType Type, const char *Name) {
+ DeclContext *DC = SemaRef.CurContext;
+ IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
+ TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
+ VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
+ TInfo, SC_Auto, SC_None);
+ Decl->setImplicit();
+ return Decl;
}
}
@@ -1723,7 +1658,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
StmtResult
Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
Stmt *First, SourceLocation ColonLoc, Expr *Range,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc, BuildForRangeKind Kind) {
if (!First || !Range)
return StmtError();
@@ -1761,15 +1696,137 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
/*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
- RParenLoc);
+ RParenLoc, Kind);
}
-/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement.
+/// \brief Create the initialization, compare, and increment steps for
+/// the range-based for loop expression.
+/// This function does not handle array-based for loops,
+/// which are created in Sema::BuildCXXForRangeStmt.
+///
+/// \returns a ForRangeStatus indicating success or what kind of error occurred.
+/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
+/// CandidateSet and BEF are set and some non-success value is returned on
+/// failure.
+static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S,
+ Expr *BeginRange, Expr *EndRange,
+ QualType RangeType,
+ VarDecl *BeginVar,
+ VarDecl *EndVar,
+ SourceLocation ColonLoc,
+ OverloadCandidateSet *CandidateSet,
+ ExprResult *BeginExpr,
+ ExprResult *EndExpr,
+ Sema::BeginEndFunction *BEF) {
+ DeclarationNameInfo BeginNameInfo(
+ &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
+ DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
+ ColonLoc);
+
+ LookupResult BeginMemberLookup(SemaRef, BeginNameInfo,
+ Sema::LookupMemberName);
+ LookupResult EndMemberLookup(SemaRef, EndNameInfo, Sema::LookupMemberName);
+
+ if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
+ // - if _RangeT is a class type, the unqualified-ids begin and end are
+ // looked up in the scope of class _RangeT as if by class member access
+ // lookup (3.4.5), and if either (or both) finds at least one
+ // declaration, begin-expr and end-expr are __range.begin() and
+ // __range.end(), respectively;
+ SemaRef.LookupQualifiedName(BeginMemberLookup, D);
+ SemaRef.LookupQualifiedName(EndMemberLookup, D);
+
+ if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
+ SourceLocation RangeLoc = BeginVar->getLocation();
+ *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin;
+
+ SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch)
+ << RangeLoc << BeginRange->getType() << *BEF;
+ return Sema::FRS_DiagnosticIssued;
+ }
+ } else {
+ // - otherwise, begin-expr and end-expr are begin(__range) and
+ // end(__range), respectively, where begin and end are looked up with
+ // argument-dependent lookup (3.4.2). For the purposes of this name
+ // lookup, namespace std is an associated namespace.
+
+ }
+
+ *BEF = Sema::BEF_begin;
+ Sema::ForRangeStatus RangeStatus =
+ SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar,
+ Sema::BEF_begin, BeginNameInfo,
+ BeginMemberLookup, CandidateSet,
+ BeginRange, BeginExpr);
+
+ if (RangeStatus != Sema::FRS_Success)
+ return RangeStatus;
+ if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
+ return Sema::FRS_DiagnosticIssued;
+ }
+
+ *BEF = Sema::BEF_end;
+ RangeStatus =
+ SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar,
+ Sema::BEF_end, EndNameInfo,
+ EndMemberLookup, CandidateSet,
+ EndRange, EndExpr);
+ if (RangeStatus != Sema::FRS_Success)
+ return RangeStatus;
+ if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF);
+ return Sema::FRS_DiagnosticIssued;
+ }
+ return Sema::FRS_Success;
+}
+
+/// Speculatively attempt to dereference an invalid range expression.
+/// If the attempt fails, this function will return a valid, null StmtResult
+/// and emit no diagnostics.
+static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
+ SourceLocation ForLoc,
+ Stmt *LoopVarDecl,
+ SourceLocation ColonLoc,
+ Expr *Range,
+ SourceLocation RangeLoc,
+ SourceLocation RParenLoc) {
+ // Determine whether we can rebuild the for-range statement with a
+ // dereferenced range expression.
+ ExprResult AdjustedRange;
+ {
+ Sema::SFINAETrap Trap(SemaRef);
+
+ AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range);
+ if (AdjustedRange.isInvalid())
+ return StmtResult();
+
+ StmtResult SR =
+ SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc,
+ AdjustedRange.get(), RParenLoc,
+ Sema::BFRK_Check);
+ if (SR.isInvalid())
+ return StmtResult();
+ }
+
+ // The attempt to dereference worked well enough that it could produce a valid
+ // loop. Produce a fixit, and rebuild the loop with diagnostics enabled, in
+ // case there are any other (non-fatal) problems with it.
+ SemaRef.Diag(RangeLoc, diag::err_for_range_dereference)
+ << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*");
+ return SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc,
+ AdjustedRange.get(), RParenLoc,
+ Sema::BFRK_Rebuild);
+}
+
+/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc, BuildForRangeKind Kind) {
Scope *S = getCurScope();
DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
@@ -1855,50 +1912,43 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
return StmtError();
}
} else {
- DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"),
- ColonLoc);
- DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"),
- ColonLoc);
-
- LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName);
- LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName);
-
- if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) {
- // - if _RangeT is a class type, the unqualified-ids begin and end are
- // looked up in the scope of class _RangeT as if by class member access
- // lookup (3.4.5), and if either (or both) finds at least one
- // declaration, begin-expr and end-expr are __range.begin() and
- // __range.end(), respectively;
- LookupQualifiedName(BeginMemberLookup, D);
- LookupQualifiedName(EndMemberLookup, D);
-
- if (BeginMemberLookup.empty() != EndMemberLookup.empty()) {
- Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch)
- << RangeType << BeginMemberLookup.empty();
- return StmtError();
- }
- } else {
- // - otherwise, begin-expr and end-expr are begin(__range) and
- // end(__range), respectively, where begin and end are looked up with
- // argument-dependent lookup (3.4.2). For the purposes of this name
- // lookup, namespace std is an associated namespace.
+ OverloadCandidateSet CandidateSet(RangeLoc);
+ Sema::BeginEndFunction BEFFailure;
+ ForRangeStatus RangeStatus =
+ BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
+ EndRangeRef.get(), RangeType,
+ 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) {
+ StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
+ LoopVarDecl, ColonLoc,
+ Range, RangeLoc,
+ RParenLoc);
+ if (SR.isInvalid() || SR.isUsable())
+ return SR;
}
- BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
- BEF_begin, BeginNameInfo,
- BeginMemberLookup,
- BeginRangeRef.get());
- if (BeginExpr.isInvalid())
- return StmtError();
-
- EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
- BEF_end, EndNameInfo,
- EndMemberLookup, EndRangeRef.get());
- if (EndExpr.isInvalid())
+ // Otherwise, emit diagnostics if we haven't already.
+ if (RangeStatus == FRS_NoViableFunction) {
+ Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
+ Diag(Range->getLocStart(), diag::err_for_range_invalid)
+ << RangeLoc << Range->getType() << BEFFailure;
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(&Range, /*NumArgs=*/1));
+ }
+ // Return an error if no fix was discovered.
+ if (RangeStatus != FRS_Success)
return StmtError();
}
- // C++0x [decl.spec.auto]p6: BeginType and EndType must be the same.
+ assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
+ "invalid range expression in for loop");
+
+ // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
@@ -1930,6 +1980,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
if (NotEqExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 0 << BeginRangeRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
@@ -1945,6 +1997,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
if (IncrExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 2 << BeginRangeRef.get()->getType() ;
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
@@ -1957,12 +2011,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
+ Diag(RangeLoc, diag::note_for_range_invalid_iterator)
+ << RangeLoc << 1 << BeginRangeRef.get()->getType();
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
return StmtError();
}
- // Attach *__begin as initializer for VD.
- if (!LoopVar->isInvalidDecl()) {
+ // Attach *__begin as initializer for VD. Don't touch it if we're just
+ // trying to determine whether this would be a valid range.
+ if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false,
/*TypeMayContainAuto=*/true);
if (LoopVar->isInvalidDecl())
@@ -1973,6 +2030,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
RangeVar->setUsed();
}
+ // Don't bother to actually allocate the result if we're just trying to
+ // determine whether it would be valid.
+ if (Kind == BFRK_Check)
+ return StmtResult();
+
return Owned(new (Context) CXXForRangeStmt(RangeDS,
cast_or_null<DeclStmt>(BeginEndDecl.get()),
NotEqExpr.take(), IncrExpr.take(),
@@ -2485,600 +2547,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
return Owned(Result);
}
-/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
-/// ignore "noop" casts in places where an lvalue is required by an inline asm.
-/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
-/// provide a strong guidance to not use it.
-///
-/// This method checks to see if the argument is an acceptable l-value and
-/// returns false if it is a case we can handle.
-static bool CheckAsmLValue(const Expr *E, Sema &S) {
- // Type dependent expressions will be checked during instantiation.
- if (E->isTypeDependent())
- return false;
-
- if (E->isLValue())
- return false; // Cool, this is an lvalue.
-
- // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
- // are supposed to allow.
- const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
- if (E != E2 && E2->isLValue()) {
- if (!S.getLangOpts().HeinousExtensions)
- S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
- << E->getSourceRange();
- else
- S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
- << E->getSourceRange();
- // Accept, even if we emitted an error diagnostic.
- return false;
- }
-
- // None of the above, just randomly invalid non-lvalue.
- return true;
-}
-
-/// isOperandMentioned - Return true if the specified operand # is mentioned
-/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
- ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
- for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
- const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == OpNo)
- return true;
- }
- return false;
-}
-
-StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
- bool IsVolatile, unsigned NumOutputs,
- unsigned NumInputs, IdentifierInfo **Names,
- MultiExprArg constraints, MultiExprArg exprs,
- Expr *asmString, MultiExprArg clobbers,
- SourceLocation RParenLoc, bool MSAsm) {
- unsigned NumClobbers = clobbers.size();
- StringLiteral **Constraints =
- reinterpret_cast<StringLiteral**>(constraints.get());
- Expr **Exprs = exprs.get();
- StringLiteral *AsmString = cast<StringLiteral>(asmString);
- StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
-
- SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
-
- // The parser verifies that there is a string literal here.
- if (!AsmString->isAscii())
- return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
- << AsmString->getSourceRange());
-
- for (unsigned i = 0; i != NumOutputs; i++) {
- StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef OutputName;
- if (Names[i])
- OutputName = Names[i]->getName();
-
- TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
- if (!Context.getTargetInfo().validateOutputConstraint(Info))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_output_constraint)
- << Info.getConstraintStr());
-
- // Check that the output exprs are valid lvalues.
- Expr *OutputExpr = Exprs[i];
- if (CheckAsmLValue(OutputExpr, *this)) {
- return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_output)
- << OutputExpr->getSourceRange());
- }
-
- OutputConstraintInfos.push_back(Info);
- }
-
- SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
-
- for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
- StringLiteral *Literal = Constraints[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef InputName;
- if (Names[i])
- InputName = Names[i]->getName();
-
- TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
- if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
- NumOutputs, Info)) {
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_invalid_input_constraint)
- << Info.getConstraintStr());
- }
-
- Expr *InputExpr = Exprs[i];
-
- // Only allow void types for memory constraints.
- if (Info.allowsMemory() && !Info.allowsRegister()) {
- if (CheckAsmLValue(InputExpr, *this))
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_input)
- << Info.getConstraintStr()
- << InputExpr->getSourceRange());
- }
-
- if (Info.allowsRegister()) {
- if (InputExpr->getType()->isVoidType()) {
- return StmtError(Diag(InputExpr->getLocStart(),
- diag::err_asm_invalid_type_in_input)
- << InputExpr->getType() << Info.getConstraintStr()
- << InputExpr->getSourceRange());
- }
- }
-
- ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
- if (Result.isInvalid())
- return StmtError();
-
- Exprs[i] = Result.take();
- InputConstraintInfos.push_back(Info);
- }
-
- // Check that the clobbers are valid.
- for (unsigned i = 0; i != NumClobbers; i++) {
- StringLiteral *Literal = Clobbers[i];
- if (!Literal->isAscii())
- return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
- << Literal->getSourceRange());
-
- StringRef Clobber = Literal->getString();
-
- if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(Diag(Literal->getLocStart(),
- diag::err_asm_unknown_register_name) << Clobber);
- }
-
- AsmStmt *NS =
- new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
- NumOutputs, NumInputs, Names, Constraints, Exprs,
- AsmString, NumClobbers, Clobbers, RParenLoc);
- // Validate the asm string, ensuring it makes sense given the operands we
- // have.
- SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
- unsigned DiagOffs;
- if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
- Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
- << AsmString->getSourceRange();
- return StmtError();
- }
-
- // Validate tied input operands for type mismatches.
- for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
- TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
-
- // If this is a tied constraint, verify that the output and input have
- // either exactly the same type, or that they are int/ptr operands with the
- // same size (int/long, int*/long, are ok etc).
- if (!Info.hasTiedOperand()) continue;
-
- unsigned TiedTo = Info.getTiedOperand();
- unsigned InputOpNo = i+NumOutputs;
- Expr *OutputExpr = Exprs[TiedTo];
- Expr *InputExpr = Exprs[InputOpNo];
-
- if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
- continue;
-
- QualType InTy = InputExpr->getType();
- QualType OutTy = OutputExpr->getType();
- if (Context.hasSameType(InTy, OutTy))
- continue; // All types can be tied to themselves.
-
- // Decide if the input and output are in the same domain (integer/ptr or
- // floating point.
- enum AsmDomain {
- AD_Int, AD_FP, AD_Other
- } InputDomain, OutputDomain;
-
- if (InTy->isIntegerType() || InTy->isPointerType())
- InputDomain = AD_Int;
- else if (InTy->isRealFloatingType())
- InputDomain = AD_FP;
- else
- InputDomain = AD_Other;
-
- if (OutTy->isIntegerType() || OutTy->isPointerType())
- OutputDomain = AD_Int;
- else if (OutTy->isRealFloatingType())
- OutputDomain = AD_FP;
- else
- OutputDomain = AD_Other;
-
- // They are ok if they are the same size and in the same domain. This
- // allows tying things like:
- // void* to int*
- // void* to int if they are the same size.
- // double to long double if they are the same size.
- //
- uint64_t OutSize = Context.getTypeSize(OutTy);
- uint64_t InSize = Context.getTypeSize(InTy);
- if (OutSize == InSize && InputDomain == OutputDomain &&
- InputDomain != AD_Other)
- continue;
-
- // If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote the smaller one to a larger input and the asm string
- // won't notice.
- bool SmallerValueMentioned = false;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (isOperandMentioned(InputOpNo, Pieces)) {
- // This is a use in the asm string of the smaller operand. Since we
- // codegen this by promoting to a wider value, the asm will get printed
- // "wrong".
- SmallerValueMentioned |= InSize < OutSize;
- }
- if (isOperandMentioned(TiedTo, Pieces)) {
- // If this is a reference to the output, and if the output is the larger
- // value, then it's ok because we'll promote the input to the larger type.
- SmallerValueMentioned |= OutSize < InSize;
- }
-
- // If the smaller value wasn't mentioned in the asm string, and if the
- // output was a register, just extend the shorter one to the size of the
- // larger one.
- if (!SmallerValueMentioned && InputDomain != AD_Other &&
- OutputConstraintInfos[TiedTo].allowsRegister())
- continue;
-
- // Either both of the operands were mentioned or the smaller one was
- // mentioned. One more special case that we'll allow: if the tied input is
- // integer, unmentioned, and is a constant, then we'll allow truncating it
- // down to the size of the destination.
- if (InputDomain == AD_Int && OutputDomain == AD_Int &&
- !isOperandMentioned(InputOpNo, Pieces) &&
- InputExpr->isEvaluatable(Context)) {
- CastKind castKind =
- (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
- InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
- Exprs[InputOpNo] = InputExpr;
- NS->setInputExpr(i, InputExpr);
- continue;
- }
-
- Diag(InputExpr->getLocStart(),
- diag::err_asm_tying_incompatible_types)
- << InTy << OutTy << OutputExpr->getSourceRange()
- << InputExpr->getSourceRange();
- return StmtError();
- }
-
- return Owned(NS);
-}
-
-// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These
-// require special handling.
-static bool isMSAsmKeyword(StringRef Name) {
- bool Ret = llvm::StringSwitch<bool>(Name)
- .Cases("EVEN", "ALIGN", true) // Alignment directives.
- .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes.
- .Case("_emit", true) // _emit Pseudoinstruction.
- .Default(false);
- return Ret;
-}
-
-static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
- StringRef Asm;
- SmallString<512> TokenBuf;
- TokenBuf.resize(512);
- bool StringInvalid = false;
- Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
- assert (!StringInvalid && "Expected valid string!");
- return Asm;
-}
-
-static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple,
- SourceLocation AsmLoc,
- ArrayRef<Token> AsmToks,
- const TargetInfo &TI,
- std::vector<llvm::BitVector> &AsmRegs,
- std::vector<llvm::BitVector> &AsmNames,
- std::vector<std::string> &AsmStrings) {
- assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
- // Assume simple asm stmt until we parse a non-register identifer (or we just
- // need to bail gracefully).
- IsSimple = true;
-
- SmallString<512> Asm;
- unsigned NumAsmStrings = 0;
- for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) {
-
- // Determine if this should be considered a new asm.
- bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
- AsmToks[i].is(tok::kw_asm);
-
- // Emit the previous asm string.
- if (i && isNewAsm) {
- AsmStrings[NumAsmStrings++] = Asm.c_str();
- if (AsmToks[i].is(tok::kw_asm)) {
- ++i; // Skip __asm
- assert (i != e && "Expected another token.");
- }
- }
-
- // Start a new asm string with the opcode.
- if (isNewAsm) {
- AsmRegs[NumAsmStrings].resize(AsmToks.size());
- AsmNames[NumAsmStrings].resize(AsmToks.size());
-
- StringRef Piece = AsmToks[i].getIdentifierInfo()->getName();
- // MS-style inline asm keywords require special handling.
- if (isMSAsmKeyword(Piece))
- IsSimple = false;
-
- // TODO: Verify this is a valid opcode.
- Asm = Piece;
- continue;
- }
-
- if (i && AsmToks[i].hasLeadingSpace())
- Asm += ' ';
-
- // Check the operand(s).
- switch (AsmToks[i].getKind()) {
- default:
- IsSimple = false;
- Asm += getSpelling(SemaRef, AsmToks[i]);
- break;
- case tok::comma: Asm += ","; break;
- case tok::colon: Asm += ":"; break;
- case tok::l_square: Asm += "["; break;
- case tok::r_square: Asm += "]"; break;
- case tok::l_brace: Asm += "{"; break;
- case tok::r_brace: Asm += "}"; break;
- case tok::numeric_constant:
- Asm += getSpelling(SemaRef, AsmToks[i]);
- break;
- case tok::identifier: {
- IdentifierInfo *II = AsmToks[i].getIdentifierInfo();
- StringRef Name = II->getName();
-
- // Valid register?
- if (TI.isValidGCCRegisterName(Name)) {
- AsmRegs[NumAsmStrings].set(i);
- Asm += Name;
- break;
- }
-
- IsSimple = false;
-
- // MS-style inline asm keywords require special handling.
- if (isMSAsmKeyword(Name)) {
- IsSimple = false;
- Asm += Name;
- break;
- }
-
- // FIXME: Why are we missing this segment register?
- if (Name == "fs") {
- Asm += Name;
- break;
- }
-
- // Lookup the identifier.
- // TODO: Someone with more experience with clang should verify this the
- // proper way of doing a symbol lookup.
- DeclarationName DeclName(II);
- Scope *CurScope = SemaRef.getCurScope();
- LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName);
- if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/))
- break;
-
- assert (R.isSingleResult() && "Expected a single result?!");
- NamedDecl *Decl = R.getFoundDecl();
- switch (Decl->getKind()) {
- default:
- assert(0 && "Unknown decl kind.");
- break;
- case Decl::Var: {
- case Decl::ParmVar:
- AsmNames[NumAsmStrings].set(i);
-
- VarDecl *Var = cast<VarDecl>(Decl);
- QualType Ty = Var->getType();
- (void)Ty; // Avoid warning.
- // TODO: Patch identifier with valid operand. One potential idea is to
- // probe the backend with type information to guess the possible
- // operand.
- break;
- }
- }
- break;
- }
- }
- }
-
- // Emit the final (and possibly only) asm string.
- AsmStrings[NumAsmStrings] = Asm.c_str();
-}
-
-// Build the unmodified MSAsmString.
-static std::string buildMSAsmString(Sema &SemaRef,
- ArrayRef<Token> AsmToks,
- unsigned &NumAsmStrings) {
- assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
- NumAsmStrings = 0;
-
- SmallString<512> Asm;
- for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
- bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
- AsmToks[i].is(tok::kw_asm);
-
- if (isNewAsm) {
- ++NumAsmStrings;
- if (i)
- Asm += '\n';
- if (AsmToks[i].is(tok::kw_asm)) {
- i++; // Skip __asm
- assert (i != e && "Expected another token");
- }
- }
-
- if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
- Asm += ' ';
-
- Asm += getSpelling(SemaRef, AsmToks[i]);
- }
- return Asm.c_str();
-}
-
-StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
- SourceLocation LBraceLoc,
- ArrayRef<Token> AsmToks,
- SourceLocation EndLoc) {
- // MS-style inline assembly is not fully supported, so emit a warning.
- Diag(AsmLoc, diag::warn_unsupported_msasm);
- SmallVector<StringRef,4> Clobbers;
- std::set<std::string> ClobberRegs;
- SmallVector<IdentifierInfo*, 4> Inputs;
- SmallVector<IdentifierInfo*, 4> Outputs;
-
- // Empty asm statements don't need to instantiate the AsmParser, etc.
- if (AsmToks.empty()) {
- StringRef AsmString;
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
- }
-
- unsigned NumAsmStrings;
- std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings);
-
- bool IsSimple;
- std::vector<llvm::BitVector> Regs;
- std::vector<llvm::BitVector> Names;
- std::vector<std::string> PatchedAsmStrings;
-
- Regs.resize(NumAsmStrings);
- Names.resize(NumAsmStrings);
- PatchedAsmStrings.resize(NumAsmStrings);
-
- // Rewrite operands to appease the AsmParser.
- patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks,
- Context.getTargetInfo(), Regs, Names, PatchedAsmStrings);
-
- // patchMSAsmStrings doesn't correctly patch non-simple asm statements.
- if (!IsSimple) {
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
- }
-
- // Initialize targets and assembly printers/parsers.
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmParsers();
-
- // Get the target specific parser.
- std::string Error;
- const std::string &TT = Context.getTargetInfo().getTriple().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::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
- OwningPtr<llvm::MCSubtargetInfo>
- STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
-
- for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) {
- llvm::SourceMgr SrcMgr;
- llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
- llvm::MemoryBuffer *Buffer =
- llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<inline asm>");
-
- // Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
-
- OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
- OwningPtr<llvm::MCAsmParser>
- Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
- OwningPtr<llvm::MCTargetAsmParser>
- TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
- // Change to the Intel dialect.
- Parser->setAssemblerDialect(1);
- Parser->setTargetParser(*TargetParser.get());
-
- // Prime the lexer.
- Parser->Lex();
-
- // Parse the opcode.
- StringRef IDVal;
- Parser->ParseIdentifier(IDVal);
-
- // Canonicalize the opcode to lower case.
- SmallString<128> Opcode;
- for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
- Opcode.push_back(tolower(IDVal[i]));
-
- // Parse the operands.
- llvm::SMLoc IDLoc;
- SmallVector<llvm::MCParsedAsmOperand*, 8> Operands;
- bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc,
- Operands);
- assert (!HadError && "Unexpected error parsing instruction");
-
- // Match the MCInstr.
- SmallVector<llvm::MCInst, 2> Instrs;
- HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs);
- assert (!HadError && "Unexpected error matching instruction");
- assert ((Instrs.size() == 1) && "Expected only a single instruction.");
-
- // Get the instruction descriptor.
- llvm::MCInst Inst = Instrs[0];
- const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
- const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode());
- llvm::MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
-
- // Build the list of clobbers.
- for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) {
- const llvm::MCOperand &Op = Inst.getOperand(i);
- if (!Op.isReg())
- continue;
-
- std::string Reg;
- llvm::raw_string_ostream OS(Reg);
- IP->printRegName(OS, Op.getReg());
-
- StringRef Clobber(OS.str());
- if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) <<
- Clobber);
- ClobberRegs.insert(Reg);
- }
- }
- for (std::set<std::string>::iterator I = ClobberRegs.begin(),
- E = ClobberRegs.end(); I != E; ++I)
- Clobbers.push_back(*I);
-
- MSAsmStmt *NS =
- new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
- /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
- AsmString, Clobbers, EndLoc);
- return Owned(NS);
-}
-
StmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, Decl *Parm,
@@ -3104,7 +2572,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
getCurFunction()->setHasBranchProtectedScope();
unsigned NumCatchStmts = CatchStmts.size();
return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try,
- CatchStmts.release(),
+ CatchStmts.data(),
NumCatchStmts,
Finally));
}
@@ -3239,7 +2707,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
unsigned NumHandlers = RawHandlers.size();
assert(NumHandlers > 0 &&
"The parser shouldn't call this if there are no handlers.");
- Stmt **Handlers = RawHandlers.get();
+ Stmt **Handlers = RawHandlers.data();
SmallVector<TypeWithHandler, 8> TypesWithHandlers;
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
new file mode 100644
index 000000000000..7c2c766e4615
--- /dev/null
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -0,0 +1,661 @@
+//===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for inline asm statements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+using namespace clang;
+using namespace sema;
+
+/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
+/// ignore "noop" casts in places where an lvalue is required by an inline asm.
+/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
+/// provide a strong guidance to not use it.
+///
+/// This method checks to see if the argument is an acceptable l-value and
+/// returns false if it is a case we can handle.
+static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ // Type dependent expressions will be checked during instantiation.
+ if (E->isTypeDependent())
+ return false;
+
+ if (E->isLValue())
+ return false; // Cool, this is an lvalue.
+
+ // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
+ // are supposed to allow.
+ const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
+ if (E != E2 && E2->isLValue()) {
+ if (!S.getLangOpts().HeinousExtensions)
+ S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ else
+ S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+ << E->getSourceRange();
+ // Accept, even if we emitted an error diagnostic.
+ return false;
+ }
+
+ // None of the above, just randomly invalid non-lvalue.
+ return true;
+}
+
+/// isOperandMentioned - Return true if the specified operand # is mentioned
+/// anywhere in the decomposed asm string.
+static bool isOperandMentioned(unsigned OpNo,
+ ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
+ for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
+ const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == OpNo)
+ return true;
+ }
+ return false;
+}
+
+StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ 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());
+
+ SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+
+ // The parser verifies that there is a string literal here.
+ if (!AsmString->isAscii())
+ return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
+ << AsmString->getSourceRange());
+
+ for (unsigned i = 0; i != NumOutputs; i++) {
+ StringLiteral *Literal = Constraints[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef OutputName;
+ if (Names[i])
+ OutputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
+ if (!Context.getTargetInfo().validateOutputConstraint(Info))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_output_constraint)
+ << Info.getConstraintStr());
+
+ // Check that the output exprs are valid lvalues.
+ Expr *OutputExpr = Exprs[i];
+ if (CheckAsmLValue(OutputExpr, *this)) {
+ return StmtError(Diag(OutputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+ }
+
+ OutputConstraintInfos.push_back(Info);
+ }
+
+ SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+
+ for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
+ StringLiteral *Literal = Constraints[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef InputName;
+ if (Names[i])
+ InputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
+ if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
+ NumOutputs, Info)) {
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_invalid_input_constraint)
+ << Info.getConstraintStr());
+ }
+
+ Expr *InputExpr = Exprs[i];
+
+ // Only allow void types for memory constraints.
+ if (Info.allowsMemory() && !Info.allowsRegister()) {
+ if (CheckAsmLValue(InputExpr, *this))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_lvalue_in_input)
+ << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+
+ if (Info.allowsRegister()) {
+ if (InputExpr->getType()->isVoidType()) {
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_type_in_input)
+ << InputExpr->getType() << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
+ }
+
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
+ if (Result.isInvalid())
+ return StmtError();
+
+ Exprs[i] = Result.take();
+ InputConstraintInfos.push_back(Info);
+ }
+
+ // Check that the clobbers are valid.
+ for (unsigned i = 0; i != NumClobbers; i++) {
+ StringLiteral *Literal = Clobbers[i];
+ if (!Literal->isAscii())
+ return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+ << Literal->getSourceRange());
+
+ StringRef Clobber = Literal->getString();
+
+ if (!Context.getTargetInfo().isValidClobber(Clobber))
+ return StmtError(Diag(Literal->getLocStart(),
+ diag::err_asm_unknown_register_name) << Clobber);
+ }
+
+ GCCAsmStmt *NS =
+ new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs, AsmString,
+ NumClobbers, Clobbers, RParenLoc);
+ // Validate the asm string, ensuring it makes sense given the operands we
+ // have.
+ SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
+ unsigned DiagOffs;
+ if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
+ Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
+ << AsmString->getSourceRange();
+ return StmtError();
+ }
+
+ // Validate constraints and modifiers.
+ for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
+ GCCAsmStmt::AsmStringPiece &Piece = Pieces[i];
+ if (!Piece.isOperand()) continue;
+
+ // Look for the correct constraint index.
+ unsigned Idx = 0;
+ unsigned ConstraintIdx = 0;
+ for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) {
+ TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+
+ if (Info.isReadWrite()) {
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+ }
+ }
+
+ for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) {
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+
+ if (Info.isReadWrite()) {
+ if (Idx == Piece.getOperandNo())
+ break;
+ ++Idx;
+ }
+ }
+
+ // Now that we have the right indexes go ahead and check.
+ StringLiteral *Literal = Constraints[ConstraintIdx];
+ const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr();
+ if (Ty->isDependentType() || Ty->isIncompleteType())
+ continue;
+
+ unsigned Size = Context.getTypeSize(Ty);
+ if (!Context.getTargetInfo()
+ .validateConstraintModifier(Literal->getString(), Piece.getModifier(),
+ Size))
+ Diag(Exprs[ConstraintIdx]->getLocStart(),
+ diag::warn_asm_mismatched_size_modifier);
+ }
+
+ // Validate tied input operands for type mismatches.
+ for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
+ TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+
+ // If this is a tied constraint, verify that the output and input have
+ // either exactly the same type, or that they are int/ptr operands with the
+ // same size (int/long, int*/long, are ok etc).
+ if (!Info.hasTiedOperand()) continue;
+
+ unsigned TiedTo = Info.getTiedOperand();
+ unsigned InputOpNo = i+NumOutputs;
+ Expr *OutputExpr = Exprs[TiedTo];
+ Expr *InputExpr = Exprs[InputOpNo];
+
+ if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
+ continue;
+
+ QualType InTy = InputExpr->getType();
+ QualType OutTy = OutputExpr->getType();
+ if (Context.hasSameType(InTy, OutTy))
+ continue; // All types can be tied to themselves.
+
+ // Decide if the input and output are in the same domain (integer/ptr or
+ // floating point.
+ enum AsmDomain {
+ AD_Int, AD_FP, AD_Other
+ } InputDomain, OutputDomain;
+
+ if (InTy->isIntegerType() || InTy->isPointerType())
+ InputDomain = AD_Int;
+ else if (InTy->isRealFloatingType())
+ InputDomain = AD_FP;
+ else
+ InputDomain = AD_Other;
+
+ if (OutTy->isIntegerType() || OutTy->isPointerType())
+ OutputDomain = AD_Int;
+ else if (OutTy->isRealFloatingType())
+ OutputDomain = AD_FP;
+ else
+ OutputDomain = AD_Other;
+
+ // They are ok if they are the same size and in the same domain. This
+ // allows tying things like:
+ // void* to int*
+ // void* to int if they are the same size.
+ // double to long double if they are the same size.
+ //
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize && InputDomain == OutputDomain &&
+ InputDomain != AD_Other)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote the smaller one to a larger input and the asm string
+ // won't notice.
+ bool SmallerValueMentioned = false;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (isOperandMentioned(InputOpNo, Pieces)) {
+ // This is a use in the asm string of the smaller operand. Since we
+ // codegen this by promoting to a wider value, the asm will get printed
+ // "wrong".
+ SmallerValueMentioned |= InSize < OutSize;
+ }
+ if (isOperandMentioned(TiedTo, Pieces)) {
+ // If this is a reference to the output, and if the output is the larger
+ // value, then it's ok because we'll promote the input to the larger type.
+ SmallerValueMentioned |= OutSize < InSize;
+ }
+
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned && InputDomain != AD_Other &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+
+ // Either both of the operands were mentioned or the smaller one was
+ // mentioned. One more special case that we'll allow: if the tied input is
+ // integer, unmentioned, and is a constant, then we'll allow truncating it
+ // down to the size of the destination.
+ if (InputDomain == AD_Int && OutputDomain == AD_Int &&
+ !isOperandMentioned(InputOpNo, Pieces) &&
+ InputExpr->isEvaluatable(Context)) {
+ CastKind castKind =
+ (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
+ Exprs[InputOpNo] = InputExpr;
+ NS->setInputExpr(i, InputExpr);
+ continue;
+ }
+
+ Diag(InputExpr->getLocStart(),
+ diag::err_asm_tying_incompatible_types)
+ << InTy << OutTy << OutputExpr->getSourceRange()
+ << InputExpr->getSourceRange();
+ return StmtError();
+ }
+
+ return Owned(NS);
+}
+
+// getSpelling - Get the spelling of the AsmTok token.
+static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
+ StringRef Asm;
+ SmallString<512> TokenBuf;
+ TokenBuf.resize(512);
+ bool StringInvalid = false;
+ Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
+ assert (!StringInvalid && "Expected valid string!");
+ return Asm;
+}
+
+// Build the inline assembly string. Returns true on error.
+static bool buildMSAsmString(Sema &SemaRef,
+ SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ llvm::SmallVectorImpl<unsigned> &TokOffsets,
+ std::string &AsmString) {
+ assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+ SmallString<512> Asm;
+ for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+ bool isNewAsm = ((i == 0) ||
+ AsmToks[i].isAtStartOfLine() ||
+ AsmToks[i].is(tok::kw_asm));
+ if (isNewAsm) {
+ if (i != 0)
+ Asm += "\n\t";
+
+ if (AsmToks[i].is(tok::kw_asm)) {
+ i++; // Skip __asm
+ if (i == e) {
+ SemaRef.Diag(AsmLoc, diag::err_asm_empty);
+ return true;
+ }
+
+ }
+ }
+
+ if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
+ Asm += ' ';
+
+ StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
+ Asm += Spelling;
+ TokOffsets.push_back(Asm.size());
+ }
+ AsmString = Asm.str();
+ return false;
+}
+
+namespace {
+
+class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback {
+ Sema &SemaRef;
+ SourceLocation AsmLoc;
+ ArrayRef<Token> AsmToks;
+ ArrayRef<unsigned> TokOffsets;
+
+public:
+ MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc,
+ ArrayRef<Token> Toks,
+ ArrayRef<unsigned> Offsets)
+ : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
+ ~MCAsmParserSemaCallbackImpl() {}
+
+ void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){
+ SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
+ NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size);
+ return static_cast<void *>(OpDecl);
+ }
+
+ bool LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset) {
+ return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc);
+ }
+
+ static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D,
+ void *Context) {
+ ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D);
+ }
+ void MSAsmDiagHandler(const llvm::SMDiagnostic &D) {
+ // Compute an offset into the inline asm buffer.
+ // FIXME: This isn't right if .macro is involved (but hopefully, no
+ // real-world code does that).
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ const llvm::MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+
+ // Figure out which token that offset points into.
+ const unsigned *OffsetPtr =
+ std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset);
+ unsigned TokIndex = OffsetPtr - TokOffsets.begin();
+
+ // If we come up with an answer which seems sane, use it; otherwise,
+ // just point at the __asm keyword.
+ // FIXME: Assert the answer is sane once we handle .macro correctly.
+ SourceLocation Loc = AsmLoc;
+ if (TokIndex < AsmToks.size()) {
+ const Token *Tok = &AsmToks[TokIndex];
+ Loc = Tok->getLocation();
+ Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength()));
+ }
+ SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+ }
+};
+
+}
+
+NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
+ unsigned &Size) {
+ Size = 0;
+ LookupResult Result(*this, &Context.Idents.get(Name), Loc,
+ Sema::LookupOrdinaryName);
+
+ if (!LookupName(Result, getCurScope())) {
+ // If we don't find anything, return null; the AsmParser will assume
+ // it is a label of some sort.
+ return 0;
+ }
+
+ if (!Result.isSingleResult()) {
+ // FIXME: Diagnose result.
+ return 0;
+ }
+
+ NamedDecl *ND = Result.getFoundDecl();
+ if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(ND))
+ Size = Context.getTypeInfo(Var->getType()).first;
+
+ return ND;
+ }
+
+ // FIXME: Handle other kinds of results? (FieldDecl, etc.)
+ // FIXME: Diagnose if we find something we can't handle, like a typedef.
+ return 0;
+}
+
+bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset, SourceLocation AsmLoc) {
+ Offset = 0;
+ LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
+ LookupOrdinaryName);
+
+ if (!LookupName(BaseResult, getCurScope()))
+ return true;
+
+ if (!BaseResult.isSingleResult())
+ return true;
+
+ NamedDecl *FoundDecl = BaseResult.getFoundDecl();
+ const RecordType *RT = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) {
+ RT = VD->getType()->getAs<RecordType>();
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) {
+ RT = TD->getUnderlyingType()->getAs<RecordType>();
+ }
+ if (!RT)
+ return true;
+
+ if (RequireCompleteType(AsmLoc, QualType(RT, 0), 0))
+ return true;
+
+ LookupResult FieldResult(*this, &Context.Idents.get(Member), SourceLocation(),
+ LookupMemberName);
+
+ if (!LookupQualifiedName(FieldResult, RT->getDecl()))
+ return true;
+
+ // FIXME: Handle IndirectFieldDecl?
+ FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
+ if (!FD)
+ return true;
+
+ const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
+ unsigned i = FD->getFieldIndex();
+ CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
+ Offset = (unsigned)Result.getQuantity();
+
+ return false;
+}
+
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
+ ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
+ SmallVector<IdentifierInfo*, 4> Names;
+ SmallVector<StringRef, 4> ConstraintRefs;
+ SmallVector<Expr*, 4> Exprs;
+ SmallVector<StringRef, 4> ClobberRefs;
+
+ // Empty asm statements don't need to instantiate the AsmParser, etc.
+ if (AsmToks.empty()) {
+ StringRef EmptyAsmStr;
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
+ /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0,
+ /*NumInputs*/ 0, Names, ConstraintRefs, Exprs,
+ EmptyAsmStr, ClobberRefs, EndLoc);
+ return Owned(NS);
+ }
+
+ std::string AsmString;
+ llvm::SmallVector<unsigned, 8> TokOffsets;
+ if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString))
+ return StmtError();
+
+ // Get the target specific parser.
+ std::string Error;
+ const std::string &TT = Context.getTargetInfo().getTriple().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::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+ OwningPtr<llvm::MCSubtargetInfo>
+ STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+ llvm::SourceMgr SrcMgr;
+ llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ llvm::MemoryBuffer *Buffer =
+ llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>");
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+ OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
+ OwningPtr<llvm::MCAsmParser>
+ Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+ OwningPtr<llvm::MCTargetAsmParser>
+ TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
+
+ // Get the instruction descriptor.
+ const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+ llvm::MCInstPrinter *IP =
+ TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+
+ // Change to the Intel dialect.
+ Parser->setAssemblerDialect(1);
+ Parser->setTargetParser(*TargetParser.get());
+ Parser->setParsingInlineAsm(true);
+ TargetParser->setParsingInlineAsm(true);
+
+ MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets);
+ TargetParser->setSemaCallback(&MCAPSI);
+ SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback,
+ &MCAPSI);
+
+ unsigned NumOutputs;
+ unsigned NumInputs;
+ std::string AsmStringIR;
+ SmallVector<std::pair<void *, bool>, 4> OpDecls;
+ SmallVector<std::string, 4> Constraints;
+ SmallVector<std::string, 4> Clobbers;
+ if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
+ NumOutputs, NumInputs, OpDecls, Constraints,
+ Clobbers, MII, IP, MCAPSI))
+ return StmtError();
+
+ // Build the vector of clobber StringRefs.
+ unsigned NumClobbers = Clobbers.size();
+ ClobberRefs.resize(NumClobbers);
+ for (unsigned i = 0; i != NumClobbers; ++i)
+ ClobberRefs[i] = StringRef(Clobbers[i]);
+
+ // Recast the void pointers and build the vector of constraint StringRefs.
+ unsigned NumExprs = NumOutputs + NumInputs;
+ Names.resize(NumExprs);
+ ConstraintRefs.resize(NumExprs);
+ Exprs.resize(NumExprs);
+ for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+ NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first);
+ if (!OpDecl)
+ return StmtError();
+
+ DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc);
+ ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo,
+ OpDecl);
+ if (OpExpr.isInvalid())
+ return StmtError();
+
+ // Need offset of variable.
+ if (OpDecls[i].second)
+ OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf,
+ OpExpr.take());
+
+ Names[i] = OpDecl->getIdentifier();
+ ConstraintRefs[i] = StringRef(Constraints[i]);
+ Exprs[i] = OpExpr.take();
+ }
+
+ bool IsSimple = NumExprs > 0;
+ MSAsmStmt *NS =
+ new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
+ /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
+ Names, ConstraintRefs, Exprs, AsmStringIR,
+ ClobberRefs, EndLoc);
+ return Owned(NS);
+}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 3c15b7a8afad..b268b4502c4f 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -48,11 +48,16 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
switch (A.getKind()) {
+ case AttributeList::UnknownAttribute:
+ S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
+ diag::warn_unhandled_ms_attribute_ignored :
+ diag::warn_unknown_attribute_ignored) << A.getName();
+ return 0;
case AttributeList::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
default:
- // if we're here, then we parsed an attribute, but didn't recognize it as a
- // statement attribute => it is declaration attribute
+ // if we're here, then we parsed a known attribute, but didn't recognize
+ // it as a statement attribute => it is declaration attribute
S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt)
<< A.getName()->getName() << St->getLocStart();
return 0;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4dbf3e45b387..f56b05406d07 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -333,7 +333,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
<< Name << CorrectedQuotedStr
@@ -1104,6 +1105,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
+ if (PrevClassTemplate)
+ mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
+
AddPushedVisibilityAttribute(NewClass);
if (TUK != TUK_Friend)
@@ -1138,8 +1142,6 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
}
- if (PrevClassTemplate)
- mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
ActOnDocumentableDecl(NewTemplate);
@@ -1204,11 +1206,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
/// of a template template parameter, recursively.
static bool DiagnoseUnexpandedParameterPacks(Sema &S,
TemplateTemplateParmDecl *TTP) {
+ // A template template parameter which is a parameter pack is also a pack
+ // expansion.
+ if (TTP->isParameterPack())
+ return false;
+
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
- if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
+ if (!NTTP->isParameterPack() &&
+ S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
NTTP->getTypeSourceInfo(),
Sema::UPPC_NonTypeTemplateParameterType))
return true;
@@ -1321,7 +1329,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
+ if (!NewNonTypeParm->isParameterPack() &&
+ DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
NewNonTypeParm->getTypeSourceInfo(),
UPPC_NonTypeTemplateParameterType)) {
Invalid = true;
@@ -1342,7 +1351,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewNonTypeParm->isParameterPack()) {
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
- SawParameterPack = true;
+ if (!NewNonTypeParm->isPackExpansion())
+ SawParameterPack = true;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
@@ -1389,7 +1399,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewTemplateParm->isParameterPack()) {
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
- SawParameterPack = true;
+ if (!NewTemplateParm->isPackExpansion())
+ SawParameterPack = true;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
@@ -1416,10 +1427,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
}
- // C++0x [temp.param]p11:
+ // C++11 [temp.param]p11:
// 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 &&
+ if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
(TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag((*NewParam)->getLocation(),
diag::err_template_param_pack_must_be_last_template_parameter);
@@ -1998,9 +2009,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
for (unsigned I = 0; I < Depth; ++I)
TemplateArgLists.addOuterTemplateArguments(0, 0);
+ LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
if (Inst)
return QualType();
+
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
@@ -2085,7 +2098,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Converted.data(),
Converted.size(), 0);
ClassTemplate->AddSpecialization(Decl, InsertPos);
- Decl->setLexicalDeclContext(CurContext);
+ if (ClassTemplate->isOutOfLine())
+ Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
}
CanonType = Context.getTypeDeclType(Decl);
@@ -2137,7 +2151,6 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
}
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
- TemplateArgsIn.release();
if (Result.isNull())
return true;
@@ -2831,6 +2844,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
Converted.push_back(Arg.getArgument());
@@ -2947,7 +2961,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (CheckTemplateArgument(TempParm, Arg))
+ if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex))
return true;
Converted.push_back(Arg.getArgument());
@@ -2965,6 +2979,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
llvm_unreachable("Integral argument with template template parameter");
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Null pointer argument with template template parameter");
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
@@ -2996,6 +3012,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
return true;
}
+/// \brief Check whether the template parameter is a pack expansion, and if so,
+/// determine the number of parameters produced by that expansion. For instance:
+///
+/// \code
+/// template<typename ...Ts> struct A {
+/// template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B;
+/// };
+/// \endcode
+///
+/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
+/// is not a pack expansion, so returns an empty Optional.
+static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (NTTP->isExpandedParameterPack())
+ return NTTP->getNumExpansionTypes();
+ }
+
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionTemplateParameters();
+ }
+
+ return llvm::Optional<unsigned>();
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@@ -3008,15 +3051,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
*ExpansionIntoFixedList = false;
TemplateParameterList *Params = Template->getTemplateParameters();
- unsigned NumParams = Params->size();
- unsigned NumArgs = TemplateArgs.size();
- bool Invalid = false;
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
- bool HasParameterPack =
- NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
// C++ [temp.arg]p1:
// [...] The type and form of each template-argument specified in
// a template-id shall match the type and form specified for the
@@ -3024,38 +3061,50 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
SmallVector<TemplateArgument, 2> ArgumentPack;
- TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- unsigned ArgIdx = 0;
+ unsigned ArgIdx = 0, NumArgs = TemplateArgs.size();
LocalInstantiationScope InstScope(*this, true);
- bool SawPackExpansion = false;
- while (Param != ParamEnd) {
- if (ArgIdx < NumArgs) {
- // If we have an expanded parameter pack, make sure we don't have too
- // many arguments.
- // FIXME: This really should fall out from the normal arity checking.
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (NTTP->isExpandedParameterPack() &&
- ArgumentPack.size() >= NTTP->getNumExpansionTypes()) {
- Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
- << true
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
- << Template;
- Diag(Template->getLocation(), diag::note_template_decl_here)
- << Params->getSourceRange();
- return true;
- }
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; /* increment in loop */) {
+ // If we have an expanded parameter pack, make sure we don't have too
+ // many arguments.
+ if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (*Expansions == ArgumentPack.size()) {
+ // We're done with this parameter pack. Pack up its arguments and add
+ // them to the list.
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+
+ // This argument is assigned to the next parameter.
+ ++Param;
+ continue;
+ } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
+ // Not enough arguments for this parameter pack.
+ Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+ << false
+ << (isa<ClassTemplateDecl>(Template)? 0 :
+ isa<FunctionTemplateDecl>(Template)? 1 :
+ isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << Template;
+ Diag(Template->getLocation(), diag::note_template_decl_here)
+ << Params->getSourceRange();
+ return true;
}
+ }
+ if (ArgIdx < NumArgs) {
// Check the template argument we were given.
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
TemplateLoc, RAngleLoc,
ArgumentPack.size(), Converted))
return true;
+ // We're now done with this argument.
+ ++ArgIdx;
+
if ((*Param)->isTemplateParameterPack()) {
// The template parameter was a template parameter pack, so take the
// deduced argument and place it on the argument pack. Note that we
@@ -3067,16 +3116,47 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Move to the next template parameter.
++Param;
}
-
- // If this template argument is a pack expansion, record that fact
- // and break out; we can't actually check any more.
- if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
- SawPackExpansion = true;
- ++ArgIdx;
- break;
+
+ // If we just saw a pack expansion, then directly convert the remaining
+ // arguments, because we don't know what parameters they'll match up
+ // with.
+ if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) {
+ bool InFinalParameterPack = Param != ParamEnd &&
+ Param + 1 == ParamEnd &&
+ (*Param)->isTemplateParameterPack() &&
+ !getExpandedPackSize(*Param);
+
+ if (!InFinalParameterPack && !ArgumentPack.empty()) {
+ // If we were part way through filling in an expanded parameter pack,
+ // fall back to just producing individual arguments.
+ Converted.insert(Converted.end(),
+ ArgumentPack.begin(), ArgumentPack.end());
+ ArgumentPack.clear();
+ }
+
+ while (ArgIdx < NumArgs) {
+ if (InFinalParameterPack)
+ ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
+ else
+ Converted.push_back(TemplateArgs[ArgIdx].getArgument());
+ ++ArgIdx;
+ }
+
+ // Push the argument pack onto the list of converted arguments.
+ if (InFinalParameterPack) {
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+ } else if (ExpansionIntoFixedList) {
+ // We have expanded a pack into a fixed list.
+ *ExpansionIntoFixedList = true;
+ }
+
+ return false;
}
-
- ++ArgIdx;
+
continue;
}
@@ -3087,14 +3167,30 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.data(),
ArgumentPack.size()));
- return Invalid;
+ return false;
}
// If we have a template parameter pack with no more corresponding
// arguments, just break out now and we'll fill in the argument pack below.
- if ((*Param)->isTemplateParameterPack())
- break;
-
+ if ((*Param)->isTemplateParameterPack()) {
+ assert(!getExpandedPackSize(*Param) &&
+ "Should have dealt with this already");
+
+ // A non-expanded parameter pack before the end of the parameter list
+ // only occurs for an ill-formed template parameter list, unless we've
+ // got a partial argument list for a function template, so just bail out.
+ if (Param + 1 != ParamEnd)
+ return true;
+
+ Converted.push_back(TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+
+ ++Param;
+ continue;
+ }
+
// Check whether we have a default argument.
TemplateArgumentLoc Arg;
@@ -3181,86 +3277,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
++ArgIdx;
}
- // If we saw a pack expansion, then directly convert the remaining arguments,
- // because we don't know what parameters they'll match up with.
- if (SawPackExpansion) {
- bool AddToArgumentPack
- = Param != ParamEnd && (*Param)->isTemplateParameterPack();
- while (ArgIdx < NumArgs) {
- if (AddToArgumentPack)
- ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
- else
- Converted.push_back(TemplateArgs[ArgIdx].getArgument());
- ++ArgIdx;
- }
-
- // Push the argument pack onto the list of converted arguments.
- if (AddToArgumentPack) {
- if (ArgumentPack.empty())
- Converted.push_back(TemplateArgument(0, 0));
- else {
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
- ArgumentPack.clear();
- }
- } else if (ExpansionIntoFixedList) {
- // We have expanded a pack into a fixed list.
- *ExpansionIntoFixedList = true;
- }
-
- return Invalid;
- }
-
// If we have any leftover arguments, then there were too many arguments.
// Complain and fail.
if (ArgIdx < NumArgs)
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
-
- // If we have an expanded parameter pack, make sure we don't have too
- // many arguments.
- // FIXME: This really should fall out from the normal arity checking.
- if (Param != ParamEnd) {
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (NTTP->isExpandedParameterPack() &&
- ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
- Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
- << false
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
- << Template;
- Diag(Template->getLocation(), diag::note_template_decl_here)
- << Params->getSourceRange();
- return true;
- }
- }
- }
-
- // Form argument packs for each of the parameter packs remaining.
- while (Param != ParamEnd) {
- // If we're checking a partial list of template arguments, don't fill
- // in arguments for non-template parameter packs.
- if ((*Param)->isTemplateParameterPack()) {
- if (!HasParameterPack)
- return true;
- if (ArgumentPack.empty())
- Converted.push_back(TemplateArgument(0, 0));
- else {
- Converted.push_back(TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
- ArgumentPack.clear();
- }
- } else if (!PartialTemplateArgs)
- return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
-
- ++Param;
- }
- return Invalid;
+ return false;
}
namespace {
@@ -3650,7 +3672,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
return false;
case NPV_Error:
@@ -3738,7 +3760,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
- NamedDecl *Entity = DRE->getDecl();
+ ValueDecl *Entity = DRE->getDecl();
// Cannot refer to non-static data members
if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) {
@@ -3926,7 +3948,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
// Create the template argument.
- Converted = TemplateArgument(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
+ ParamType->isReferenceType());
S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
return false;
}
@@ -3947,7 +3970,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
return false;
case NPV_NotNullPointer:
break;
@@ -4016,10 +4039,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (isa<NonTypeTemplateParmDecl>(VD) ||
(isa<VarDecl>(VD) &&
S.Context.getCanonicalType(VD->getType()).isConstQualified())) {
- if (Arg->isTypeDependent() || Arg->isValueDependent())
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- else
- Converted = TemplateArgument(VD->getCanonicalDecl());
+ } else {
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ Converted = TemplateArgument(VD, /*isReferenceParam*/false);
+ }
return Invalid;
}
}
@@ -4040,10 +4065,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
- if (Arg->isTypeDependent() || Arg->isValueDependent())
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- else
- Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl());
+ } else {
+ ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
+ Converted = TemplateArgument(D, /*isReferenceParam*/false);
+ }
return Invalid;
}
@@ -4396,8 +4423,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument((Decl *)0);
- return Owned(Arg);;
+ Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
+ return Owned(Arg);
}
}
@@ -4417,8 +4444,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
- const TemplateArgumentLoc &Arg) {
- TemplateName Name = Arg.getArgument().getAsTemplate();
+ const TemplateArgumentLoc &Arg,
+ unsigned ArgumentPackIndex) {
+ TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
// Any dependent template name is fine.
@@ -4448,8 +4476,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
<< Template;
}
+ TemplateParameterList *Params = Param->getTemplateParameters();
+ if (Param->isExpandedParameterPack())
+ Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
+
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
- Param->getTemplateParameters(),
+ Params,
true,
TPL_TemplateTemplateArgumentMatch,
Arg.getLocation());
@@ -4463,12 +4495,9 @@ ExprResult
Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc) {
- assert(Arg.getKind() == TemplateArgument::Declaration &&
- "Only declaration template arguments permitted here");
-
// For a NULL non-type template argument, return nullptr casted to the
// parameter's type.
- if (!Arg.getAsDecl()) {
+ if (Arg.getKind() == TemplateArgument::NullPtr) {
return ImpCastExprToType(
new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc),
ParamType,
@@ -4476,7 +4505,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
? CK_NullToMemberPointer
: CK_NullToPointer);
}
-
+ assert(Arg.getKind() == TemplateArgument::Declaration &&
+ "Only declaration template arguments permitted here");
+
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
if (VD->getDeclContext()->isRecord() &&
@@ -4524,7 +4555,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
ParamType.getUnqualifiedType()));
- return move(RefExpr);
+ return RefExpr;
}
}
@@ -4542,7 +4573,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (RefExpr.isInvalid())
return ExprError();
- return move(RefExpr);
+ return RefExpr;
}
// Take the address of everything else
@@ -5071,10 +5102,10 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S,
continue;
}
- Expr *ArgExpr = Args[I].getAsExpr();
- if (!ArgExpr) {
+ if (Args[I].getKind() != TemplateArgument::Expression)
continue;
- }
+
+ Expr *ArgExpr = Args[I].getAsExpr();
// We can have a pack expansion of any of the bullets below.
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr))
@@ -5173,7 +5204,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
- ? TemplateParameterLists.get()[0]->getTemplateLoc() : SourceLocation();
+ ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
@@ -5199,7 +5230,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
TemplateNameLoc,
SS,
- (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.data(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
isExplicitSpecialization,
@@ -5354,7 +5385,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
PrevDecl = 0;
CanonType = Context.getTypeDeclType(Specialization);
@@ -5382,7 +5413,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateParams,
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
// Create a new class template partial specialization declaration node.
@@ -5406,7 +5437,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size() - 1,
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
if (!PrevPartial)
@@ -5461,7 +5492,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
TemplateParameterLists.size(),
- (TemplateParameterList**) TemplateParameterLists.release());
+ TemplateParameterLists.data());
}
if (!PrevDecl)
@@ -5544,7 +5575,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Specialization->setTypeAsWritten(WrittenTy);
Specialization->setTemplateKeywordLoc(TemplateKWLoc);
}
- TemplateArgsIn.release();
// C++ [temp.expl.spec]p9:
// A template explicit specialization is in the scope of the
@@ -5579,7 +5609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Decl *Sema::ActOnTemplateDeclarator(Scope *S,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
- Decl *NewDecl = HandleDeclarator(S, D, move(TemplateParameterLists));
+ Decl *NewDecl = HandleDeclarator(S, D, TemplateParameterLists);
ActOnDocumentableDecl(NewDecl);
return NewDecl;
}
@@ -5598,7 +5628,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
- move(TemplateParameterLists));
+ TemplateParameterLists);
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(DP))
return ActOnStartOfFunctionDef(FnBodyScope,
@@ -5902,7 +5932,7 @@ 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(Context, FD->getLocation());
+ TemplateDeductionInfo Info(FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
@@ -6399,7 +6429,6 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TemplateArgs,
Context.getTypeDeclType(Specialization));
Specialization->setTypeAsWritten(WrittenTy);
- TemplateArgsIn.release();
// Set source locations for keywords.
Specialization->setExternLoc(ExternLoc);
@@ -6475,9 +6504,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
- MultiTemplateParamsArg(*this, 0, 0),
- Owned, IsDependent, SourceLocation(), false,
- TypeResult());
+ MultiTemplateParamsArg(), Owned, IsDependent,
+ SourceLocation(), false, TypeResult());
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -6729,12 +6757,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(*this,
- TemplateId->getTemplateArgs(),
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
HasExplicitTemplateArgs = true;
- TemplateArgsPtr.release();
}
// C++ [temp.explicit]p1:
@@ -6762,7 +6788,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(Context, D.getIdentifierLoc());
+ TemplateDeductionInfo Info(D.getIdentifierLoc());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 9500ec3219d4..bf4533d6998c 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -158,9 +158,6 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Determine whether two declaration pointers refer to the same
/// declaration.
static bool isSameDeclaration(Decl *X, Decl *Y) {
- if (!X || !Y)
- return !X && !Y;
-
if (NamedDecl *NX = dyn_cast<NamedDecl>(X))
X = NX->getUnderlyingDecl();
if (NamedDecl *NY = dyn_cast<NamedDecl>(Y))
@@ -262,7 +259,27 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced two declarations, make sure they they refer to the
// same declaration.
if (Y.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(X.getAsDecl(), Y.getAsDecl()))
+ isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
+ X.isDeclForReferenceParam() == Y.isDeclForReferenceParam())
+ return X;
+
+ // All other combinations are incompatible.
+ return DeducedTemplateArgument();
+
+ case TemplateArgument::NullPtr:
+ // If we deduced a null pointer and a dependent expression, keep the
+ // null pointer.
+ if (Y.getKind() == TemplateArgument::Expression)
+ return X;
+
+ // If we deduced a null pointer and an integral constant, keep the
+ // integral constant.
+ if (Y.getKind() == TemplateArgument::Integral)
+ return Y;
+
+ // If we deduced two null pointers, make sure they have the same type.
+ if (Y.getKind() == TemplateArgument::NullPtr &&
+ Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
return X;
// All other combinations are incompatible.
@@ -356,13 +373,15 @@ DeduceNonTypeTemplateArgument(Sema &S,
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
- Decl *D,
+ ValueDecl *D,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
- DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0);
+ D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : 0;
+ TemplateArgument New(D, NTTP->getType()->isReferenceType());
+ DeducedTemplateArgument NewDeduced(New);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
@@ -570,7 +589,10 @@ static void PrepareArgumentPackDeduction(Sema &S,
SavedPacks[I] = Deduced[PackIndices[I]];
Deduced[PackIndices[I]] = TemplateArgument();
- // If the template arugment pack was explicitly specified, add that to
+ if (!S.CurrentInstantiationScope)
+ continue;
+
+ // If the template argument pack was explicitly specified, add that to
// the set of deduced arguments.
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
@@ -612,7 +634,7 @@ FinishArgumentPackDeduction(Sema &S,
if (NewlyDeducedPacks[I].empty()) {
// If we deduced an empty argument pack, create it now.
- NewPack = DeducedTemplateArgument(TemplateArgument(0, 0));
+ NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
} else {
TemplateArgument *ArgumentPack
= new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
@@ -1371,9 +1393,11 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If this is a base class, try to perform template argument
// deduction from it.
if (NextT != RecordT) {
+ TemplateDeductionInfo BaseInfo(Info.getLocation());
Sema::TemplateDeductionResult BaseResult
= DeduceTemplateArguments(S, TemplateParams, SpecParam,
- QualType(NextT, 0), Info, Deduced);
+ QualType(NextT, 0), BaseInfo,
+ Deduced);
// If template argument deduction for this base was successful,
// note that we had some success. Otherwise, ignore any deductions
@@ -1382,6 +1406,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Successful = true;
DeducedOrig.clear();
DeducedOrig.append(Deduced.begin(), Deduced.end());
+ Info.Param = BaseInfo.Param;
+ Info.FirstArg = BaseInfo.FirstArg;
+ Info.SecondArg = BaseInfo.SecondArg;
}
else
Deduced = DeducedOrig;
@@ -1596,7 +1623,17 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Declaration:
if (Arg.getKind() == TemplateArgument::Declaration &&
- isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
+ isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()) &&
+ Param.isDeclForReferenceParam() == Arg.isDeclForReferenceParam())
+ return Sema::TDK_Success;
+
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+
+ case TemplateArgument::NullPtr:
+ if (Arg.getKind() == TemplateArgument::NullPtr &&
+ S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -1867,7 +1904,11 @@ static bool isSameTemplateArg(ASTContext &Context,
Context.getCanonicalType(Y.getAsType());
case TemplateArgument::Declaration:
- return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
+ return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) &&
+ X.isDeclForReferenceParam() == Y.isDeclForReferenceParam();
+
+ case TemplateArgument::NullPtr:
+ return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType());
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
@@ -1937,6 +1978,14 @@ getTrivialTemplateArgumentLoc(Sema &S,
return TemplateArgumentLoc(TemplateArgument(E), E);
}
+ case TemplateArgument::NullPtr: {
+ Expr *E
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true),
+ E);
+ }
+
case TemplateArgument::Integral: {
Expr *E
= S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
@@ -2162,6 +2211,9 @@ Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *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
@@ -2601,12 +2653,13 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// explicitly-specified set (C++0x [temp.arg.explicit]p9).
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;
- if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
+ if (CurrentInstantiationScope &&
+ CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs)
== Param)
Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
else
- Builder.push_back(TemplateArgument(0, 0));
+ Builder.push_back(TemplateArgument::getEmptyPack());
continue;
}
@@ -2784,7 +2837,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// Otherwise, see if we can resolve a function type
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ TemplateDeductionInfo Info(Ovl->getNameLoc());
if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs,
Specialization, Info))
continue;
@@ -2815,7 +2868,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// So we do not reject deductions which were made elsewhere.
SmallVector<DeducedTemplateArgument, 8>
Deduced(TemplateParams->size());
- TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ TemplateDeductionInfo Info(Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
@@ -2992,8 +3045,6 @@ DeduceTemplateArgumentByListElement(Sema &S,
///
/// \param Args the function call arguments
///
-/// \param NumArgs the number of arguments in Args
-///
/// \param Name the name of the function being called. This is only significant
/// when the function template is a conversion function template, in which
/// case this routine will also perform template argument deduction based on
@@ -3013,6 +3064,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
llvm::ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
// C++ [temp.deduct.call]p1:
@@ -3269,6 +3323,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -3328,6 +3385,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
+ if (FunctionTemplate->isInvalidDecl())
+ return TDK_Invalid;
+
CXXConversionDecl *Conv
= cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
QualType FromType = Conv->getConversionType();
@@ -3572,7 +3632,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
QualType InitType = Init->getType();
unsigned TDF = 0;
- TemplateDeductionInfo Info(Context, Loc);
+ TemplateDeductionInfo Info(Loc);
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
@@ -3594,10 +3654,11 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
return DAR_Failed;
}
- QualType DeducedType = Deduced[0].getAsType();
- if (DeducedType.isNull())
+ if (Deduced[0].getKind() != TemplateArgument::Type)
return DAR_Failed;
+ QualType DeducedType = Deduced[0].getAsType();
+
if (InitList) {
DeducedType = BuildStdInitializerList(DeducedType, Loc);
if (DeducedType.isNull())
@@ -3637,26 +3698,23 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
llvm::SmallBitVector &Deduced);
/// \brief If this is a non-static member function,
-static void MaybeAddImplicitObjectParameterType(ASTContext &Context,
+static void AddImplicitObjectParameterType(ASTContext &Context,
CXXMethodDecl *Method,
SmallVectorImpl<QualType> &ArgTypes) {
- if (Method->isStatic())
- return;
-
- // C++ [over.match.funcs]p4:
- //
- // For non-static member functions, the type of the implicit
- // object parameter is
- // - "lvalue reference to cv X" for functions declared without a
- // ref-qualifier or with the & ref-qualifier
- // - "rvalue reference to cv X" for functions declared with the
- // && ref-qualifier
+ // 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
+ // the class of which the function template is a member.
//
- // FIXME: We don't have ref-qualifiers yet, so we don't do that part.
+ // The standard doesn't say explicitly, but we pick the appropriate kind of
+ // reference type based on [over.match.funcs]p4.
QualType ArgTy = Context.getTypeDeclType(Method->getParent());
ArgTy = Context.getQualifiedType(ArgTy,
Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
- ArgTy = Context.getLValueReferenceType(ArgTy);
+ if (Method->getRefQualifier() == RQ_RValue)
+ ArgTy = Context.getRValueReferenceType(ArgTy);
+ else
+ ArgTy = Context.getLValueReferenceType(ArgTy);
ArgTypes.push_back(ArgTy);
}
@@ -3682,7 +3740,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// C++0x [temp.deduct.partial]p3:
// The types used to determine the ordering depend on the context in which
// the partial ordering is done:
- TemplateDeductionInfo Info(S.Context, Loc);
+ TemplateDeductionInfo Info(Loc);
CXXMethodDecl *Method1 = 0;
CXXMethodDecl *Method2 = 0;
bool IsNonStatic2 = false;
@@ -3697,7 +3755,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
IsNonStatic1 = Method1 && !Method1->isStatic();
IsNonStatic2 = Method2 && !Method2->isStatic();
- // C++0x [temp.func.order]p3:
+ // C++11 [temp.func.order]p3:
// [...] If only one of the function templates is a non-static
// member, that function template is considered to have a new
// first parameter inserted in its function parameter list. The
@@ -3705,22 +3763,25 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// the cv-qualifiers of the function template (if any) and A is
// the class of which the function template is a member.
//
+ // Note that we interpret this to mean "if one of the function
+ // templates is a non-static member and the other is a non-member";
+ // otherwise, the ordering rules for static functions against non-static
+ // functions don't make any sense.
+ //
// C++98/03 doesn't have this provision, so instead we drop the
- // first argument of the free function or static member, which
- // seems to match existing practice.
+ // first argument of the free function, which seems to match
+ // existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOpts().CPlusPlus0x &&
- IsNonStatic2 && !IsNonStatic1;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2)
- MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1);
+ unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1;
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2)
+ AddImplicitObjectParameterType(S.Context, Method1, Args1);
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
SmallVector<QualType, 4> Args2;
- Skip2 = !S.getLangOpts().CPlusPlus0x &&
- IsNonStatic1 && !IsNonStatic2;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
- MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2);
+ Skip2 = !S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2;
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1)
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
@@ -4118,7 +4179,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// template partial specialization's template arguments, for
// example.
SmallVector<DeducedTemplateArgument, 4> Deduced;
- TemplateDeductionInfo Info(Context, Loc);
+ TemplateDeductionInfo Info(Loc);
QualType PT1 = PS1->getInjectedSpecializationType();
QualType PT2 = PS2->getInjectedSpecializationType();
@@ -4496,6 +4557,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
case TemplateArgument::Declaration:
break;
+ case TemplateArgument::NullPtr:
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced,
+ Depth, Used);
+ break;
+
case TemplateArgument::Type:
MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced,
Depth, Used);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 20e755fdaee1..665dd07b8f85 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -769,7 +769,7 @@ namespace {
/// instantiating it.
Decl *TransformDefinition(SourceLocation Loc, Decl *D);
- /// \bried Transform the first qualifier within a scope by instantiating the
+ /// \brief Transform the first qualifier within a scope by instantiating the
/// declaration.
NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
@@ -802,11 +802,24 @@ namespace {
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+
ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E);
-
+
+ /// \brief Rebuild a DeclRefExpr for a ParmVarDecl reference.
+ ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc);
+
+ /// \brief Transform a reference to a function parameter pack.
+ ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E,
+ ParmVarDecl *PD);
+
+ /// \brief Transform a FunctionParmPackExpr which was built when we couldn't
+ /// expand a function parameter pack reference which refers to an expanded
+ /// pack.
+ ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
+
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL);
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
@@ -835,7 +848,7 @@ namespace {
ExprResult Result =
TreeTransform<TemplateInstantiator>::TransformCallExpr(CE);
getSema().CallsUndergoingInstantiation.pop_back();
- return move(Result);
+ return Result;
}
ExprResult TransformLambdaExpr(LambdaExpr *E) {
@@ -1161,10 +1174,11 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
result = SemaRef.Owned(argExpr);
type = argExpr->getType();
- } else if (arg.getKind() == TemplateArgument::Declaration) {
+ } else if (arg.getKind() == TemplateArgument::Declaration ||
+ arg.getKind() == TemplateArgument::NullPtr) {
ValueDecl *VD;
- if (Decl *D = arg.getAsDecl()) {
- VD = cast<ValueDecl>(D);
+ if (arg.getKind() == TemplateArgument::Declaration) {
+ VD = cast<ValueDecl>(arg.getAsDecl());
// Find the instantiation of the template argument. This is
// required for nested templates.
@@ -1230,8 +1244,81 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
}
ExprResult
+TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD,
+ SourceLocation Loc) {
+ DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
+ return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD);
+}
+
+ExprResult
+TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ if (getSema().ArgumentPackSubstitutionIndex != -1) {
+ // We can expand this parameter pack now.
+ ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
+ ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D));
+ if (!VD)
+ return ExprError();
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc());
+ }
+
+ QualType T = TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+
+ // Transform each of the parameter expansions into the corresponding
+ // parameters in the instantiation of the function decl.
+ llvm::SmallVector<Decl*, 8> Parms;
+ Parms.reserve(E->getNumExpansions());
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I) {
+ ParmVarDecl *D =
+ cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I));
+ if (!D)
+ return ExprError();
+ Parms.push_back(D);
+ }
+
+ return FunctionParmPackExpr::Create(getSema().Context, T,
+ E->getParameterPack(),
+ E->getParameterPackLocation(), Parms);
+}
+
+ExprResult
+TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
+ ParmVarDecl *PD) {
+ typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
+ = getSema().CurrentInstantiationScope->findInstantiationOf(PD);
+ assert(Found && "no instantiation for parameter pack");
+
+ Decl *TransformedDecl;
+ if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) {
+ // If this is a reference to a function parameter pack which we can substitute
+ // but can't yet expand, build a FunctionParmPackExpr for it.
+ if (getSema().ArgumentPackSubstitutionIndex == -1) {
+ QualType T = TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+ return FunctionParmPackExpr::Create(getSema().Context, T, PD,
+ E->getExprLoc(), *Pack);
+ }
+
+ TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
+ } else {
+ TransformedDecl = Found->get<Decl*>();
+ }
+
+ // We have either an unexpanded pack or a specific expansion.
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl),
+ E->getExprLoc());
+}
+
+ExprResult
TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
NamedDecl *D = E->getDecl();
+
+ // Handle references to non-type template parameters and non-type template
+ // parameter packs.
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
if (NTTP->getDepth() < TemplateArgs.getNumLevels())
return TransformTemplateParmRefExpr(E, NTTP);
@@ -1240,6 +1327,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
// FindInstantiatedDecl will find it in the local instantiation scope.
}
+ // Handle references to function parameter packs.
+ if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D))
+ if (PD->isParameterPack())
+ return TransformFunctionParmPackRefExpr(E, PD);
+
return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E);
}
@@ -2159,7 +2251,7 @@ Sema::InstantiateClassTemplateSpecialization(
Template->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
- TemplateDeductionInfo Info(Context, PointOfInstantiation);
+ TemplateDeductionInfo Info(PointOfInstantiation);
if (TemplateDeductionResult Result
= DeduceTemplateArguments(Partial,
ClassTemplateSpec->getTemplateArgs(),
@@ -2543,8 +2635,25 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
return Instantiator.TransformTemplateArguments(Args, NumArgs, Result);
}
+
+static const Decl* getCanonicalParmVarDecl(const Decl *D) {
+ // When storing ParmVarDecls in the local instantiation scope, we always
+ // want to use the ParmVarDecl from the canonical function declaration,
+ // since the map is then valid for any redeclaration or definition of that
+ // function.
+ if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+ unsigned i = PV->getFunctionScopeIndex();
+ return FD->getCanonicalDecl()->getParamDecl(i);
+ }
+ }
+ return D;
+}
+
+
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+ D = getCanonicalParmVarDecl(D);
for (LocalInstantiationScope *Current = this; Current;
Current = Current->Outer) {
@@ -2576,6 +2685,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
}
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
+ D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
if (Stored.isNull())
Stored = Inst;
@@ -2588,11 +2698,13 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
Decl *Inst) {
+ D = getCanonicalParmVarDecl(D);
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
Pack->push_back(Inst);
}
void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
+ D = getCanonicalParmVarDecl(D);
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
assert(Stored.isNull() && "Already instantiated this local");
DeclArgumentPack *Pack = new DeclArgumentPack;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bdbe71dd8aba..19c46ab9c97f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -158,6 +158,22 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
+ // HACK: g++ has a bug where it gets the value kind of ?: wrong.
+ // libstdc++ relies upon this bug in its implementation of common_type.
+ // If we happen to be processing that implementation, fake up the g++ ?:
+ // semantics. See LWG issue 2141 for more information on the bug.
+ const DecltypeType *DT = DI->getType()->getAs<DecltypeType>();
+ CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext());
+ if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) &&
+ DT->isReferenceType() &&
+ RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() &&
+ RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") &&
+ D->getIdentifier() && D->getIdentifier()->isStr("type") &&
+ SemaRef.getSourceManager().isInSystemHeader(D->getLocStart()))
+ // Fold it to the (non-reference) type which g++ would have produced.
+ DI = SemaRef.Context.getTrivialTypeSourceInfo(
+ DI->getType().getNonReferenceType());
+
// Create the new typedef
TypedefNameDecl *Typedef;
if (IsTypeAlias)
@@ -510,7 +526,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
if (!InstTy)
return 0;
- FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocation(),
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocStart(),
D->getFriendLoc(), InstTy);
if (!FD)
return 0;
@@ -1008,6 +1024,30 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
return Record;
}
+/// \brief Adjust the given function type for an instantiation of the
+/// given declaration, to cope with modifications to the function's type that
+/// aren't reflected in the type-source information.
+///
+/// \param D The declaration we're instantiating.
+/// \param TInfo The already-instantiated type.
+static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
+ FunctionDecl *D,
+ TypeSourceInfo *TInfo) {
+ const FunctionProtoType *OrigFunc
+ = D->getType()->castAs<FunctionProtoType>();
+ const FunctionProtoType *NewFunc
+ = TInfo->getType()->castAs<FunctionProtoType>();
+ if (OrigFunc->getExtInfo() == NewFunc->getExtInfo())
+ return TInfo->getType();
+
+ FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
+ NewEPI.ExtInfo = OrigFunc->getExtInfo();
+ return Context.getFunctionType(NewFunc->getResultType(),
+ NewFunc->arg_type_begin(),
+ NewFunc->getNumArgs(),
+ NewEPI);
+}
+
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves two purposes:
/// 1) instantiating function templates
@@ -1048,7 +1088,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
- QualType T = TInfo->getType();
+ QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
@@ -1075,7 +1115,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
- D->getLocation(), D->getDeclName(), T, TInfo,
+ D->getNameInfo(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
D->isConstexpr());
@@ -1366,7 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
- QualType T = TInfo->getType();
+ 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
@@ -1657,7 +1697,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
- } else if (isa<PackExpansionTypeLoc>(TL)) {
+ } else if (D->isPackExpansion()) {
// The non-type template parameter pack's type is a pack expansion of types.
// Determine whether we need to expand this parameter pack into separate
// types.
@@ -1771,27 +1811,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return Param;
}
+static void collectUnexpandedParameterPacks(
+ Sema &S,
+ TemplateParameterList *Params,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ for (TemplateParameterList::const_iterator I = Params->begin(),
+ E = Params->end(); I != E; ++I) {
+ if ((*I)->isTemplateParameterPack())
+ continue;
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I))
+ S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(),
+ Unexpanded);
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I))
+ collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(),
+ Unexpanded);
+ }
+}
+
Decl *
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateTemplateParmDecl *D) {
// Instantiate the template parameter list of the template template parameter.
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams;
- {
+ SmallVector<TemplateParameterList*, 8> ExpandedParams;
+
+ bool IsExpandedParameterPack = false;
+
+ if (D->isExpandedParameterPack()) {
+ // The template template parameter pack is an already-expanded pack
+ // expansion of template parameters. Substitute into each of the expanded
+ // parameters.
+ ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I) {
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *Expansion =
+ SubstTemplateParams(D->getExpansionTemplateParameters(I));
+ if (!Expansion)
+ return 0;
+ ExpandedParams.push_back(Expansion);
+ }
+
+ IsExpandedParameterPack = true;
+ InstParams = TempParams;
+ } else if (D->isPackExpansion()) {
+ // The template template parameter pack expands to a pack of template
+ // template parameters. Determine whether we need to expand this parameter
+ // pack into separate parameters.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(),
+ Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ llvm::Optional<unsigned> NumExpansions;
+ if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
+ TempParams->getSourceRange(),
+ Unexpanded,
+ TemplateArgs,
+ Expand, RetainExpansion,
+ NumExpansions))
+ return 0;
+
+ if (Expand) {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+ LocalInstantiationScope Scope(SemaRef);
+ TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
+ if (!Expansion)
+ return 0;
+ ExpandedParams.push_back(Expansion);
+ }
+
+ // Note that we have an expanded parameter pack. The "type" of this
+ // expanded parameter pack is the original expansion type, but callers
+ // will end up using the expanded parameter pack types for type-checking.
+ IsExpandedParameterPack = true;
+ InstParams = TempParams;
+ } else {
+ // We cannot fully expand the pack expansion now, so just substitute
+ // into the pattern.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
+
+ LocalInstantiationScope Scope(SemaRef);
+ InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+ }
+ } else {
// Perform the actual substitution of template parameters within a new,
// local instantiation scope.
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return 0;
}
// Build the template template parameter.
- TemplateTemplateParmDecl *Param
- = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ TemplateTemplateParmDecl *Param;
+ if (IsExpandedParameterPack)
+ Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getPosition(),
+ D->getIdentifier(), InstParams,
+ ExpandedParams);
+ else
+ Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(), D->isParameterPack(),
- D->getIdentifier(), InstParams);
+ D->getPosition(),
+ D->isParameterPack(),
+ D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
Param->setAccess(AS_public);
@@ -1813,7 +1947,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
D->getIdentLocation(),
D->getNominatedNamespace(),
D->getCommonAncestor());
- Owner->addDecl(Inst);
+
+ // Add the using directive to its declaration context
+ // only if this is not a function or method.
+ if (!Owner->isFunctionOrMethod())
+ Owner->addDecl(Inst);
+
return Inst;
}
@@ -2863,7 +3002,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const MultiLevelTemplateArgumentList &TemplateArgs) {
SmallVector<CXXCtorInitializer*, 4> NewInits;
- bool AnyErrors = false;
+ bool AnyErrors = Tmpl->isInvalidDecl();
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
@@ -3031,7 +3170,7 @@ ExprResult Sema::SubstInitializer(Expr *Init,
isa<CXXTemporaryObjectExpr>(Construct))
return SubstExpr(Init, TemplateArgs);
- ASTOwningVector<Expr*> NewArgs(*this);
+ SmallVector<Expr*, 8> NewArgs;
if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
TemplateArgs, NewArgs))
return ExprError();
@@ -3043,7 +3182,7 @@ ExprResult Sema::SubstInitializer(Expr *Init,
// Build a ParenListExpr to represent anything else.
// FIXME: Fake locations!
SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
- return ActOnParenListExpr(Loc, Loc, move_arg(NewArgs));
+ return ActOnParenListExpr(Loc, Loc, NewArgs);
}
// TODO: this could be templated if the various decl types used the
@@ -3298,7 +3437,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (Decl *FD = Found->dyn_cast<Decl *>())
return cast<NamedDecl>(FD);
- unsigned PackIdx = ArgumentPackSubstitutionIndex;
+ int PackIdx = ArgumentPackSubstitutionIndex;
+ assert(PackIdx != -1 && "found declaration pack but not pack expanding");
return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index aece90b78590..6147d63ef44b 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_enum:
case TST_union:
case TST_struct:
+ case TST_interface:
case TST_class:
case TST_auto:
case TST_unknown_anytype:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 54f8dbaf0127..4b23167951aa 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -105,7 +105,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_ThisCall: \
case AttributeList::AT_Pascal: \
case AttributeList::AT_Regparm: \
- case AttributeList::AT_Pcs \
+ case AttributeList::AT_Pcs: \
+ case AttributeList::AT_PnaclCall \
namespace {
/// An object which stores processing state for the entire
@@ -552,19 +553,28 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
SourceLocation loc = declarator.getLocStart();
// ...and *prepend* it to the declarator.
+ SourceLocation NoLoc;
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
- /*proto*/ true,
- /*variadic*/ false,
- /*ambiguous*/ false, SourceLocation(),
- /*args*/ 0, 0,
- /*type quals*/ 0,
- /*ref-qualifier*/true, SourceLocation(),
- /*const qualifier*/SourceLocation(),
- /*volatile qualifier*/SourceLocation(),
- /*mutable qualifier*/SourceLocation(),
- /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
- /*parens*/ loc, loc,
- declarator));
+ /*HasProto=*/true,
+ /*IsAmbiguous=*/false,
+ /*LParenLoc=*/NoLoc,
+ /*ArgInfo=*/0,
+ /*NumArgs=*/0,
+ /*EllipsisLoc=*/NoLoc,
+ /*RParenLoc=*/NoLoc,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLvalueRef=*/true,
+ /*RefQualifierLoc=*/NoLoc,
+ /*ConstQualifierLoc=*/NoLoc,
+ /*VolatileQualifierLoc=*/NoLoc,
+ /*MutableLoc=*/NoLoc,
+ EST_None,
+ /*ESpecLoc=*/NoLoc,
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ loc, loc, declarator));
// For consistency, make sure the state still has us as processing
// the decl spec.
@@ -636,7 +646,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**)PQ,
+ (ObjCProtocolDecl*const*)PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
break;
@@ -698,11 +708,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_longlong:
Result = Context.LongLongTy;
- // long long is a C99 feature.
- if (!S.getLangOpts().C99)
- S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!S.getLangOpts().C99) {
+ if (S.getLangOpts().CPlusPlus)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
+ }
break;
}
} else {
@@ -713,11 +727,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TSW_longlong:
Result = Context.UnsignedLongLongTy;
- // long long is a C99 feature.
- if (!S.getLangOpts().C99)
- S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_longlong : diag::ext_longlong);
+ // 'long long' is a C99 or C++11 feature.
+ if (!S.getLangOpts().C99) {
+ if (S.getLangOpts().CPlusPlus)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
+ else
+ S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
+ }
break;
}
}
@@ -753,7 +771,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_class:
case DeclSpec::TST_enum:
case DeclSpec::TST_union:
- case DeclSpec::TST_struct: {
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_interface: {
TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl());
if (!D) {
// This can happen in C++ with ambiguous lookups.
@@ -794,18 +813,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (DS.getNumProtocolQualifiers())
Result = Context.getObjCObjectType(Result,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
} else if (Result->isObjCIdType()) {
// id<protocol-list>
Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
} else if (Result->isObjCClassType()) {
// Class<protocol-list>
Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy,
- (ObjCProtocolDecl**) PQ,
+ (ObjCProtocolDecl*const*) PQ,
DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Result);
} else {
@@ -1853,30 +1872,31 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case TTK_Struct: Error = 1; /* Struct member */ break;
case TTK_Union: Error = 2; /* Union member */ break;
case TTK_Class: Error = 3; /* Class member */ break;
+ case TTK_Interface: Error = 4; /* Interface member */ break;
}
break;
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
- Error = 4; // Exception declaration
+ Error = 5; // Exception declaration
break;
case Declarator::TemplateParamContext:
- Error = 5; // Template parameter
+ Error = 6; // Template parameter
break;
case Declarator::BlockLiteralContext:
- Error = 6; // Block literal
+ Error = 7; // Block literal
break;
case Declarator::TemplateTypeArgContext:
- Error = 7; // Template type argument
+ Error = 8; // Template type argument
break;
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
- Error = 9; // Type alias
+ Error = 10; // Type alias
break;
case Declarator::TrailingReturnContext:
- Error = 10; // Function return type
+ Error = 11; // Function return type
break;
case Declarator::TypeNameContext:
- Error = 11; // Generic
+ Error = 12; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
@@ -1887,11 +1907,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
}
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- Error = 8;
+ Error = 9;
// In Objective-C it is an error to use 'auto' on a function declarator.
if (D.isFunctionDeclarator())
- Error = 10;
+ Error = 11;
// C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
@@ -2149,16 +2169,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
ASTContext &Context = S.Context;
const LangOptions &LangOpts = S.getLangOpts();
- bool ImplicitlyNoexcept = false;
- if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
- LangOpts.CPlusPlus0x) {
- OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
- /// In C++0x, deallocation functions (normal and array operator delete)
- /// are implicitly noexcept.
- if (OO == OO_Delete || OO == OO_Array_Delete)
- ImplicitlyNoexcept = true;
- }
-
// The name we're declaring, if any.
DeclarationName Name;
if (D.getIdentifier())
@@ -2558,12 +2568,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- if (FTI.getExceptionSpecType() == EST_None &&
- ImplicitlyNoexcept && chunkIndex == 0) {
- // Only the outermost chunk is marked noexcept, of course.
- EPI.ExceptionSpecType = EST_BasicNoexcept;
- }
-
T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
}
@@ -2657,6 +2661,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
// function that is not a constructor declares that function to be const.
+ // FIXME: This should be deferred until we know whether this is a static
+ // member function (for an out-of-class definition, we don't know
+ // this until we perform redeclaration lookup).
if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
D.getName().getKind() != UnqualifiedId::IK_ConstructorName &&
@@ -2668,6 +2675,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getFunctionType(FnTy->getResultType(),
FnTy->arg_type_begin(),
FnTy->getNumArgs(), EPI);
+ // Rebuild any parens around the identifier in the function type.
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
+ break;
+ T = S.BuildParenType(T);
+ }
}
// C++11 [dcl.fct]p6 (w/DR1417):
@@ -2721,6 +2734,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getFunctionType(FnTy->getResultType(),
FnTy->arg_type_begin(),
FnTy->getNumArgs(), EPI);
+ // Rebuild any parens around the identifier in the function type.
+ for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
+ break;
+ T = S.BuildParenType(T);
+ }
}
}
@@ -2985,6 +3004,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_Pascal;
case AttributedType::attr_pcs:
return AttributeList::AT_Pcs;
+ case AttributedType::attr_pnaclcall:
+ return AttributeList::AT_PnaclCall;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -3271,6 +3292,8 @@ namespace {
TL.setLocalRangeEnd(Chunk.EndLoc);
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
+ TL.setLParenLoc(FTI.getLParenLoc());
+ TL.setRParenLoc(FTI.getRParenLoc());
for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
TL.setArg(tpi++, Param);
@@ -3588,7 +3611,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak if the runtime doesn't support it.
if (lifetime == Qualifiers::OCL_Weak &&
- !S.getLangOpts().ObjCRuntimeHasWeak && !NonObjCPointer) {
+ !S.getLangOpts().ObjCARCWeak && !NonObjCPointer) {
// Actually, delay this until we know what we're parsing.
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
@@ -3611,11 +3634,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
while (const PointerType *ptr = T->getAs<PointerType>())
T = ptr->getPointeeType();
if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
- ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
- if (Class->isArcWeakrefUnavailable()) {
- S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
- S.Diag(ObjT->getInterfaceDecl()->getLocation(),
- diag::note_class_declared);
+ if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) {
+ if (Class->isArcWeakrefUnavailable()) {
+ S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
+ S.Diag(ObjT->getInterfaceDecl()->getLocation(),
+ diag::note_class_declared);
+ }
}
}
}
@@ -3875,14 +3899,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+ // Delay if the type didn't work out to a function.
+ if (!unwrapped.isFunctionType()) return false;
+
// Otherwise, a calling convention.
CallingConv CC;
if (S.CheckCallingConvAttr(attr, CC))
return true;
- // Delay if the type didn't work out to a function.
- if (!unwrapped.isFunctionType()) return false;
-
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
if (S.Context.getCanonicalCallConv(CC) ==
@@ -4429,6 +4453,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return RequireCompleteType(Loc, T, Diagnoser);
}
+/// \brief Get diagnostic %select index for tag kind for
+/// literal type diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) {
+ switch (Tag) {
+ case TTK_Struct: return 0;
+ case TTK_Interface: return 1;
+ case TTK_Class: return 2;
+ default: llvm_unreachable("Invalid tag kind for literal type diagnostic!");
+ }
+}
+
/// @brief Ensure that the type T is a literal type.
///
/// This routine checks whether the type @p T is a literal type. If @p T is an
@@ -4485,7 +4523,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
// of constexpr constructors.
if (RD->getNumVBases()) {
Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
- << RD->isStruct() << RD->getNumVBases();
+ << getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getLocStart(),
@@ -4578,15 +4616,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
// member access (5.2.5), decltype(e) is the type of the entity named
// by e. If there is no such entity, or if e names a set of overloaded
// functions, the program is ill-formed;
+ //
+ // We apply the same rules for Objective-C ivar and property references.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
return VD->getType();
- }
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
return FD->getType();
+ } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) {
+ return IR->getDecl()->getType();
+ } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (PR->isExplicitProperty())
+ return PR->getExplicitProperty()->getType();
}
-
+
// C++11 [expr.lambda.prim]p18:
// Every occurrence of decltype((x)) where x is a possibly
// parenthesized id-expression that names an entity of automatic
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 619ad330b95b..294d74244673 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -574,6 +574,10 @@ public:
/// \brief Transform the captures and body of a lambda expression.
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ ExprResult TransformAddressOfOperand(Expr *E);
+ ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
+ bool IsAddressOfOperand);
+
#define STMT(Node, Parent) \
StmtResult Transform##Node(Node *S);
#define EXPR(Node, Parent) \
@@ -1162,32 +1166,23 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildAsmStmt(SourceLocation AsmLoc,
- bool IsSimple,
- bool IsVolatile,
- unsigned NumOutputs,
- unsigned NumInputs,
- IdentifierInfo **Names,
- MultiExprArg Constraints,
- MultiExprArg Exprs,
- Expr *AsmString,
- MultiExprArg Clobbers,
- SourceLocation RParenLoc,
- bool MSAsm) {
- return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
- NumInputs, Names, move(Constraints),
- Exprs, AsmString, Clobbers,
- RParenLoc, MSAsm);
+ StmtResult RebuildGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+ bool IsVolatile, unsigned NumOutputs,
+ unsigned NumInputs, IdentifierInfo **Names,
+ MultiExprArg Constraints, MultiExprArg Exprs,
+ Expr *AsmString, MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs,
+ AsmString, Clobbers, RParenLoc);
}
/// \brief Build a new MS style inline asm statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc,
- SourceLocation LBraceLoc,
- ArrayRef<Token> AsmToks,
- SourceLocation EndLoc) {
+ StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
+ ArrayRef<Token> AsmToks, SourceLocation EndLoc) {
return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc);
}
@@ -1199,7 +1194,7 @@ public:
Stmt *TryBody,
MultiStmtArg CatchStmts,
Stmt *Finally) {
- return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, move(CatchStmts),
+ return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, CatchStmts,
Finally);
}
@@ -1325,7 +1320,7 @@ public:
StmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
Stmt *TryBlock,
MultiStmtArg Handlers) {
- return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers));
+ return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers);
}
/// \brief Build a new C++0x range-based for statement.
@@ -1339,7 +1334,8 @@ public:
Stmt *LoopVar,
SourceLocation RParenLoc) {
return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
- Cond, Inc, LoopVar, RParenLoc);
+ Cond, Inc, LoopVar, RParenLoc,
+ Sema::BFRK_Rebuild);
}
/// \brief Build a new C++0x range-based for statement.
@@ -1478,7 +1474,7 @@ public:
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
/// \brief Build a new array subscript expression.
@@ -1503,7 +1499,7 @@ public:
SourceLocation RParenLoc,
Expr *ExecConfig = 0) {
return getSema().ActOnCallExpr(/*Scope=*/0, Callee, LParenLoc,
- move(Args), RParenLoc, ExecConfig);
+ Args, RParenLoc, ExecConfig);
}
/// \brief Build a new member access expression.
@@ -1638,15 +1634,15 @@ public:
SourceLocation RBraceLoc,
QualType ResultTy) {
ExprResult Result
- = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc);
+ = SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc);
if (Result.isInvalid() || ResultTy->isDependentType())
- return move(Result);
+ return Result;
// Patch in the result type we were given, which may have been computed
// when the initial InitListExpr was built.
InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get());
ILE->setType(ResultTy);
- return move(Result);
+ return Result;
}
/// \brief Build a new designated initializer expression.
@@ -1664,8 +1660,7 @@ public:
if (Result.isInvalid())
return ExprError();
- ArrayExprs.release();
- return move(Result);
+ return Result;
}
/// \brief Build a new value-initialized expression.
@@ -1696,7 +1691,7 @@ public:
ExprResult RebuildParenListExpr(SourceLocation LParenLoc,
MultiExprArg SubExprs,
SourceLocation RParenLoc) {
- return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
+ return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs);
}
/// \brief Build a new address-of-label expression.
@@ -1974,8 +1969,7 @@ public:
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc,
- MultiExprArg(getSema(), 0, 0),
- RParenLoc);
+ MultiExprArg(), RParenLoc);
}
/// \brief Build a new C++ "new" expression.
@@ -1995,7 +1989,7 @@ public:
Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
- move(PlacementArgs),
+ PlacementArgs,
PlacementRParen,
TypeIdParens,
AllocatedType,
@@ -2083,7 +2077,8 @@ public:
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsAddressOfOperand) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -2091,7 +2086,8 @@ public:
return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc,
NameInfo, TemplateArgs);
- return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo);
+ return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo,
+ IsAddressOfOperand);
}
/// \brief Build a new template-id expression.
@@ -2120,13 +2116,13 @@ public:
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
- ASTOwningVector<Expr*> ConvertedArgs(SemaRef);
- if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc,
+ SmallVector<Expr*, 8> ConvertedArgs;
+ if (getSema().CompleteConstructorCall(Constructor, Args, Loc,
ConvertedArgs))
return ExprError();
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
- move_arg(ConvertedArgs),
+ ConvertedArgs,
HadMultipleCandidates,
RequiresZeroInit, ConstructKind,
ParenRange);
@@ -2142,7 +2138,7 @@ public:
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo,
LParenLoc,
- move(Args),
+ Args,
RParenLoc);
}
@@ -2156,7 +2152,7 @@ public:
SourceLocation RParenLoc) {
return getSema().BuildCXXTypeConstructExpr(TSInfo,
LParenLoc,
- move(Args),
+ Args,
RParenLoc);
}
@@ -2288,7 +2284,7 @@ public:
ReceiverTypeInfo->getType(),
/*SuperLoc=*/SourceLocation(),
Sel, Method, LBracLoc, SelectorLocs,
- RBracLoc, move(Args));
+ RBracLoc, Args);
}
/// \brief Build a new Objective-C instance message.
@@ -2303,7 +2299,7 @@ public:
Receiver->getType(),
/*SuperLoc=*/SourceLocation(),
Sel, Method, LBracLoc, SelectorLocs,
- RBracLoc, move(Args));
+ RBracLoc, Args);
}
/// \brief Build a new Objective-C ivar reference expression.
@@ -2326,7 +2322,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IvarLoc, IsArrow,
@@ -2355,7 +2351,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/PropertyLoc, IsArrow,
@@ -2398,7 +2394,7 @@ public:
return ExprError();
if (Result.get())
- return move(Result);
+ return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IsaLoc, IsArrow,
@@ -2424,21 +2420,17 @@ public:
// Build a reference to the __builtin_shufflevector builtin
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
- ExprResult Callee
- = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false,
- Builtin->getType(),
- VK_LValue, BuiltinLoc));
- Callee = SemaRef.UsualUnaryConversions(Callee.take());
- if (Callee.isInvalid())
- return ExprError();
+ Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
+ SemaRef.Context.BuiltinFnTy,
+ VK_RValue, BuiltinLoc);
+ QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType());
+ Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy,
+ CK_BuiltinFnToFnPtr).take();
// Build the CallExpr
- unsigned NumSubExprs = SubExprs.size();
- Expr **Subs = (Expr **)SubExprs.release();
ExprResult TheCall = SemaRef.Owned(
- new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(),
- Subs, NumSubExprs,
- Builtin->getCallResultType(),
+ new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs,
+ Builtin->getCallResultType(),
Expr::getValueKindForType(Builtin->getResultType()),
RParenLoc));
@@ -2478,6 +2470,7 @@ public:
case TemplateArgument::Declaration:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::NullPtr:
llvm_unreachable("Pack expansion pattern has no parameter packs");
case TemplateArgument::Type:
@@ -2515,10 +2508,7 @@ public:
// Just create the expression; there is not any interesting semantic
// analysis here because we can't actually build an AtomicExpr until
// we are sure it is semantically sound.
- unsigned NumSubExprs = SubExprs.size();
- Expr **Subs = (Expr **)SubExprs.release();
- return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs,
- NumSubExprs, RetTy, Op,
+ return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op,
RParenLoc);
}
@@ -2963,6 +2953,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::Pack:
+ case TemplateArgument::NullPtr:
Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
break;
}
@@ -2976,8 +2967,10 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
- Output = Input;
- return false;
+ case TemplateArgument::Pack:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ llvm_unreachable("Unexpected TemplateArgument");
case TemplateArgument::Type: {
TypeSourceInfo *DI = Input.getTypeSourceInfo();
@@ -2991,28 +2984,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
return false;
}
- case TemplateArgument::Declaration: {
- // FIXME: we should never have to transform one of these.
- DeclarationName Name;
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl()))
- Name = ND->getDeclName();
- TemporaryBase Rebase(*this, Input.getLocation(), Name);
- Decl *D = getDerived().TransformDecl(Input.getLocation(), Arg.getAsDecl());
- if (!D) return true;
-
- Expr *SourceExpr = Input.getSourceDeclExpression();
- if (SourceExpr) {
- EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::ConstantEvaluated);
- ExprResult E = getDerived().TransformExpr(SourceExpr);
- E = SemaRef.ActOnConstantExpression(E);
- SourceExpr = (E.isInvalid() ? 0 : E.take());
- }
-
- Output = TemplateArgumentLoc(TemplateArgument(D), SourceExpr);
- return false;
- }
-
case TemplateArgument::Template: {
NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc();
if (QualifierLoc) {
@@ -3051,35 +3022,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take());
return false;
}
-
- case TemplateArgument::Pack: {
- SmallVector<TemplateArgument, 4> TransformedArgs;
- TransformedArgs.reserve(Arg.pack_size());
- for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
- AEnd = Arg.pack_end();
- A != AEnd; ++A) {
-
- // FIXME: preserve source information here when we start
- // caring about parameter packs.
-
- TemplateArgumentLoc InputArg;
- TemplateArgumentLoc OutputArg;
- getDerived().InventTemplateArgumentLoc(*A, InputArg);
- if (getDerived().TransformTemplateArgument(InputArg, OutputArg))
- return true;
-
- TransformedArgs.push_back(OutputArg.getArgument());
- }
-
- TemplateArgument *TransformedArgsPtr
- = new (getSema().Context) TemplateArgument[TransformedArgs.size()];
- std::copy(TransformedArgs.begin(), TransformedArgs.end(),
- TransformedArgsPtr);
- Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr,
- TransformedArgs.size()),
- Input.getLocInfo());
- return false;
- }
}
// Work around bogus GCC warning
@@ -4260,6 +4202,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result);
NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i)
NewTL.setArg(i, ParamDecls[i]);
@@ -4283,6 +4227,8 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result);
NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
return Result;
@@ -4339,7 +4285,8 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
TypeOfExprTypeLoc TL) {
// typeof expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
if (E.isInvalid())
@@ -5099,7 +5046,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
bool SubStmtInvalid = false;
bool SubStmtChanged = false;
- ASTOwningVector<Stmt*> Statements(getSema());
+ SmallVector<Stmt*, 8> Statements;
for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
B != BEnd; ++B) {
StmtResult Result = getDerived().TransformStmt(*B);
@@ -5126,7 +5073,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
return SemaRef.Owned(S);
return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
- move_arg(Statements),
+ Statements,
S->getRBracLoc(),
IsStmtExpr);
}
@@ -5533,14 +5480,14 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
+TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
- ASTOwningVector<Expr*> Constraints(getSema());
- ASTOwningVector<Expr*> Exprs(getSema());
+ SmallVector<Expr*, 8> Constraints;
+ SmallVector<Expr*, 8> Exprs;
SmallVector<IdentifierInfo *, 4> Names;
ExprResult AsmString;
- ASTOwningVector<Expr*> Clobbers(getSema());
+ SmallVector<Expr*, 8> Clobbers;
bool ExprsChanged = false;
@@ -5585,23 +5532,15 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
// Go through the clobbers.
for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
- Clobbers.push_back(S->getClobber(I));
+ Clobbers.push_back(S->getClobberStringLiteral(I));
// No need to transform the asm string literal.
AsmString = SemaRef.Owned(S->getAsmString());
-
- return getDerived().RebuildAsmStmt(S->getAsmLoc(),
- S->isSimple(),
- S->isVolatile(),
- S->getNumOutputs(),
- S->getNumInputs(),
- Names.data(),
- move_arg(Constraints),
- move_arg(Exprs),
- AsmString.get(),
- move_arg(Clobbers),
- S->getRParenLoc(),
- S->isMSAsm());
+ return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(),
+ S->isVolatile(), S->getNumOutputs(),
+ S->getNumInputs(), Names.data(),
+ Constraints, Exprs, AsmString.get(),
+ Clobbers, S->getRParenLoc());
}
template<typename Derived>
@@ -5624,7 +5563,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
// Transform the @catch statements (if present).
bool AnyCatchChanged = false;
- ASTOwningVector<Stmt*> CatchStmts(SemaRef);
+ SmallVector<Stmt*, 8> CatchStmts;
for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
StmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I));
if (Catch.isInvalid())
@@ -5651,7 +5590,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
// Build a new statement.
return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(),
- move_arg(CatchStmts), Finally.get());
+ CatchStmts, Finally.get());
}
template<typename Derived>
@@ -5855,7 +5794,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
// Transform the handlers.
bool HandlerChanged = false;
- ASTOwningVector<Stmt*> Handlers(SemaRef);
+ SmallVector<Stmt*, 8> Handlers;
for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
StmtResult Handler
= getDerived().TransformCXXCatchStmt(S->getHandler(I));
@@ -5872,7 +5811,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
return SemaRef.Owned(S);
return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(),
- move_arg(Handlers));
+ Handlers);
}
template<typename Derived>
@@ -6205,10 +6144,22 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
E->getRParen());
}
+/// \brief The operand of a unary address-of operator has special rules: it's
+/// allowed to refer to a non-static member of a class even if there's no 'this'
+/// object available.
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
+ if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
+ return getDerived().TransformDependentScopeDeclRefExpr(DRE, true);
+ else
+ return getDerived().TransformExpr(E);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
- ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ ExprResult SubExpr = TransformAddressOfOperand(E->getSubExpr());
if (SubExpr.isInvalid())
return ExprError();
@@ -6338,7 +6289,8 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
// C++0x [expr.sizeof]p1:
// The operand is either an expression, which is an unevaluated operand
// [...]
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
if (SubExpr.isInvalid())
@@ -6386,7 +6338,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
@@ -6394,13 +6346,13 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Callee.get() == E->getCallee() &&
!ArgChanged)
- return SemaRef.MaybeBindToTemporary(E);;
+ return SemaRef.MaybeBindToTemporary(E);
// FIXME: Wrong source location information for the '('.
SourceLocation FakeLParenLoc
= ((Expr *)Callee.get())->getSourceRange().getBegin();
return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getRParenLoc());
}
@@ -6499,6 +6451,9 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
RHS.get() == E->getRHS())
return SemaRef.Owned(E);
+ Sema::FPContractStateRAII FPContractState(getSema());
+ getSema().FPFeatures.fp_contract = E->isFPContractable();
+
return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
LHS.get(), RHS.get());
}
@@ -6645,7 +6600,7 @@ ExprResult
TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
bool InitChanged = false;
- ASTOwningVector<Expr*, 4> Inits(SemaRef);
+ SmallVector<Expr*, 4> Inits;
if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false,
Inits, &InitChanged))
return ExprError();
@@ -6653,7 +6608,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
if (!getDerived().AlwaysRebuild() && !InitChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits),
+ return getDerived().RebuildInitList(E->getLBraceLoc(), Inits,
E->getRBraceLoc(), E->getType());
}
@@ -6668,7 +6623,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
return ExprError();
// transform the designators.
- ASTOwningVector<Expr*, 4> ArrayExprs(SemaRef);
+ SmallVector<Expr*, 4> ArrayExprs;
bool ExprChanged = false;
for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
DEnd = E->designators_end();
@@ -6720,7 +6675,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
!ExprChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs),
+ return getDerived().RebuildDesignatedInitExpr(Desig, ArrayExprs,
E->getEqualOrColonLoc(),
E->usesGNUSyntax(), Init.get());
}
@@ -6768,13 +6723,13 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) {
bool ArgumentChanged = false;
- ASTOwningVector<Expr*, 4> Inits(SemaRef);
+ SmallVector<Expr*, 4> Inits;
if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits,
&ArgumentChanged))
return ExprError();
return getDerived().RebuildParenListExpr(E->getLParenLoc(),
- move_arg(Inits),
+ Inits,
E->getRParenLoc());
}
@@ -6875,13 +6830,13 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
static_cast<Expr *>(Object.get())->getLocEnd());
// Transform the call arguments.
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true,
Args))
return ExprError();
return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getLocEnd());
}
@@ -6905,7 +6860,11 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
if (Callee.isInvalid())
return ExprError();
- ExprResult First = getDerived().TransformExpr(E->getArg(0));
+ ExprResult First;
+ if (E->getOperator() == OO_Amp)
+ First = getDerived().TransformAddressOfOperand(E->getArg(0));
+ else
+ First = getDerived().TransformExpr(E->getArg(0));
if (First.isInvalid())
return ExprError();
@@ -6922,6 +6881,9 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
(E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
return SemaRef.MaybeBindToTemporary(E);
+ Sema::FPContractStateRAII FPContractState(getSema());
+ getSema().FPFeatures.fp_contract = E->isFPContractable();
+
return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
E->getOperatorLoc(),
Callee.get(),
@@ -6950,7 +6912,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgChanged))
return ExprError();
@@ -6964,7 +6926,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
SourceLocation FakeLParenLoc
= ((Expr *)Callee.get())->getSourceRange().getBegin();
return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc,
- move_arg(Args),
+ Args,
E->getRParenLoc(), EC.get());
}
@@ -6989,9 +6951,6 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
SourceLocation FakeLAngleLoc
= SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
- SourceLocation FakeRParenLoc
- = SemaRef.PP.getLocForEndOfToken(
- E->getSubExpr()->getSourceRange().getEnd());
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
FakeLAngleLoc,
@@ -6999,7 +6958,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
FakeRAngleLoc,
FakeRAngleLoc,
SubExpr.get(),
- FakeRParenLoc);
+ E->getRParenLoc());
}
template<typename Derived>
@@ -7074,7 +7033,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
// after we perform semantic analysis. We speculatively assume it is
// unevaluated; it will get fixed later if the subexpression is in fact
// potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -7222,7 +7182,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the placement arguments (if any).
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> PlacementArgs(SemaRef);
+ SmallVector<Expr*, 8> PlacementArgs;
if (getDerived().TransformExprs(E->getPlacementArgs(),
E->getNumPlacementArgs(), true,
PlacementArgs, &ArgumentChanged))
@@ -7313,7 +7273,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return getDerived().RebuildCXXNewExpr(E->getLocStart(),
E->isGlobalNew(),
/*FIXME:*/E->getLocStart(),
- move_arg(PlacementArgs),
+ PlacementArgs,
/*FIXME:*/E->getLocStart(),
E->getTypeIdParens(),
AllocType,
@@ -7512,7 +7472,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// If we have template arguments, rebuild them, then rebuild the
// templateid expression.
TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
- if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
+ if (Old->hasExplicitTemplateArgs() &&
+ getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
Old->getNumTemplateArgs(),
TransArgs))
return ExprError();
@@ -7732,6 +7693,14 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E) {
+ return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *E,
+ bool IsAddressOfOperand) {
NestedNameSpecifierLoc QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
if (!QualifierLoc)
@@ -7758,7 +7727,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
TemplateKWLoc,
NameInfo,
- /*TemplateArgs*/ 0);
+ /*TemplateArgs*/ 0,
+ IsAddressOfOperand);
}
TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -7770,7 +7740,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
TemplateKWLoc,
NameInfo,
- &TransArgs);
+ &TransArgs,
+ IsAddressOfOperand);
}
template<typename Derived>
@@ -7796,7 +7767,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
return ExprError();
@@ -7813,7 +7784,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
Constructor, E->isElidable(),
- move_arg(Args),
+ Args,
E->hadMultipleCandidates(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
@@ -7857,7 +7828,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->getNumArgs());
if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
@@ -7874,19 +7845,13 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
- move_arg(Args),
+ Args,
E->getLocEnd());
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- // Create the local class that will describe the lambda.
- CXXRecordDecl *Class
- = getSema().createLambdaClosureType(E->getIntroducerRange(),
- /*KnownDependent=*/false);
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
-
// Transform the type of the lambda parameters and start the definition of
// the lambda itself.
TypeSourceInfo *MethodTy
@@ -7894,6 +7859,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (!MethodTy)
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);
+
// Transform lambda parameters.
llvm::SmallVector<QualType, 4> ParamTypes;
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -8038,7 +8010,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
return ExprError();
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->arg_size());
if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args,
&ArgumentChanged))
@@ -8052,7 +8024,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
// FIXME: we're faking the locations of the commas
return getDerived().RebuildCXXUnresolvedConstructExpr(T,
E->getLParenLoc(),
- move_arg(Args),
+ Args,
E->getRParenLoc());
}
@@ -8346,6 +8318,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return SemaRef.Owned(E);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
return getDerived().TransformExpr(E->GetTemporaryExpr());
@@ -8576,7 +8555,7 @@ ExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// Transform arguments.
bool ArgChanged = false;
- ASTOwningVector<Expr*> Args(SemaRef);
+ SmallVector<Expr*, 8> Args;
Args.reserve(E->getNumArgs());
if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args,
&ArgChanged))
@@ -8602,7 +8581,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
- move_arg(Args),
+ Args,
E->getRightLoc());
}
@@ -8627,7 +8606,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
SelLocs,
E->getMethodDecl(),
E->getLeftLoc(),
- move_arg(Args),
+ Args,
E->getRightLoc());
}
@@ -8740,7 +8719,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> SubExprs(SemaRef);
+ SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
SubExprs, &ArgumentChanged))
@@ -8751,7 +8730,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
return SemaRef.Owned(E);
return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(),
- move_arg(SubExprs),
+ SubExprs,
E->getRParenLoc());
}
@@ -8854,7 +8833,7 @@ ExprResult
TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
QualType RetTy = getDerived().TransformType(E->getType());
bool ArgumentChanged = false;
- ASTOwningVector<Expr*> SubExprs(SemaRef);
+ SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false,
SubExprs, &ArgumentChanged))
@@ -8864,7 +8843,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
!ArgumentChanged)
return SemaRef.Owned(E);
- return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs),
+ return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs,
RetTy, E->getOp(), E->getRParenLoc());
}
@@ -9185,7 +9164,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
}
@@ -9200,7 +9179,12 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// IsAcceptableNonMemberOperatorCandidate for each of these?
Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
- Functions.addDecl(cast<DeclRefExpr>(Callee)->getDecl());
+ // If we've resolved this to a particular non-member function, just call
+ // that function. If we resolved it to a member function,
+ // CreateOverloaded* will find that function for us.
+ NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
+ if (!isa<CXXMethodDecl>(ND))
+ Functions.addDecl(ND);
}
// Add any functions found via argument-dependent lookup.
@@ -9240,7 +9224,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (Result.isInvalid())
return ExprError();
- return move(Result);
+ return Result;
}
template<typename Derived>
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 67f74f7d7a51..0ec03cfe1e68 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -60,6 +60,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
+ case BuiltinType::BuiltinFn:
+ ID = PREDEF_TYPE_BUILTIN_FN; break;
+
}
return TypeIdx(ID);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 3adbc5783397..deba302e2138 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -30,13 +30,16 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/StringExtras.h"
@@ -62,353 +65,306 @@ using namespace clang::serialization::reader;
ASTReaderListener::~ASTReaderListener() {}
-bool
-PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
- const LangOptions &PPLangOpts = PP.getLangOpts();
-
-#define LANGOPT(Name, Bits, Default, Description) \
- if (PPLangOpts.Name != LangOpts.Name) { \
- Reader.Diag(diag::err_pch_langopt_mismatch) \
- << Description << LangOpts.Name << PPLangOpts.Name; \
+/// \brief Compare the given set of language options against an existing set of
+/// language options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the languagae options mis-match, false otherwise.
+static bool checkLanguageOptions(const LangOptions &LangOpts,
+ const LangOptions &ExistingLangOpts,
+ DiagnosticsEngine *Diags) {
+#define LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_mismatch) \
+ << Description << LangOpts.Name << ExistingLangOpts.Name; \
+ return true; \
+ }
+
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ if (ExistingLangOpts.Name != LangOpts.Name) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
return true; \
}
-#define VALUE_LANGOPT(Name, Bits, Default, Description) \
- if (PPLangOpts.Name != LangOpts.Name) { \
- Reader.Diag(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
-}
-
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \
- Reader.Diag(diag::err_pch_langopt_value_mismatch) \
- << Description; \
- return true; \
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_langopt_value_mismatch) \
+ << Description; \
+ return true; \
}
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
- if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
- Reader.Diag(diag::err_pch_langopt_value_mismatch)
+ if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
<< "target Objective-C runtime";
return true;
}
-
+
return false;
}
-bool PCHValidator::ReadTargetTriple(StringRef Triple) {
- if (Triple == PP.getTargetInfo().getTriple().str())
- return false;
-
- Reader.Diag(diag::warn_pch_target_triple)
- << Triple << PP.getTargetInfo().getTriple().str();
- return true;
-}
+/// \brief Compare the given set of target options against an existing set of
+/// target options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the target options mis-match, false otherwise.
+static bool checkTargetOptions(const TargetOptions &TargetOpts,
+ const TargetOptions &ExistingTargetOpts,
+ DiagnosticsEngine *Diags) {
+#define CHECK_TARGET_OPT(Field, Name) \
+ if (TargetOpts.Field != ExistingTargetOpts.Field) { \
+ if (Diags) \
+ Diags->Report(diag::err_pch_targetopt_mismatch) \
+ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \
+ return true; \
+ }
+
+ CHECK_TARGET_OPT(Triple, "target");
+ CHECK_TARGET_OPT(CPU, "target CPU");
+ CHECK_TARGET_OPT(ABI, "target ABI");
+ CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
+ CHECK_TARGET_OPT(LinkerVersion, "target linker version");
+#undef CHECK_TARGET_OPT
+
+ // Compare feature sets.
+ SmallVector<StringRef, 4> ExistingFeatures(
+ ExistingTargetOpts.FeaturesAsWritten.begin(),
+ ExistingTargetOpts.FeaturesAsWritten.end());
+ SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
+ TargetOpts.FeaturesAsWritten.end());
+ std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
+ std::sort(ReadFeatures.begin(), ReadFeatures.end());
+
+ unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size();
+ unsigned ReadIdx = 0, ReadN = ReadFeatures.size();
+ while (ExistingIdx < ExistingN && ReadIdx < ReadN) {
+ if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) {
+ ++ExistingIdx;
+ ++ReadIdx;
+ continue;
+ }
-namespace {
- struct EmptyStringRef {
- bool operator ()(StringRef r) const { return r.empty(); }
- };
- struct EmptyBlock {
- bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();}
- };
-}
+ if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
+ return true;
+ }
-static bool EqualConcatenations(SmallVector<StringRef, 2> L,
- PCHPredefinesBlocks R) {
- // First, sum up the lengths.
- unsigned LL = 0, RL = 0;
- for (unsigned I = 0, N = L.size(); I != N; ++I) {
- LL += L[I].size();
- }
- for (unsigned I = 0, N = R.size(); I != N; ++I) {
- RL += R[I].Data.size();
- }
- if (LL != RL)
- return false;
- if (LL == 0 && RL == 0)
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
return true;
-
- // Kick out empty parts, they confuse the algorithm below.
- L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end());
- R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
-
- // Do it the hard way. At this point, both vectors must be non-empty.
- StringRef LR = L[0], RR = R[0].Data;
- unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
- (void) RN;
- for (;;) {
- // Compare the current pieces.
- if (LR.size() == RR.size()) {
- // If they're the same length, it's pretty easy.
- if (LR != RR)
- return false;
- // Both pieces are done, advance.
- ++LI;
- ++RI;
- // If either string is done, they're both done, since they're the same
- // length.
- if (LI == LN) {
- assert(RI == RN && "Strings not the same length after all?");
- return true;
- }
- LR = L[LI];
- RR = R[RI].Data;
- } else if (LR.size() < RR.size()) {
- // Right piece is longer.
- if (!RR.startswith(LR))
- return false;
- ++LI;
- assert(LI != LN && "Strings not the same length after all?");
- RR = RR.substr(LR.size());
- LR = L[LI];
- } else {
- // Left piece is longer.
- if (!LR.startswith(RR))
- return false;
- ++RI;
- assert(RI != RN && "Strings not the same length after all?");
- LR = LR.substr(RR.size());
- RR = R[RI].Data;
- }
}
-}
-static std::pair<FileID, StringRef::size_type>
-FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) {
- std::pair<FileID, StringRef::size_type> Res;
- for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
- Res.second = Buffers[I].Data.find(MacroDef);
- if (Res.second != StringRef::npos) {
- Res.first = Buffers[I].BufferID;
- break;
- }
+ if (ExistingIdx < ExistingN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << true << ExistingFeatures[ExistingIdx];
+ return true;
}
- return Res;
-}
-
-bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
- StringRef OriginalFileName,
- std::string &SuggestedPredefines,
- FileManager &FileMgr) {
- // We are in the context of an implicit include, so the predefines buffer will
- // have a #include entry for the PCH file itself (as normalized by the
- // preprocessor initialization). Find it and skip over it in the checking
- // below.
- SmallString<256> PCHInclude;
- PCHInclude += "#include \"";
- PCHInclude += HeaderSearch::NormalizeDashIncludePath(OriginalFileName,
- FileMgr);
- PCHInclude += "\"\n";
- std::pair<StringRef,StringRef> Split =
- StringRef(PP.getPredefines()).split(PCHInclude.str());
- StringRef Left = Split.first, Right = Split.second;
- if (Left == PP.getPredefines()) {
- Error("Missing PCH include entry!");
+
+ if (ReadIdx < ReadN) {
+ if (Diags)
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch)
+ << false << ReadFeatures[ReadIdx];
return true;
}
- // If the concatenation of all the PCH buffers is equal to the adjusted
- // command line, we're done.
- SmallVector<StringRef, 2> CommandLine;
- CommandLine.push_back(Left);
- CommandLine.push_back(Right);
- if (EqualConcatenations(CommandLine, Buffers))
- return false;
+ return false;
+}
- SourceManager &SourceMgr = PP.getSourceManager();
-
- // The predefines buffers are different. Determine what the differences are,
- // and whether they require us to reject the PCH file.
- SmallVector<StringRef, 8> PCHLines;
- for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
- Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
-
- SmallVector<StringRef, 8> CmdLineLines;
- Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
-
- // Pick out implicit #includes after the PCH and don't consider them for
- // validation; we will insert them into SuggestedPredefines so that the
- // preprocessor includes them.
- std::string IncludesAfterPCH;
- SmallVector<StringRef, 8> AfterPCHLines;
- Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) {
- if (AfterPCHLines[i].startswith("#include ")) {
- IncludesAfterPCH += AfterPCHLines[i];
- IncludesAfterPCH += '\n';
- } else {
- CmdLineLines.push_back(AfterPCHLines[i]);
- }
- }
-
- // Make sure we add the includes last into SuggestedPredefines before we
- // exit this function.
- struct AddIncludesRAII {
- std::string &SuggestedPredefines;
- std::string &IncludesAfterPCH;
-
- AddIncludesRAII(std::string &SuggestedPredefines,
- std::string &IncludesAfterPCH)
- : SuggestedPredefines(SuggestedPredefines),
- IncludesAfterPCH(IncludesAfterPCH) { }
- ~AddIncludesRAII() {
- SuggestedPredefines += IncludesAfterPCH;
- }
- } AddIncludes(SuggestedPredefines, IncludesAfterPCH);
-
- // Sort both sets of predefined buffer lines, since we allow some extra
- // definitions and they may appear at any point in the output.
- std::sort(CmdLineLines.begin(), CmdLineLines.end());
- std::sort(PCHLines.begin(), PCHLines.end());
-
- // Determine which predefines that were used to build the PCH file are missing
- // from the command line.
- std::vector<StringRef> MissingPredefines;
- std::set_difference(PCHLines.begin(), PCHLines.end(),
- CmdLineLines.begin(), CmdLineLines.end(),
- std::back_inserter(MissingPredefines));
-
- bool MissingDefines = false;
- bool ConflictingDefines = false;
- for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) {
- StringRef Missing = MissingPredefines[I];
- if (Missing.startswith("#include ")) {
- // An -include was specified when generating the PCH; it is included in
- // the PCH, just ignore it.
- continue;
- }
- if (!Missing.startswith("#define ")) {
- Reader.Diag(diag::warn_pch_compiler_options_mismatch);
- return true;
- }
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ const LangOptions &ExistingLangOpts = PP.getLangOpts();
+ return checkLanguageOptions(LangOpts, ExistingLangOpts,
+ Complain? &Reader.Diags : 0);
+}
- // This is a macro definition. Determine the name of the macro we're
- // defining.
- std::string::size_type StartOfMacroName = strlen("#define ");
- std::string::size_type EndOfMacroName
- = Missing.find_first_of("( \n\r", StartOfMacroName);
- assert(EndOfMacroName != std::string::npos &&
- "Couldn't find the end of the macro name");
- StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName);
-
- // Determine whether this macro was given a different definition on the
- // command line.
- std::string MacroDefStart = "#define " + MacroName.str();
- std::string::size_type MacroDefLen = MacroDefStart.size();
- SmallVector<StringRef, 8>::iterator ConflictPos
- = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
- MacroDefStart);
- for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
- if (!ConflictPos->startswith(MacroDefStart)) {
- // Different macro; we're done.
- ConflictPos = CmdLineLines.end();
- break;
- }
+bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
+ return checkTargetOptions(TargetOpts, ExistingTargetOpts,
+ Complain? &Reader.Diags : 0);
+}
- assert(ConflictPos->size() > MacroDefLen &&
- "Invalid #define in predefines buffer?");
- if ((*ConflictPos)[MacroDefLen] != ' ' &&
- (*ConflictPos)[MacroDefLen] != '(')
- continue; // Longer macro name; keep trying.
+namespace {
+ typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >
+ MacroDefinitionsMap;
+}
- // We found a conflicting macro definition.
- break;
- }
+/// \brief Collect the macro definitions provided by the given preprocessor
+/// options.
+static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
+ MacroDefinitionsMap &Macros,
+ SmallVectorImpl<StringRef> *MacroNames = 0){
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ StringRef Macro = PPOpts.Macros[I].first;
+ bool IsUndef = PPOpts.Macros[I].second;
- if (ConflictPos != CmdLineLines.end()) {
- Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
- << MacroName;
+ std::pair<StringRef, StringRef> MacroPair = Macro.split('=');
+ StringRef MacroName = MacroPair.first;
+ StringRef MacroBody = MacroPair.second;
- // Show the definition of this macro within the PCH file.
- std::pair<FileID, StringRef::size_type> MacroLoc =
- FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
- SourceLocation PCHMissingLoc =
- SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getLocWithOffset(MacroLoc.second);
- Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
+ // For an #undef'd macro, we only care about the name.
+ if (IsUndef) {
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
- ConflictingDefines = true;
+ Macros[MacroName] = std::make_pair("", true);
continue;
}
- // If the macro doesn't conflict, then we'll just pick up the macro
- // definition from the PCH file. Warn the user that they made a mistake.
- if (ConflictingDefines)
- continue; // Don't complain if there are already conflicting defs
-
- if (!MissingDefines) {
- Reader.Diag(diag::warn_cmdline_missing_macro_defs);
- MissingDefines = true;
+ // For a #define'd macro, figure out the actual definition.
+ if (MacroName.size() == Macro.size())
+ MacroBody = "1";
+ else {
+ // Note: GCC drops anything following an end-of-line character.
+ StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ MacroBody = MacroBody.substr(0, End);
}
- // Show the definition of this macro within the PCH file.
- std::pair<FileID, StringRef::size_type> MacroLoc =
- FindMacro(Buffers, Missing);
- assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!");
- SourceLocation PCHMissingLoc =
- SourceMgr.getLocForStartOfFile(MacroLoc.first)
- .getLocWithOffset(MacroLoc.second);
- Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
+ if (MacroNames && !Macros.count(MacroName))
+ MacroNames->push_back(MacroName);
+ Macros[MacroName] = std::make_pair(MacroBody, false);
}
+}
+
+/// \brief Check the preprocessor options deserialized from the control block
+/// against the preprocessor options in an existing preprocessor.
+///
+/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
+static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ DiagnosticsEngine *Diags,
+ FileManager &FileMgr,
+ std::string &SuggestedPredefines) {
+ // Check macro definitions.
+ MacroDefinitionsMap ASTFileMacros;
+ collectMacroDefinitions(PPOpts, ASTFileMacros);
+ MacroDefinitionsMap ExistingMacros;
+ SmallVector<StringRef, 4> ExistingMacroNames;
+ collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames);
+
+ for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) {
+ // Dig out the macro definition in the existing preprocessor options.
+ StringRef MacroName = ExistingMacroNames[I];
+ std::pair<StringRef, bool> Existing = ExistingMacros[MacroName];
+
+ // Check whether we know anything about this macro name or not.
+ llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known
+ = ASTFileMacros.find(MacroName);
+ if (Known == ASTFileMacros.end()) {
+ // FIXME: Check whether this identifier was referenced anywhere in the
+ // AST file. If so, we should reject the AST file. Unfortunately, this
+ // information isn't in the control block. What shall we do about it?
+
+ if (Existing.second) {
+ SuggestedPredefines += "#undef ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += '\n';
+ } else {
+ SuggestedPredefines += "#define ";
+ SuggestedPredefines += MacroName.str();
+ SuggestedPredefines += ' ';
+ SuggestedPredefines += Existing.first.str();
+ SuggestedPredefines += '\n';
+ }
+ continue;
+ }
- if (ConflictingDefines)
- return true;
-
- // Determine what predefines were introduced based on command-line
- // parameters that were not present when building the PCH
- // file. Extra #defines are okay, so long as the identifiers being
- // defined were not used within the precompiled header.
- std::vector<StringRef> ExtraPredefines;
- std::set_difference(CmdLineLines.begin(), CmdLineLines.end(),
- PCHLines.begin(), PCHLines.end(),
- std::back_inserter(ExtraPredefines));
- for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
- StringRef &Extra = ExtraPredefines[I];
- if (!Extra.startswith("#define ")) {
- Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+ // If the macro was defined in one but undef'd in the other, we have a
+ // conflict.
+ if (Existing.second != Known->second.second) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef)
+ << MacroName << Known->second.second;
+ }
return true;
}
- // This is an extra macro definition. Determine the name of the
- // macro we're defining.
- std::string::size_type StartOfMacroName = strlen("#define ");
- std::string::size_type EndOfMacroName
- = Extra.find_first_of("( \n\r", StartOfMacroName);
- assert(EndOfMacroName != std::string::npos &&
- "Couldn't find the end of the macro name");
- StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName);
-
- // Check whether this name was used somewhere in the PCH file. If
- // so, defining it as a macro could change behavior, so we reject
- // the PCH file.
- if (IdentifierInfo *II = Reader.get(MacroName)) {
- Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
- return true;
+ // If the macro was #undef'd in both, or if the macro bodies are identical,
+ // it's fine.
+ if (Existing.second || Existing.first == Known->second.first)
+ continue;
+
+ // The macro bodies differ; complain.
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_conflict)
+ << MacroName << Known->second.first << Existing.first;
}
+ return true;
+ }
- // Add this definition to the suggested predefines buffer.
- SuggestedPredefines += Extra;
- SuggestedPredefines += '\n';
+ // Check whether we're using predefines.
+ if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
+ }
+ return true;
+ }
+
+ // Compute the #include and #include_macros lines we need.
+ for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.Includes[I];
+ if (File == ExistingPPOpts.ImplicitPCHInclude)
+ continue;
+
+ if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File)
+ != PPOpts.Includes.end())
+ continue;
+
+ SuggestedPredefines += "#include \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n";
+ }
+
+ for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) {
+ StringRef File = ExistingPPOpts.MacroIncludes[I];
+ if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(),
+ File)
+ != PPOpts.MacroIncludes.end())
+ continue;
+
+ SuggestedPredefines += "#__include_macros \"";
+ SuggestedPredefines +=
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr);
+ SuggestedPredefines += "\"\n##\n";
}
- // If we get here, it's because the predefines buffer had compatible
- // contents. Accept the PCH file.
return false;
}
+bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
+
+ return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
+ Complain? &Reader.Diags : 0,
+ PP.getFileManager(),
+ SuggestedPredefines);
+}
+
void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI,
unsigned ID) {
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID);
++NumHeaderInfos;
}
-void PCHValidator::ReadCounter(unsigned Value) {
+void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
PP.setCounterValue(Value);
}
@@ -527,6 +483,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
return II;
}
+ unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
unsigned Bits = ReadUnalignedLE16(d);
bool CPlusPlusOperatorKeyword = Bits & 0x01;
Bits >>= 1;
@@ -536,13 +493,11 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Bits >>= 1;
bool ExtensionToken = Bits & 0x01;
Bits >>= 1;
- bool hasMacroDefinition = Bits & 0x01;
+ bool hadMacroDefinition = Bits & 0x01;
Bits >>= 1;
- unsigned ObjCOrBuiltinID = Bits & 0x7FF;
- Bits >>= 11;
assert(Bits == 0 && "Extra bits in the identifier?");
- DataLen -= 6;
+ DataLen -= 8;
// Build the IdentifierInfo itself and link the identifier ID with
// the new IdentifierInfo.
@@ -570,31 +525,14 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
- if (hasMacroDefinition) {
- // FIXME: Check for conflicts?
- uint32_t Offset = ReadUnalignedLE32(d);
- unsigned LocalSubmoduleID = ReadUnalignedLE32(d);
-
- // Determine whether this macro definition should be visible now, or
- // whether it is in a hidden submodule.
- bool Visible = true;
- if (SubmoduleID GlobalSubmoduleID
- = Reader.getGlobalSubmoduleID(F, LocalSubmoduleID)) {
- if (Module *Owner = Reader.getSubmodule(GlobalSubmoduleID)) {
- if (Owner->NameVisibility == Module::Hidden) {
- // The owning module is not visible, and this macro definition should
- // not be, either.
- Visible = false;
-
- // Note that this macro definition was hidden because its owning
- // module is not yet visible.
- Reader.HiddenNamesMap[Owner].push_back(II);
- }
- }
+ if (hadMacroDefinition) {
+ SmallVector<MacroID, 4> MacroIDs;
+ while (uint32_t LocalID = ReadUnalignedLE32(d)) {
+ MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
+ DataLen -= 4;
}
-
- Reader.setIdentifierIsMacro(II, F, Offset, Visible);
- DataLen -= 8;
+ DataLen -= 4;
+ Reader.setIdentifierIsMacro(II, MacroIDs);
}
Reader.SetIdentifierInfo(ID, II);
@@ -780,16 +718,6 @@ void ASTReader::Error(unsigned DiagID,
Diag(DiagID) << Arg1 << Arg2;
}
-/// \brief Tell the AST listener about the predefines buffers in the chain.
-bool ASTReader::CheckPredefinesBuffers() {
- if (Listener)
- return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
- ActualOriginalFileName,
- SuggestedPredefines,
- FileMgr);
- return false;
-}
-
//===----------------------------------------------------------------------===//
// Source Manager Deserialization
//===----------------------------------------------------------------------===//
@@ -808,7 +736,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
unsigned FilenameLen = Record[Idx++];
std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen);
Idx += FilenameLen;
- MaybeAddSystemRootToFilename(Filename);
+ MaybeAddSystemRootToFilename(F, Filename);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
@@ -841,106 +769,8 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
return false;
}
-namespace {
-
-class ASTStatData {
-public:
- const ino_t ino;
- const dev_t dev;
- const mode_t mode;
- const time_t mtime;
- const off_t size;
-
- ASTStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
- : ino(i), dev(d), mode(mo), mtime(m), size(s) {}
-};
-
-class ASTStatLookupTrait {
- public:
- typedef const char *external_key_type;
- typedef const char *internal_key_type;
-
- typedef ASTStatData data_type;
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(path);
- }
-
- static internal_key_type GetInternalKey(const char *path) { return path; }
-
- static bool EqualKey(internal_key_type a, internal_key_type b) {
- return strcmp(a, b) == 0;
- }
-
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d) {
- unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
- unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
- }
-
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
-
- static data_type ReadData(const internal_key_type, const unsigned char *d,
- unsigned /*DataLen*/) {
- using namespace clang::io;
-
- 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);
- off_t size = (off_t) ReadUnalignedLE64(d);
- return data_type(ino, dev, mode, mtime, size);
- }
-};
-
-/// \brief stat() cache for precompiled headers.
-///
-/// This cache is very similar to the stat cache used by pretokenized
-/// headers.
-class ASTStatCache : public FileSystemStatCache {
- typedef OnDiskChainedHashTable<ASTStatLookupTrait> CacheTy;
- CacheTy *Cache;
-
- unsigned &NumStatHits, &NumStatMisses;
-public:
- ASTStatCache(const unsigned char *Buckets, const unsigned char *Base,
- unsigned &NumStatHits, unsigned &NumStatMisses)
- : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
- Cache = CacheTy::Create(Buckets, Base);
- }
-
- ~ASTStatCache() { delete Cache; }
-
- LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- // Do the lookup for the file's data in the AST file.
- CacheTy::iterator I = Cache->find(Path);
-
- // If we don't get a hit in the AST file just forward to 'stat'.
- if (I == Cache->end()) {
- ++NumStatMisses;
- return statChained(Path, StatBuf, FileDescriptor);
- }
-
- ++NumStatHits;
- ASTStatData Data = *I;
-
- 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;
- return CacheExists;
- }
-};
-} // end anonymous namespace
-
-
/// \brief Read a source manager block
-ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
+bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
@@ -954,13 +784,13 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
// The stream itself is going to skip over the source manager block.
if (F.Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
// Enter the source manager block.
if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
Error("malformed source manager block record in AST file");
- return Failure;
+ return true;
}
RecordData Record;
@@ -969,9 +799,9 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
if (Code == llvm::bitc::END_BLOCK) {
if (SLocEntryCursor.ReadBlockEnd()) {
Error("error at end of Source Manager block in AST file");
- return Failure;
+ return true;
}
- return Success;
+ return false;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
@@ -979,7 +809,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
SLocEntryCursor.ReadSubBlockID();
if (SLocEntryCursor.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -1001,7 +831,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
// Once we hit one of the source location entries, we're done.
- return Success;
+ return false;
}
}
}
@@ -1039,14 +869,13 @@ resolveFileRelativeToOriginalDir(const std::string &Filename,
return currPCHPath.str();
}
-/// \brief Read in the source location entry with the given ID.
-ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
+bool ASTReader::ReadSLocEntry(int ID) {
if (ID == 0)
- return Success;
+ return false;
if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
Error("source location entry ID out-of-range for AST file");
- return Failure;
+ return true;
}
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
@@ -1060,7 +889,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
Code == llvm::bitc::ENTER_SUBBLOCK ||
Code == llvm::bitc::DEFINE_ABBREV) {
Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ return true;
}
RecordData Record;
@@ -1069,58 +898,18 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
default:
Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ return true;
case SM_SLOC_FILE_ENTRY: {
- if (Record.size() < 7) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
// We will detect whether a file changed and return 'Failure' for it, but
// we will also try to fail gracefully by setting up the SLocEntry.
- ASTReader::ASTReadResult Result = Success;
-
- bool OverriddenBuffer = Record[6];
-
- std::string OrigFilename(BlobStart, BlobStart + BlobLen);
- std::string Filename = OrigFilename;
- MaybeAddSystemRootToFilename(Filename);
- const FileEntry *File =
- OverriddenBuffer? FileMgr.getVirtualFile(Filename, (off_t)Record[4],
- (time_t)Record[5])
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
- if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
- OriginalDir != CurrentDir) {
- std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- OriginalDir,
- CurrentDir);
- if (!resolved.empty())
- File = FileMgr.getFile(resolved);
- }
- if (File == 0)
- File = FileMgr.getVirtualFile(Filename, (off_t)Record[4],
- (time_t)Record[5]);
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return Failure;
- }
+ unsigned InputID = Record[4];
+ InputFile IF = getInputFile(*F, InputID);
+ const FileEntry *File = IF.getPointer();
+ bool OverriddenBuffer = IF.getInt();
- if (!DisableValidation &&
- ((off_t)Record[4] != File->getSize()
-#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || (time_t)Record[5] != File->getModificationTime()
-#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- Result = Failure;
- }
+ if (!IF.getPointer())
+ return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) {
@@ -1133,12 +922,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
- FileInfo.NumCreatedFIDs = Record[7];
+ FileInfo.NumCreatedFIDs = Record[5];
if (Record[3])
FileInfo.setHasLineDirectives();
- const DeclID *FirstDecl = F->FileSortedDecls + Record[8];
- unsigned NumFileDecls = Record[9];
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
+ unsigned NumFileDecls = Record[7];
if (NumFileDecls) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
@@ -1157,23 +946,24 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
- return Failure;
+ return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Filename);
+ File->getName());
SourceMgr.overrideFileContents(File, Buffer);
}
- if (Result == Failure)
- return Failure;
break;
}
case SM_SLOC_BUFFER_ENTRY: {
const char *Name = BlobStart;
unsigned Offset = Record[0];
+ SrcMgr::CharacteristicKind
+ FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode
@@ -1181,23 +971,14 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
- return Failure;
+ return true;
}
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
Name);
- FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID,
- BaseOffset + Offset);
-
- if (strcmp(Name, "<built-in>") == 0 && F->Kind == MK_PCH) {
- PCHPredefinesBlock Block = {
- BufferID,
- StringRef(BlobStart, BlobLen - 1)
- };
- PCHPredefinesBuffers.push_back(Block);
- }
-
+ SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
+ BaseOffset + Offset, IncludeLoc);
break;
}
@@ -1213,7 +994,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
}
}
- return Success;
+ return false;
}
/// \brief Find the location where the module F is imported.
@@ -1258,7 +1039,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
+void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
+ MacroInfo *Hint) {
llvm::BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
@@ -1270,6 +1052,24 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
+ // RAII object to add the loaded macro information once we're done
+ // adding tokens.
+ struct AddLoadedMacroInfoRAII {
+ Preprocessor &PP;
+ MacroInfo *Hint;
+ MacroInfo *MI;
+ IdentifierInfo *II;
+
+ AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint)
+ : PP(PP), Hint(Hint), MI(), II() { }
+ ~AddLoadedMacroInfoRAII( ) {
+ if (MI) {
+ // Finally, install the macro.
+ PP.addLoadedMacroInfo(II, MI, Hint);
+ }
+ }
+ } AddLoadedMacroInfo(PP, Hint);
+
while (true) {
unsigned Code = Stream.ReadCode();
switch (Code) {
@@ -1312,18 +1112,31 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
Error("macro must have a name in AST file");
return;
}
-
- SourceLocation Loc = ReadSourceLocation(F, Record[1]);
- bool isUsed = Record[2];
+ unsigned GlobalID = getGlobalMacroID(F, Record[1]);
+
+ // If this macro has already been loaded, don't do so again.
+ if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS])
+ return;
+
+ SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]);
+ unsigned NextIndex = 3;
+ SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
MacroInfo *MI = PP.AllocateMacroInfo(Loc);
- MI->setIsUsed(isUsed);
+
+ // Record this macro.
+ MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
+
+ SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
+ if (UndefLoc.isValid())
+ MI->setUndefLoc(UndefLoc);
+
+ MI->setIsUsed(Record[NextIndex++]);
MI->setIsFromAST();
- bool IsPublic = Record[3];
- unsigned NextIndex = 4;
+ bool IsPublic = Record[NextIndex++];
MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex));
-
+
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
bool isC99VarArgs = Record[NextIndex++];
@@ -1341,8 +1154,60 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
PP.getPreprocessorAllocator());
}
- // Finally, install the macro.
- PP.setMacroInfo(II, MI, /*LoadedFromAST=*/true);
+ if (DeserializationListener)
+ DeserializationListener->MacroRead(GlobalID, MI);
+
+ // If an update record marked this as undefined, do so now.
+ // FIXME: Only if the submodule this update came from is visible?
+ MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID);
+ if (Update != MacroUpdates.end()) {
+ if (MI->getUndefLoc().isInvalid()) {
+ for (unsigned I = 0, N = Update->second.size(); I != N; ++I) {
+ bool Hidden = false;
+ if (unsigned SubmoduleID = Update->second[I].first) {
+ if (Module *Owner = getSubmodule(SubmoduleID)) {
+ if (Owner->NameVisibility == Module::Hidden) {
+ // Note that this #undef is hidden.
+ Hidden = true;
+
+ // Record this hiding for later.
+ HiddenNamesMap[Owner].push_back(
+ HiddenName(II, MI, Update->second[I].second.UndefLoc));
+ }
+ }
+ }
+
+ if (!Hidden) {
+ MI->setUndefLoc(Update->second[I].second.UndefLoc);
+ if (PPMutationListener *Listener = PP.getPPMutationListener())
+ Listener->UndefinedMacro(MI);
+ break;
+ }
+ }
+ }
+ MacroUpdates.erase(Update);
+ }
+
+ // Determine whether this macro definition is visible.
+ bool Hidden = !MI->isPublic();
+ if (!Hidden && GlobalSubmoduleID) {
+ if (Module *Owner = getSubmodule(GlobalSubmoduleID)) {
+ if (Owner->NameVisibility == Module::Hidden) {
+ // The owning module is not visible, and this macro definition
+ // should not be, either.
+ Hidden = true;
+
+ // Note that this macro definition was hidden because its owning
+ // module is not yet visible.
+ HiddenNamesMap[Owner].push_back(HiddenName(II, MI));
+ }
+ }
+ }
+ MI->setHidden(Hidden);
+
+ // Make sure we install the macro once we're done.
+ AddLoadedMacroInfo.MI = MI;
+ AddLoadedMacroInfo.II = II;
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
@@ -1451,18 +1316,16 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
return HFI;
}
-void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F,
- uint64_t LocalOffset, bool Visible) {
- if (Visible) {
- // Note that this identifier has a macro definition.
- II->setHasMacroDefinition(true);
- }
-
- // Adjust the offset to a global offset.
- UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset;
+void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
+ II->setHadMacroDefinition(true);
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].append(IDs.begin(), IDs.end());
}
void ASTReader::ReadDefinedMacros() {
+ // Note that we are loading defined macros.
+ Deserializing Macros(this);
+
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
E = ModuleMgr.rend(); I != E; ++I) {
llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
@@ -1514,26 +1377,6 @@ void ASTReader::ReadDefinedMacros() {
}
}
}
-
- // Drain the unread macro-record offsets map.
- while (!UnreadMacroRecordOffsets.empty())
- LoadMacroDefinition(UnreadMacroRecordOffsets.begin());
-}
-
-void ASTReader::LoadMacroDefinition(
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
- assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition");
- uint64_t Offset = Pos->second;
- UnreadMacroRecordOffsets.erase(Pos);
-
- RecordLocation Loc = getLocalBitOffset(Offset);
- ReadMacroRecord(*Loc.F, Loc.Offset);
-}
-
-void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos
- = UnreadMacroRecordOffsets.find(II);
- LoadMacroDefinition(Pos);
}
namespace {
@@ -1582,6 +1425,9 @@ namespace {
}
void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
unsigned PriorGeneration = 0;
if (getContext().getLangOpts().Modules)
PriorGeneration = IdentifierGeneration[&II];
@@ -1602,14 +1448,132 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
IdentifierGeneration[II] = CurrentGeneration;
}
+llvm::PointerIntPair<const FileEntry *, 1, bool>
+ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+ // If this ID is bogus, just return an empty input file.
+ if (ID == 0 || ID > F.InputFilesLoaded.size())
+ return InputFile();
+
+ // If we've already loaded this input file, return it.
+ if (F.InputFilesLoaded[ID-1].getPointer())
+ return F.InputFilesLoaded[ID-1];
+
+ // Go find this input file.
+ llvm::BitstreamCursor &Cursor = F.InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
+
+ unsigned Code = Cursor.ReadCode();
+ RecordData Record;
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case INPUT_FILE: {
+ unsigned StoredID = Record[0];
+ assert(ID == StoredID && "Bogus stored ID or offset");
+ (void)StoredID;
+ off_t StoredSize = (off_t)Record[1];
+ time_t StoredTime = (time_t)Record[2];
+ bool Overridden = (bool)Record[3];
+
+ // Get the file entry for this input file.
+ StringRef OrigFilename(BlobStart, BlobLen);
+ std::string Filename = OrigFilename;
+ MaybeAddSystemRootToFilename(F, Filename);
+ const FileEntry *File
+ = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
+
+ // If we didn't find the file, resolve it relative to the
+ // original directory from which this AST file was created.
+ if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
+ F.OriginalDir != CurrentDir) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
+ F.OriginalDir,
+ CurrentDir);
+ if (!Resolved.empty())
+ File = FileMgr.getFile(Resolved);
+ }
+
+ // For an overridden file, create a virtual file with the stored
+ // size/timestamp.
+ if (Overridden && File == 0) {
+ File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
+ }
+
+ if (File == 0) {
+ if (Complain) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ }
+ return InputFile();
+ }
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = InputFile(File, Overridden);
+
+ // Check if there was a request to override the contents of the file
+ // that was part of the precompiled header. Overridding such a file
+ // can lead to problems when lexing using the source locations from the
+ // PCH.
+ SourceManager &SM = getSourceManager();
+ if (!Overridden && SM.isFileOverridden(File)) {
+ Error(diag::err_fe_pch_file_overridden, Filename);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ // For an overridden file, there is nothing to validate.
+ if (Overridden)
+ return InputFile(File, Overridden);
+
+ // The stat info from the FileEntry came from the cached stat
+ // info of the PCH, so we cannot trust it.
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf) != 0) {
+ StatBuf.st_size = File->getSize();
+ StatBuf.st_mtime = File->getModificationTime();
+ }
+
+ if ((StoredSize != StatBuf.st_size
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || StoredTime != StatBuf.st_mtime
+#endif
+ )) {
+ if (Complain)
+ Error(diag::err_fe_pch_file_modified, Filename);
+
+ return InputFile();
+ }
+
+ return InputFile(File, Overridden);
+ }
+ }
+
+ return InputFile();
+}
+
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
+ ModuleFile &M = ModuleMgr.getPrimaryModule();
std::string Filename = filenameStrRef;
- MaybeAddSystemRootToFilename(Filename);
+ MaybeAddSystemRootToFilename(M, Filename);
const FileEntry *File = FileMgr.getFile(Filename);
- if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
- OriginalDir != CurrentDir) {
+ if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
+ M.OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
- OriginalDir,
+ M.OriginalDir,
CurrentDir);
if (!resolved.empty())
File = FileMgr.getFile(resolved);
@@ -1621,9 +1585,10 @@ const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
-void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
+void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
+ std::string &Filename) {
// If this is not a relocatable PCH file, there's nothing to do.
- if (!RelocatablePCH)
+ if (!M.RelocatablePCH)
return;
if (Filename.empty() || llvm::sys::path::is_absolute(Filename))
@@ -1643,29 +1608,226 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
}
ASTReader::ASTReadResult
-ASTReader::ReadASTBlock(ModuleFile &F) {
+ASTReader::ReadControlBlock(ModuleFile &F,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities) {
llvm::BitstreamCursor &Stream = F.Stream;
- if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
- // Read all of the records and blocks for the ASt file.
+ // Read all of the records and blocks in the control block.
RecordData Record;
while (!Stream.AtEndOfStream()) {
unsigned Code = Stream.ReadCode();
if (Code == llvm::bitc::END_BLOCK) {
if (Stream.ReadBlockEnd()) {
- Error("error at end of module block in AST file");
+ Error("error at end of control block in AST file");
return Failure;
}
+ // Validate all of the input files.
+ if (!DisableValidation) {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+ for (unsigned I = 0, N = Record[0]; I < N; ++I)
+ if (!getInputFile(F, I+1, Complain).getPointer())
+ return OutOfDate;
+ }
+
return Success;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
switch (Stream.ReadSubBlockID()) {
+ case INPUT_FILES_BLOCK_ID:
+ F.InputFilesCursor = Stream;
+ if (Stream.SkipBlock() || // Skip with the main cursor
+ // Read the abbreviations
+ ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+
+ default:
+ if (!Stream.SkipBlock())
+ continue;
+ break;
+ }
+
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
+ : diag::warn_pch_version_too_new);
+ return VersionMismatch;
+ }
+
+ bool hasErrors = Record[5];
+ if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+ Diag(diag::err_pch_with_compiler_errors);
+ return HadErrors;
+ }
+
+ F.RelocatablePCH = Record[4];
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
+ return VersionMismatch;
+ }
+ break;
+ }
+
+ case IMPORTS: {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+ ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ unsigned Length = Record[Idx++];
+ SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Load the AST file.
+ switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded,
+ ClientLoadCapabilities)) {
+ case Failure: return Failure;
+ // If we have to ignore the dependency, we'll have to ignore this too.
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
+ case Success: break;
+ }
+ }
+ break;
+ }
+
+ case LANGUAGE_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseLanguageOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case TARGET_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseTargetOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseDiagnosticOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case FILE_SYSTEM_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseFileSystemOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case HEADER_SEARCH_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParseHeaderSearchOptions(Record, Complain, *Listener) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case PREPROCESSOR_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ if (Listener && &F == *ModuleMgr.begin() &&
+ ParsePreprocessorOptions(Record, Complain, *Listener,
+ SuggestedPredefines) &&
+ !DisableValidation)
+ return ConfigurationMismatch;
+ break;
+ }
+
+ case ORIGINAL_FILE:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
+ F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
+ MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
+ break;
+
+ case ORIGINAL_PCH_DIR:
+ F.OriginalDir.assign(BlobStart, BlobLen);
+ break;
+
+ case INPUT_FILE_OFFSETS:
+ F.InputFileOffsets = (const uint32_t *)BlobStart;
+ F.InputFilesLoaded.resize(Record[0]);
+ break;
+ }
+ }
+
+ Error("premature end of bitstream in AST file");
+ return Failure;
+}
+
+bool ASTReader::ReadASTBlock(ModuleFile &F) {
+ llvm::BitstreamCursor &Stream = F.Stream;
+
+ if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+
+ // Read all of the records and blocks for the AST file.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of module block in AST file");
+ return true;
+ }
+
+ DeclContext *DC = Context.getTranslationUnitDecl();
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
+
+ return false;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
case DECLTYPES_BLOCK_ID:
// We lazily load the decls block, but we want to set up the
// DeclsCursor cursor to point into it. Clone our current bitcode
@@ -1676,14 +1838,14 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
// Read the abbrevs.
ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
break;
case DECL_UPDATES_BLOCK_ID:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
break;
@@ -1695,7 +1857,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
@@ -1706,7 +1868,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
Error("malformed preprocessor detail record in AST file");
- return Failure;
+ return true;
}
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
@@ -1718,31 +1880,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case SOURCE_MANAGER_BLOCK_ID:
- switch (ReadSourceManagerBlock(F)) {
- case Success:
- break;
-
- case Failure:
- Error("malformed source manager block in AST file");
- return Failure;
-
- case IgnorePCH:
- return IgnorePCH;
- }
+ if (ReadSourceManagerBlock(F))
+ return true;
break;
case SUBMODULE_BLOCK_ID:
- switch (ReadSubmoduleBlock(F)) {
- case Success:
- break;
-
- case Failure:
- Error("malformed submodule block in AST file");
- return Failure;
-
- case IgnorePCH:
- return IgnorePCH;
- }
+ if (ReadSubmoduleBlock(F))
+ return true;
break;
case COMMENTS_BLOCK_ID: {
@@ -1750,7 +1894,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
- return Failure;
+ return true;
}
CommentsCursors.push_back(std::make_pair(C, &F));
break;
@@ -1760,7 +1904,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
if (!Stream.SkipBlock())
break;
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -1779,54 +1923,10 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
default: // Default behavior: ignore.
break;
- case METADATA: {
- if (Record[0] != VERSION_MAJOR && !DisableValidation) {
- Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
- return IgnorePCH;
- }
-
- bool hasErrors = Record[5];
- if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
- Diag(diag::err_pch_with_compiler_errors);
- return IgnorePCH;
- }
-
- RelocatablePCH = Record[4];
- if (Listener) {
- std::string TargetTriple(BlobStart, BlobLen);
- if (Listener->ReadTargetTriple(TargetTriple))
- return IgnorePCH;
- }
- break;
- }
-
- case IMPORTS: {
- // Load each of the imported PCH files.
- unsigned Idx = 0, N = Record.size();
- while (Idx < N) {
- // Read information about the AST file.
- ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
- unsigned Length = Record[Idx++];
- SmallString<128> ImportedFile(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- Idx += Length;
-
- // Load the AST file.
- switch(ReadASTCore(ImportedFile, ImportedKind, &F)) {
- case Failure: return Failure;
- // If we have to ignore the dependency, we'll have to ignore this too.
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
- break;
- }
-
case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.TypeOffsets = (const uint32_t *)BlobStart;
F.LocalNumTypes = Record[0];
@@ -1850,7 +1950,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_OFFSET: {
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.DeclOffsets = (const DeclOffset *)BlobStart;
F.LocalNumDecls = Record[0];
@@ -1904,11 +2004,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
break;
}
- case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record) && !DisableValidation)
- return IgnorePCH;
- break;
-
case IDENTIFIER_TABLE:
F.IdentifierTableData = BlobStart;
if (Record[0]) {
@@ -1925,7 +2020,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_OFFSET: {
if (F.LocalNumIdentifiers != 0) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return Failure;
+ return true;
}
F.IdentifierOffsets = (const uint32_t *)BlobStart;
F.LocalNumIdentifiers = Record[0];
@@ -1949,7 +2044,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
}
-
+
case EXTERNAL_DEFINITIONS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
@@ -1980,7 +2075,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case WEAK_UNDECLARED_IDENTIFIERS:
if (Record.size() % 4 != 0) {
Error("invalid weak identifiers record");
- return Failure;
+ return true;
}
// FIXME: Ignore weak undeclared identifiers from non-original PCH
@@ -2050,11 +2145,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case PP_COUNTER_VALUE:
if (!Record.empty() && Listener)
- Listener->ReadCounter(Record[0]);
+ Listener->ReadCounter(F, Record[0]);
break;
case FILE_SORTED_DECLS:
F.FileSortedDecls = (const DeclID *)BlobStart;
+ F.NumFileSortedDecls = Record[0];
break;
case SOURCE_LOCATION_OFFSETS: {
@@ -2098,7 +2194,9 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
IdentifierRemap(F.IdentifierRemap);
- ContinuousRangeMap<uint32_t, int, 2>::Builder
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
+ MacroRemap(F.MacroRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
PreprocessedEntityRemap(F.PreprocessedEntityRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
SubmoduleRemap(F.SubmoduleRemap);
@@ -2114,11 +2212,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
ModuleFile *OM = ModuleMgr.lookup(Name);
if (!OM) {
Error("SourceLocation remap refers to unknown module");
- return Failure;
+ return true;
}
uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
@@ -2131,6 +2230,8 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
IdentifierRemap.insert(
std::make_pair(IdentifierIDOffset,
OM->BaseIdentifierID - IdentifierIDOffset));
+ MacroRemap.insert(std::make_pair(MacroIDOffset,
+ OM->BaseMacroID - MacroIDOffset));
PreprocessedEntityRemap.insert(
std::make_pair(PreprocessedEntityIDOffset,
OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
@@ -2152,12 +2253,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_LINE_TABLE:
if (ParseLineTable(F, Record))
- return Failure;
- break;
-
- case FILE_SOURCE_LOCATION_OFFSETS:
- F.SLocFileOffsets = (const uint32_t *)BlobStart;
- F.LocalNumSLocFileEntries = Record[0];
+ return true;
break;
case SOURCE_LOCATION_PRELOADS: {
@@ -2165,25 +2261,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
// which is based off F.SLocEntryBaseID.
if (!F.PreloadSLocEntries.empty()) {
Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return Failure;
+ return true;
}
F.PreloadSLocEntries.swap(Record);
break;
}
- case STAT_CACHE: {
- if (!DisableStatCache) {
- ASTStatCache *MyStatCache =
- new ASTStatCache((const unsigned char *)BlobStart + Record[0],
- (const unsigned char *)BlobStart,
- NumStatHits, NumStatMisses);
- FileMgr.addStatCache(MyStatCache);
- F.StatCache = MyStatCache;
- }
- break;
- }
-
case EXT_VECTOR_DECLS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I]));
@@ -2192,7 +2276,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case VTABLE_USES:
if (Record.size() % 3 != 0) {
Error("Invalid VTABLE_USES record");
- return Failure;
+ return true;
}
// Later tables overwrite earlier ones.
@@ -2215,13 +2299,15 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case PENDING_IMPLICIT_INSTANTIATIONS:
if (PendingInstantiations.size() % 2 != 0) {
+ Error("Invalid existing PendingInstantiations");
+ return true;
+ }
+
+ if (Record.size() % 2 != 0) {
Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return Failure;
+ return true;
}
-
- // Later lists of pending instantiations overwrite earlier ones.
- // FIXME: This is most certainly wrong for modules.
- PendingInstantiations.clear();
+
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
PendingInstantiations.push_back(
@@ -2237,34 +2323,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
- case ORIGINAL_FILE_NAME:
- // The primary AST will be the last to get here, so it will be the one
- // that's used.
- ActualOriginalFileName.assign(BlobStart, BlobLen);
- OriginalFileName = ActualOriginalFileName;
- MaybeAddSystemRootToFilename(OriginalFileName);
- break;
-
- case ORIGINAL_FILE_ID:
- OriginalFileID = FileID::get(Record[0]);
- break;
-
- case ORIGINAL_PCH_DIR:
- // The primary AST will be the last to get here, so it will be the one
- // that's used.
- OriginalDir.assign(BlobStart, BlobLen);
- break;
-
- case VERSION_CONTROL_BRANCH_REVISION: {
- const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
- if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
- Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
- return IgnorePCH;
- }
- break;
- }
-
case PPD_ENTITIES_OFFSETS: {
F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
assert(BlobLen % sizeof(PPEntityOffset) == 0);
@@ -2300,7 +2358,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_UPDATE_OFFSETS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return Failure;
+ return true;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 2)
DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
@@ -2311,7 +2369,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_REPLACEMENTS: {
if (Record.size() % 3 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
- return Failure;
+ return true;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 3)
ReplacedDecls[getGlobalDeclID(F, Record[I])]
@@ -2322,7 +2380,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case OBJC_CATEGORIES_MAP: {
if (F.LocalNumObjCCategoriesInMap != 0) {
Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return Failure;
+ return true;
}
F.LocalNumObjCCategoriesInMap = Record[0];
@@ -2337,7 +2395,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
- return Failure;
+ return true;
}
F.LocalNumCXXBaseSpecifiers = Record[0];
@@ -2347,11 +2405,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
case DIAG_PRAGMA_MAPPINGS:
- if (Record.size() % 2 != 0) {
- Error("invalid DIAG_USER_MAPPINGS block in AST file");
- return Failure;
- }
-
if (F.PragmaDiagMappings.empty())
F.PragmaDiagMappings.swap(Record);
else
@@ -2428,7 +2481,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
case LOCAL_REDECLARATIONS_MAP: {
if (F.LocalNumRedeclarationsInMap != 0) {
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return Failure;
+ return true;
}
F.LocalNumRedeclarationsInMap = Record[0];
@@ -2445,113 +2498,77 @@ ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
}
- }
- }
- Error("premature end of bitstream in AST file");
- return Failure;
-}
-
-ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
- llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor;
-
- for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) {
- SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]);
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
- }
- RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default:
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
+ case MACRO_OFFSET: {
+ if (F.LocalNumMacros != 0) {
+ Error("duplicate MACRO_OFFSET record in AST file");
+ return true;
+ }
+ F.MacroOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumMacros = Record[0];
+ unsigned LocalBaseMacroID = Record[1];
+ F.BaseMacroID = getTotalNumMacros();
- case SM_SLOC_FILE_ENTRY: {
- // If the buffer was overridden, the file need not exist.
- if (Record[6])
- break;
-
- StringRef Filename(BlobStart, BlobLen);
- const FileEntry *File = getFileEntry(Filename);
+ if (F.LocalNumMacros > 0) {
+ // Introduce the global -> local mapping for macros within this module.
+ GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F));
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return IgnorePCH;
- }
+ // Introduce the local -> global mapping for macros within this module.
+ F.MacroRemap.insertOrReplace(
+ std::make_pair(LocalBaseMacroID,
+ F.BaseMacroID - LocalBaseMacroID));
- if (Record.size() < 7) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
- off_t StoredSize = (off_t)Record[4];
- time_t StoredTime = (time_t)Record[5];
-
- // Check if there was a request to override the contents of the file
- // that was part of the precompiled header. Overridding such a file
- // can lead to problems when lexing using the source locations from the
- // PCH.
- SourceManager &SM = getSourceManager();
- if (SM.isFileOverridden(File)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
+ MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros);
}
+ break;
+ }
- // The stat info from the FileEntry came from the cached stat
- // info of the PCH, so we cannot trust it.
- struct stat StatBuf;
- if (::stat(File->getName(), &StatBuf) != 0) {
- StatBuf.st_size = File->getSize();
- StatBuf.st_mtime = File->getModificationTime();
- }
+ case MACRO_UPDATES: {
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ MacroID ID = getGlobalMacroID(F, Record[I++]);
+ if (I == N)
+ break;
- if ((StoredSize != StatBuf.st_size
-#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || StoredTime != StatBuf.st_mtime
-#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- return IgnorePCH;
+ SourceLocation UndefLoc = ReadSourceLocation(F, Record, I);
+ SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);;
+ MacroUpdate Update;
+ Update.UndefLoc = UndefLoc;
+ MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update));
}
-
break;
}
}
}
-
- return Success;
+ Error("premature end of bitstream in AST file");
+ return true;
}
void ASTReader::makeNamesVisible(const HiddenNames &Names) {
for (unsigned I = 0, N = Names.size(); I != N; ++I) {
- if (Decl *D = Names[I].dyn_cast<Decl *>())
- D->Hidden = false;
- else {
- IdentifierInfo *II = Names[I].get<IdentifierInfo *>();
- if (!II->hasMacroDefinition()) {
- II->setHasMacroDefinition(true);
- if (DeserializationListener)
- DeserializationListener->MacroVisible(II);
+ switch (Names[I].getKind()) {
+ case HiddenName::Declaration:
+ Names[I].getDecl()->Hidden = false;
+ break;
+
+ case HiddenName::MacroVisibility: {
+ std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
+ Macro.second->setHidden(!Macro.second->isPublic());
+ if (Macro.second->isDefined()) {
+ PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ }
+ break;
+ }
+
+ case HiddenName::MacroUndef: {
+ std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
+ if (Macro.second->isDefined()) {
+ Macro.second->setUndefLoc(Names[I].getMacroUndefLoc());
+ if (PPMutationListener *Listener = PP.getPPMutationListener())
+ Listener->UndefinedMacro(Macro.second);
+ PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
}
+ break;
+ }
}
}
}
@@ -2631,7 +2648,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
Module *Imported = Mod->Imports[I];
- if (Visited.count(Imported))
+ if (!Visited.insert(Imported))
continue;
bool Acceptable = UnrestrictedWildcard;
@@ -2649,32 +2666,62 @@ void ASTReader::makeModuleVisible(Module *Mod,
if (!Acceptable)
continue;
- Visited.insert(Imported);
Stack.push_back(Imported);
}
}
}
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
- ModuleKind Type) {
+ ModuleKind Type,
+ unsigned ClientLoadCapabilities) {
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
-
- switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
+
+ unsigned NumModules = ModuleMgr.size();
+ llvm::SmallVector<ModuleFile *, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type,
+ /*ImportedBy=*/0, Loaded,
+ ClientLoadCapabilities)) {
+ case Failure:
+ case OutOfDate:
+ case VersionMismatch:
+ case ConfigurationMismatch:
+ case HadErrors:
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ return ReadResult;
+
+ case Success:
+ break;
}
// Here comes stuff that we only do once the entire chain is loaded.
- // Check the predefines buffers.
- if (!DisableValidation && Type == MK_PCH &&
- // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
- // if DisableValidation is true, defines that were set on command-line
- // but not in the PCH file will not be added to SuggestedPredefines.
- CheckPredefinesBuffers())
- return IgnorePCH;
+ // Load the AST blocks of all of the modules that we loaded.
+ for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = **M;
+
+ // Read the AST block.
+ if (ReadASTBlock(F))
+ return Failure;
+
+ // Once read, set the ModuleFile bit base offset and update the size in
+ // bits of all files we've seen.
+ F.GlobalBitOffset = TotalModulesSizeInBits;
+ TotalModulesSizeInBits += F.SizeInBits;
+ GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
+
+ // Preload SLocEntries.
+ for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
+ int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
+ // Load it through the SourceManager and don't call ReadSLocEntry()
+ // directly because the entry may have already been loaded in which case
+ // calling ReadSLocEntry() directly would trigger an assertion in
+ // SourceManager.
+ SourceMgr.getLoadedSLocEntryByID(Index);
+ }
+ }
// Mark all of the identifiers in the identifier table as being out of date,
// so that various accessors know to check the loaded modules when the
@@ -2707,17 +2754,19 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
- if (!OriginalFileID.isInvalid()) {
- OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
- + OriginalFileID.getOpaqueValue() - 1);
+ ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
+ if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
+ PrimaryModule.OriginalSourceFileID
+ = FileID::get(PrimaryModule.SLocEntryBaseID
+ + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
- // If this AST file is a precompiled preamble, then set the preamble file ID
- // of the source manager to the file source file from which the preamble was
- // built.
+ // If this AST file is a precompiled preamble, then set the
+ // preamble file ID of the source manager to the file source file
+ // from which the preamble was built.
if (Type == MK_Preamble) {
- SourceMgr.setPreambleFileID(OriginalFileID);
+ SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID);
} else if (Type == MK_MainFile) {
- SourceMgr.setMainFileID(OriginalFileID);
+ SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID);
}
}
@@ -2732,9 +2781,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
return Success;
}
-ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
- ModuleKind Type,
- ModuleFile *ImportedBy) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTCore(StringRef FileName,
+ ModuleKind Type,
+ ModuleFile *ImportedBy,
+ llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ unsigned ClientLoadCapabilities) {
ModuleFile *M;
bool NewModule;
std::string ErrorStr;
@@ -2785,7 +2837,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
unsigned BlockID = Stream.ReadSubBlockID();
- // We only know the AST subblock ID.
+ // We only know the control subblock ID.
switch (BlockID) {
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (Stream.ReadBlockInfoBlock()) {
@@ -2793,29 +2845,23 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
return Failure;
}
break;
- case AST_BLOCK_ID:
- switch (ReadASTBlock(F)) {
+ case CONTROL_BLOCK_ID:
+ switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
case Success:
break;
- case Failure:
- return Failure;
-
- case IgnorePCH:
- // FIXME: We could consider reading through to the end of this
- // AST block, skipping subblocks, to see if there are other
- // AST blocks elsewhere.
-
- // FIXME: We can't clear loaded slocentries anymore.
- //SourceMgr.ClearPreallocatedSLocEntries();
-
- // Remove the stat cache.
- if (F.StatCache)
- FileMgr.removeStatCache((ASTStatCache*)F.StatCache);
-
- return IgnorePCH;
+ case Failure: return Failure;
+ case OutOfDate: return OutOfDate;
+ case VersionMismatch: return VersionMismatch;
+ case ConfigurationMismatch: return ConfigurationMismatch;
+ case HadErrors: return HadErrors;
}
break;
+ case AST_BLOCK_ID:
+ // Record that we've loaded this module.
+ Loaded.push_back(M);
+ return Success;
+
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
@@ -2825,32 +2871,6 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
}
}
- // Once read, set the ModuleFile bit base offset and update the size in
- // bits of all files we've seen.
- F.GlobalBitOffset = TotalModulesSizeInBits;
- TotalModulesSizeInBits += F.SizeInBits;
- GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
-
- // Make sure that the files this module was built against are still available.
- if (!DisableValidation) {
- switch(validateFileEntries(*M)) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
-
- // Preload SLocEntries.
- for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) {
- int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
- // Load it through the SourceManager and don't call ReadSLocEntryRecord()
- // directly because the entry may have already been loaded in which case
- // calling ReadSLocEntryRecord() directly would trigger an assertion in
- // SourceManager.
- SourceMgr.getLoadedSLocEntryByID(Index);
- }
-
-
return Success;
}
@@ -3038,8 +3058,8 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
// We only know the AST subblock ID.
switch (BlockID) {
- case AST_BLOCK_ID:
- if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
+ case CONTROL_BLOCK_ID:
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
return std::string();
}
@@ -3071,19 +3091,191 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
Record.clear();
const char *BlobStart = 0;
unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)
- == ORIGINAL_FILE_NAME)
+ if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
return std::string(BlobStart, BlobLen);
}
return std::string();
}
-ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+namespace {
+ class SimplePCHValidator : public ASTReaderListener {
+ const LangOptions &ExistingLangOpts;
+ const TargetOptions &ExistingTargetOpts;
+ const PreprocessorOptions &ExistingPPOpts;
+ FileManager &FileMgr;
+
+ public:
+ SimplePCHValidator(const LangOptions &ExistingLangOpts,
+ const TargetOptions &ExistingTargetOpts,
+ const PreprocessorOptions &ExistingPPOpts,
+ FileManager &FileMgr)
+ : ExistingLangOpts(ExistingLangOpts),
+ ExistingTargetOpts(ExistingTargetOpts),
+ ExistingPPOpts(ExistingPPOpts),
+ FileMgr(FileMgr)
+ {
+ }
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
+ }
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
+ }
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
+ SuggestedPredefines);
+ }
+ };
+}
+
+bool ASTReader::readASTFileControlBlock(StringRef Filename,
+ FileManager &FileMgr,
+ ASTReaderListener &Listener) {
+ // Open the AST file.
+ std::string ErrStr;
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the stream
+ llvm::BitstreamReader StreamFile;
+ llvm::BitstreamCursor Stream;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'P' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(8) != 'H') {
+ return true;
+ }
+
+ RecordData Record;
+ bool InControlBlock = false;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the control subblock ID.
+ switch (BlockID) {
+ case CONTROL_BLOCK_ID:
+ if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+ return true;
+ } else {
+ InControlBlock = true;
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock())
+ return true;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ return true;
+ }
+
+ InControlBlock = false;
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ if (InControlBlock) {
+ switch ((ControlRecordTypes)RecCode) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR) {
+ return true;
+ }
+
+ const std::string &CurBranch = getClangFullRepositoryVersion();
+ StringRef ASTBranch(BlobStart, BlobLen);
+ if (StringRef(CurBranch) != ASTBranch)
+ return true;
+
+ break;
+ }
+ case LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case TARGET_OPTIONS:
+ if (ParseTargetOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case DIAGNOSTIC_OPTIONS:
+ if (ParseDiagnosticOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case FILE_SYSTEM_OPTIONS:
+ if (ParseFileSystemOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case HEADER_SEARCH_OPTIONS:
+ if (ParseHeaderSearchOptions(Record, false, Listener))
+ return true;
+ break;
+
+ case PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
+
+ default:
+ // No other validation to perform.
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool ASTReader::isAcceptableASTFile(StringRef Filename,
+ FileManager &FileMgr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts) {
+ SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr);
+ return !readASTFileControlBlock(Filename, FileMgr, validator);
+}
+
+bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
// Enter the submodule block.
if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
Error("malformed submodule block record in AST file");
- return Failure;
+ return true;
}
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
@@ -3095,9 +3287,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (Code == llvm::bitc::END_BLOCK) {
if (F.Stream.ReadBlockEnd()) {
Error("error at end of submodule block in AST file");
- return Failure;
+ return true;
}
- return Success;
+ return false;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
@@ -3105,7 +3297,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
F.Stream.ReadSubBlockID();
if (F.Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return Failure;
+ return true;
}
continue;
}
@@ -3126,12 +3318,12 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_DEFINITION: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (Record.size() < 7) {
Error("malformed module definition");
- return Failure;
+ return true;
}
StringRef Name(BlobStart, BlobLen);
@@ -3157,9 +3349,10 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
Error("too many submodules");
- return Failure;
+ return true;
}
+ CurrentModule->setASTFile(F.File);
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->InferSubmodules = InferSubmodules;
@@ -3175,7 +3368,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3187,7 +3380,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
Error("mismatched umbrella headers in submodule");
- return Failure;
+ return true;
}
}
break;
@@ -3196,7 +3389,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3208,15 +3401,51 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (std::find(CurrentModule->Headers.begin(),
CurrentModule->Headers.end(),
File) == CurrentModule->Headers.end())
- ModMap.addHeader(CurrentModule, File);
+ ModMap.addHeader(CurrentModule, File, false);
}
break;
}
-
+
+ case SUBMODULE_EXCLUDED_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ ModMap.addHeader(CurrentModule, File, true);
+ }
+ break;
+ }
+
+ case SUBMODULE_TOPHEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName))
+ CurrentModule->TopHeaders.insert(File);
+ break;
+ }
+
case SUBMODULE_UMBRELLA_DIR: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3229,7 +3458,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
Error("mismatched umbrella directories in submodule");
- return Failure;
+ return true;
}
}
break;
@@ -3238,7 +3467,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_METADATA: {
if (!First) {
Error("submodule metadata record not at beginning of block");
- return Failure;
+ return true;
}
First = false;
@@ -3264,7 +3493,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_IMPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3285,7 +3514,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3309,7 +3538,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_REQUIRES: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return Failure;
+ return true;
}
if (!CurrentModule)
@@ -3331,27 +3560,144 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
/// them to the AST listener if one is set.
///
/// \returns true if the listener deems the file unacceptable, false otherwise.
-bool ASTReader::ParseLanguageOptions(const RecordData &Record) {
- if (Listener) {
- LangOptions LangOpts;
- unsigned Idx = 0;
+bool ASTReader::ParseLanguageOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ LangOptions LangOpts;
+ unsigned Idx = 0;
#define LANGOPT(Name, Bits, Default, Description) \
LangOpts.Name = Record[Idx++];
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
- ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
- VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
- LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
-
- unsigned Length = Record[Idx++];
- LangOpts.CurrentModule.assign(Record.begin() + Idx,
- Record.begin() + Idx + Length);
- return Listener->ReadLanguageOptions(LangOpts);
+ ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
+ VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
+ LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
+
+ unsigned Length = Record[Idx++];
+ LangOpts.CurrentModule.assign(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ return Listener.ReadLanguageOptions(LangOpts, Complain);
+}
+
+bool ASTReader::ParseTargetOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ unsigned Idx = 0;
+ TargetOptions TargetOpts;
+ TargetOpts.Triple = ReadString(Record, Idx);
+ TargetOpts.CPU = ReadString(Record, Idx);
+ TargetOpts.ABI = ReadString(Record, Idx);
+ TargetOpts.CXXABI = ReadString(Record, Idx);
+ TargetOpts.LinkerVersion = ReadString(Record, Idx);
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
+ }
+ for (unsigned N = Record[Idx++]; N; --N) {
+ TargetOpts.Features.push_back(ReadString(Record, Idx));
}
- return false;
+ return Listener.ReadTargetOptions(TargetOpts, Complain);
+}
+
+bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ DiagnosticOptions DiagOpts;
+ unsigned Idx = 0;
+#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
+#include "clang/Basic/DiagnosticOptions.def"
+
+ for (unsigned N = Record[Idx++]; N; --N) {
+ DiagOpts.Warnings.push_back(ReadString(Record, Idx));
+ }
+
+ return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
+}
+
+bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ FileSystemOptions FSOpts;
+ unsigned Idx = 0;
+ FSOpts.WorkingDir = ReadString(Record, Idx);
+ return Listener.ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener) {
+ HeaderSearchOptions HSOpts;
+ unsigned Idx = 0;
+ HSOpts.Sysroot = ReadString(Record, Idx);
+
+ // Include entries.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Path = ReadString(Record, Idx);
+ frontend::IncludeDirGroup Group
+ = static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
+ bool IsUserSupplied = Record[Idx++];
+ bool IsFramework = Record[Idx++];
+ bool IgnoreSysRoot = Record[Idx++];
+ bool IsInternal = Record[Idx++];
+ bool ImplicitExternC = Record[Idx++];
+ HSOpts.UserEntries.push_back(
+ HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework,
+ IgnoreSysRoot, IsInternal, ImplicitExternC));
+ }
+
+ // System header prefixes.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Prefix = ReadString(Record, Idx);
+ bool IsSystemHeader = Record[Idx++];
+ HSOpts.SystemHeaderPrefixes.push_back(
+ HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader));
+ }
+
+ HSOpts.ResourceDir = ReadString(Record, Idx);
+ HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.UseBuiltinIncludes = Record[Idx++];
+ HSOpts.UseStandardSystemIncludes = Record[Idx++];
+ HSOpts.UseStandardCXXIncludes = Record[Idx++];
+ HSOpts.UseLibcxx = Record[Idx++];
+
+ return Listener.ReadHeaderSearchOptions(HSOpts, Complain);
+}
+
+bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
+ bool Complain,
+ ASTReaderListener &Listener,
+ std::string &SuggestedPredefines) {
+ PreprocessorOptions PPOpts;
+ unsigned Idx = 0;
+
+ // Macro definitions/undefs
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string Macro = ReadString(Record, Idx);
+ bool IsUndef = Record[Idx++];
+ PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef));
+ }
+
+ // Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.Includes.push_back(ReadString(Record, Idx));
+ }
+
+ // Macro Includes
+ for (unsigned N = Record[Idx++]; N; --N) {
+ PPOpts.MacroIncludes.push_back(ReadString(Record, Idx));
+ }
+
+ PPOpts.UsePredefines = Record[Idx++];
+ PPOpts.ImplicitPCHInclude = ReadString(Record, Idx);
+ PPOpts.ImplicitPTHInclude = ReadString(Record, Idx);
+ PPOpts.ObjCXXARCStandardLibrary =
+ static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]);
+ SuggestedPredefines.clear();
+ return Listener.ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines);
}
std::pair<ModuleFile *, unsigned>
@@ -3365,6 +3711,23 @@ ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
return std::make_pair(M, LocalIndex);
}
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const {
+ if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord())
+ return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID,
+ Mod.NumPreprocessedEntities);
+
+ return std::make_pair(PreprocessingRecord::iterator(),
+ PreprocessingRecord::iterator());
+}
+
+std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator>
+ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) {
+ return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls),
+ ModuleDeclIterator(this, &Mod,
+ Mod.FileSortedDecls + Mod.NumFileSortedDecls));
+}
+
PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
PreprocessedEntityID PPID = Index+1;
std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
@@ -3455,7 +3818,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
InclusionDirective *ID
= new (PPRec) InclusionDirective(PPRec, Kind,
StringRef(BlobStart, Record[0]),
- Record[1],
+ Record[1], Record[3],
File,
Range);
return ID;
@@ -3476,7 +3839,7 @@ PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
ModuleFile &M = *SLocMapI->second;
if (M.NumPreprocessedEntities)
- return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID);
+ return M.BasePreprocessedEntityID;
}
return getTotalNumPreprocessedEntities();
@@ -3559,8 +3922,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
if (PPI == pp_end)
return findNextPreprocessedEntity(SLocMapI);
- return getGlobalPreprocessedEntityID(M,
- M.BasePreprocessedEntityID + (PPI - pp_begin));
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
}
/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
@@ -3589,8 +3951,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
if (PPI == pp_end)
return findNextPreprocessedEntity(SLocMapI);
- return getGlobalPreprocessedEntityID(M,
- M.BasePreprocessedEntityID + (PPI - pp_begin));
+ return M.BasePreprocessedEntityID + (PPI - pp_begin);
}
/// \brief Returns a pair of [Begin, End) indices of preallocated
@@ -3681,14 +4042,31 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
}
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
ModuleFile &F = *(*I);
unsigned Idx = 0;
+ DiagStates.clear();
+ assert(!Diag.DiagStates.empty());
+ DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
while (Idx < F.PragmaDiagMappings.size()) {
SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
+ if (DiagStateID != 0) {
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
+ FullSourceLoc(Loc, SourceMgr)));
+ continue;
+ }
+
+ assert(DiagStateID == 0);
+ // A new DiagState was created here.
Diag.DiagStates.push_back(*Diag.GetCurDiagState());
+ DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ DiagStates.push_back(NewState);
Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(&Diag.DiagStates.back(),
+ DiagnosticsEngine::DiagStatePoint(NewState,
FullSourceLoc(Loc, SourceMgr)));
while (1) {
assert(Idx < F.PragmaDiagMappings.size() &&
@@ -4258,6 +4636,8 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
}
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
@@ -4467,6 +4847,10 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_VA_LIST_TAG:
T = Context.getVaListTagType();
break;
+
+ case PREDEF_TYPE_BUILTIN_FN:
+ T = Context.BuiltinFnTy;
+ break;
}
assert(!T.isNull() && "Unknown predefined type");
@@ -4537,7 +4921,9 @@ ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Pack:
+ // FIXME: Is this right?
return TemplateArgumentLocInfo();
}
llvm_unreachable("unexpected template argument loc");
@@ -4593,7 +4979,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
}
serialization::DeclID
-ASTReader::getGlobalDeclID(ModuleFile &F, unsigned LocalID) const {
+ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
if (LocalID < NUM_PREDEF_DECL_IDS)
return LocalID;
@@ -4930,8 +5316,10 @@ namespace {
continue;
if (ND->getDeclName() != This->Name) {
- assert(!This->Name.getCXXNameType().isNull() &&
- "Name mismatch without a type");
+ // A name might be null because the decl's redeclarable part is
+ // currently read before reading its name. The lookup is triggered by
+ // building that decl (likely indirectly), and so it is later in the
+ // sense of "already existing" and can be ignored here.
continue;
}
@@ -5132,13 +5520,15 @@ void ASTReader::PrintStats() {
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
IdentifiersLoaded.end(),
(IdentifierInfo *)0);
+ unsigned NumMacrosLoaded
+ = MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
+ MacrosLoaded.end(),
+ (MacroInfo *)0);
unsigned NumSelectorsLoaded
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
SelectorsLoaded.end(),
Selector());
- std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
- std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
if (unsigned TotalNumSLocEntries = getTotalNumSLocs())
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
NumSLocEntriesRead, TotalNumSLocEntries,
@@ -5155,6 +5545,10 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n",
NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(),
((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100));
+ if (!MacrosLoaded.empty())
+ std::fprintf(stderr, " %u/%u macros read (%f%%)\n",
+ NumMacrosLoaded, (unsigned)MacrosLoaded.size(),
+ ((float)NumMacrosLoaded/MacrosLoaded.size() * 100));
if (!SelectorsLoaded.empty())
std::fprintf(stderr, " %u/%u selectors read (%f%%)\n",
NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(),
@@ -5213,6 +5607,7 @@ void ASTReader::dump() {
dumpModuleIDMap("Global type map", GlobalTypeMap);
dumpModuleIDMap("Global declaration map", GlobalDeclMap);
dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global macro map", GlobalMacroMap);
dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
dumpModuleIDMap("Global selector map", GlobalSelectorMap);
dumpModuleIDMap("Global preprocessed entity map",
@@ -5246,7 +5641,7 @@ void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
void ASTReader::InitializeSema(Sema &S) {
SemaObj = &S;
- S.ExternalSource = this;
+ S.addExternalSource(this);
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
@@ -5281,6 +5676,9 @@ void ASTReader::InitializeSema(Sema &S) {
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
+ // Note that we are loading an identifier.
+ Deserializing AnIdentifier(this);
+
IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
/*PriorGeneration=*/0);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
@@ -5570,6 +5968,7 @@ void ASTReader::ReadPendingInstantiations(
ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++]));
SourceLocation Loc
= SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]);
+
Pending.push_back(std::make_pair(D, Loc));
}
PendingInstantiations.clear();
@@ -5682,8 +6081,37 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
return LocalID + I->second;
}
-bool ASTReader::ReadSLocEntry(int ID) {
- return ReadSLocEntryRecord(ID) != Success;
+MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
+ if (ID == 0)
+ return 0;
+
+ if (MacrosLoaded.empty()) {
+ Error("no macro table in AST file");
+ return 0;
+ }
+
+ ID -= NUM_PREDEF_MACRO_IDS;
+ if (!MacrosLoaded[ID]) {
+ GlobalMacroMapType::iterator I
+ = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS);
+ assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
+ ModuleFile *M = I->second;
+ unsigned Index = ID - M->BaseMacroID;
+ ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
+ }
+
+ return MacrosLoaded[ID];
+}
+
+MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_MACRO_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
+ assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
+
+ return LocalID + I->second;
}
serialization::SubmoduleID
@@ -5694,7 +6122,7 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
assert(I != M.SubmoduleRemap.end()
- && "Invalid index into identifier index remap");
+ && "Invalid index into submodule index remap");
return LocalID + I->second;
}
@@ -5759,7 +6187,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
assert(I != M.SelectorRemap.end()
- && "Invalid index into identifier index remap");
+ && "Invalid index into selector index remap");
return LocalID + I->second;
}
@@ -5926,8 +6354,13 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
return TemplateArgument();
case TemplateArgument::Type:
return TemplateArgument(readType(F, Record, Idx));
- case TemplateArgument::Declaration:
- return TemplateArgument(ReadDecl(F, Record, Idx));
+ case TemplateArgument::Declaration: {
+ ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx);
+ bool ForReferenceParam = Record[Idx++];
+ return TemplateArgument(D, ForReferenceParam);
+ }
+ case TemplateArgument::NullPtr:
+ return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true);
case TemplateArgument::Integral: {
llvm::APSInt Value = ReadAPSInt(Record, Idx);
QualType T = readType(F, Record, Idx);
@@ -6340,7 +6773,8 @@ void ASTReader::ReadComments() {
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty()) {
+ while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
+ !PendingMacroIDs.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
while (!PendingIdentifierInfos.empty()) {
@@ -6355,6 +6789,18 @@ void ASTReader::finishPendingActions() {
PendingDeclChainsKnown.erase(PendingDeclChains[I]);
}
PendingDeclChains.clear();
+
+ // Load any pending macro definitions.
+ for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
+ // FIXME: std::move here
+ SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second;
+ MacroInfo *Hint = 0;
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ Hint = getMacro(GlobalIDs[IDIdx], Hint);
+ }
+ }
+ PendingMacroIDs.clear();
}
// If we deserialized any C++ or Objective-C class definitions, any
@@ -6408,9 +6854,29 @@ void ASTReader::finishPendingActions() {
for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
REnd = RTD->redecls_end();
R != REnd; ++R)
- R->Common = RTD->Common;
+ R->Common = RTD->Common;
}
PendingDefinitions.clear();
+
+ // Load the bodies of any functions or methods we've encountered. We do
+ // this now (delayed) so that we can be sure that the declaration chains
+ // have been fully wired up.
+ for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
+ PBEnd = PendingBodies.end();
+ PB != PBEnd; ++PB) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
+ // FIXME: Check for =delete/=default?
+ // FIXME: Complain about ODR violations here?
+ if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ FD->setLazyBody(PB->second);
+ continue;
+ }
+
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first);
+ if (!getContext().getLangOpts().Modules || !MD->hasBody())
+ MD->setLazyBody(PB->second);
+ }
+ PendingBodies.clear();
}
void ASTReader::FinishedDeserializing() {
@@ -6442,17 +6908,14 @@ void ASTReader::FinishedDeserializing() {
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, bool DisableValidation,
- bool DisableStatCache, bool AllowASTWithCompilerErrors)
+ bool AllowASTWithCompilerErrors)
: Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
- Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
- RelocatablePCH(false), isysroot(isysroot),
- DisableValidation(DisableValidation),
- DisableStatCache(DisableStatCache),
+ Consumer(0), ModuleMgr(PP.getFileManager()),
+ isysroot(isysroot), DisableValidation(DisableValidation),
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
- NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index cb21f82600e0..c42944df6344 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -37,7 +37,6 @@ namespace clang {
class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
ASTReader &Reader;
ModuleFile &F;
- llvm::BitstreamCursor &Cursor;
const DeclID ThisDeclID;
const unsigned RawLocation;
typedef ASTReader::RecordData RecordData;
@@ -48,6 +47,8 @@ namespace clang {
DeclID DeclContextIDForTemplateParmDecl;
DeclID LexicalDeclContextIDForTemplateParmDecl;
+ bool HasPendingBody;
+
uint64_t GetCurrentCursorOffset();
SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
@@ -116,7 +117,7 @@ namespace clang {
GlobalDeclID FirstID;
mutable bool Owning;
- RedeclarableResult &operator=(RedeclarableResult&); // DO NOT IMPLEMENT
+ void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION;
public:
RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
@@ -162,7 +163,7 @@ namespace clang {
NamedDecl *Existing;
mutable bool AddResult;
- FindExistingResult &operator=(FindExistingResult&); // DO NOT IMPLEMENT
+ void operator=(FindExistingResult&) LLVM_DELETED_FUNCTION;
public:
FindExistingResult(ASTReader &Reader)
@@ -194,16 +195,19 @@ namespace clang {
public:
ASTDeclReader(ASTReader &Reader, ModuleFile &F,
- llvm::BitstreamCursor &Cursor, DeclID thisDeclID,
+ DeclID thisDeclID,
unsigned RawLocation,
const RecordData &Record, unsigned &Idx)
- : Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID),
+ : Reader(Reader), F(F), ThisDeclID(thisDeclID),
RawLocation(RawLocation), Record(Record), Idx(Idx),
- TypeIDForTypeDecl(0) { }
+ TypeIDForTypeDecl(0), HasPendingBody(false) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
static void attachLatestDecl(Decl *D, Decl *latest);
+ /// \brief Determine whether this declaration has a pending body.
+ bool hasPendingBody() const { return HasPendingBody; }
+
void Visit(Decl *D);
void UpdateDecl(Decl *D, ModuleFile &ModuleFile,
@@ -321,8 +325,14 @@ void ASTDeclReader::Visit(Decl *D) {
ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
- if (Record[Idx++])
- FD->setLazyBody(GetCurrentCursorOffset());
+ // We only read it if FD doesn't already have a body (e.g., from another
+ // module).
+ // FIXME: Also consider = default and = delete.
+ // FIXME: Can we diagnose ODR violations somehow?
+ if (Record[Idx++]) {
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ }
} else if (D->isTemplateParameter()) {
// If we have a fully initialized template parameter, we can now
// set its DeclContext.
@@ -590,8 +600,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
TemplArgs.size(), C);
void *InsertPos = 0;
CanonTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
- assert(InsertPos && "Another specialization already inserted!");
- CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
+ if (InsertPos)
+ CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
+ else
+ assert(0 && "Another specialization already inserted!");
}
break;
}
@@ -628,19 +640,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
VisitNamedDecl(MD);
if (Record[Idx++]) {
- // In practice, this won't be executed (since method definitions
- // don't occur in header files).
- // Switch case IDs for this method body.
- ASTReader::SwitchCaseMapTy SwitchCaseStmtsForObjCMethod;
- SaveAndRestore<ASTReader::SwitchCaseMapTy *>
- SCFOM(Reader.CurrSwitchCaseStmts, &SwitchCaseStmtsForObjCMethod);
- MD->setBody(Reader.ReadStmt(F));
+ // Load the body on-demand. Most clients won't care, because method
+ // definitions rarely show up in headers.
+ Reader.PendingBodies[MD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx));
}
MD->setInstanceMethod(Record[Idx++]);
MD->setVariadic(Record[Idx++]);
- MD->setSynthesized(Record[Idx++]);
+ MD->setPropertyAccessor(Record[Idx++]);
MD->setDefined(Record[Idx++]);
MD->IsOverriding = Record[Idx++];
@@ -846,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
+ D->setHasNonZeroConstructors(Record[Idx++]);
+ D->setHasDestructors(Record[Idx++]);
llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
@@ -897,7 +908,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.NRVOVariable = Record[Idx++];
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
-
+ VD->VarDeclBits.IsConstexpr = Record[Idx++];
+
// Only true variables (not parameters or implicit parameters) can be merged.
if (VD->getKind() == Decl::Var)
mergeRedeclarable(VD, Redecl);
@@ -1135,6 +1147,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.Captures
= (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
+ Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
SourceLocation Loc = ReadSourceLocation(Record, Idx);
bool IsImplicit = Record[Idx++];
@@ -1155,7 +1168,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record[Idx++];
if (IsLambda)
- D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false);
+ D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0,
+ false);
else
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
@@ -1242,6 +1256,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1);
for (unsigned I = 0, N = Record.back(); I != N; ++I)
StoredLocs[I] = ReadSourceLocation(Record, Idx);
+ ++Idx; // The number of stored source locations.
}
void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
@@ -1308,10 +1323,12 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
D->setMemberSpecialization();
}
}
-
+
VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
-
+
+ mergeRedeclarable(D, Redecl);
+
return Redecl;
}
@@ -1336,10 +1353,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
for (unsigned I = 0; I != Size; ++I)
SpecIDs.push_back(ReadDeclID(Record, Idx));
+ ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
if (SpecIDs[0]) {
typedef serialization::DeclID DeclID;
- ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
// FIXME: Append specializations!
CommonPtr->LazySpecializations
= new (Reader.getContext()) DeclID [SpecIDs.size()];
@@ -1347,7 +1364,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
SpecIDs.size() * sizeof(DeclID));
}
- // InjectedClassNameType is computed.
+ CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx);
}
}
@@ -1391,14 +1408,17 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl(
TemplArgs.size());
D->PointOfInstantiation = ReadSourceLocation(Record, Idx);
D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++];
-
- if (D->isCanonicalDecl()) { // It's kept in the folding set.
+
+ bool writtenAsCanonicalDecl = Record[Idx++];
+ if (writtenAsCanonicalDecl) {
ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
- if (ClassTemplatePartialSpecializationDecl *Partial
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
- CanonPattern->getCommonPtr()->PartialSpecializations.InsertNode(Partial);
- } else {
- CanonPattern->getCommonPtr()->Specializations.InsertNode(D);
+ if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ if (ClassTemplatePartialSpecializationDecl *Partial
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+ CanonPattern->getCommonPtr()->PartialSpecializations.GetOrInsertNode(Partial);
+ } else {
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
}
}
}
@@ -1486,11 +1506,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// TemplateParmPosition.
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
- // Rest of TemplateTemplateParmDecl.
- TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
- bool IsInherited = Record[Idx++];
- D->setDefaultArgument(Arg, IsInherited);
- D->ParameterPack = Record[Idx++];
+ if (D->isExpandedParameterPack()) {
+ void **Data = reinterpret_cast<void **>(D + 1);
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
+ bool IsInherited = Record[Idx++];
+ D->setDefaultArgument(Arg, IsInherited);
+ D->ParameterPack = Record[Idx++];
+ }
}
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@@ -1640,7 +1667,7 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) {
/// This routine should return true for anything that might affect
/// code generation, e.g., inline function definitions, Objective-C
/// declarations with metadata, etc.
-static bool isConsumerInterestedIn(Decl *D) {
+static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
// An ObjCMethodDecl is never considered as "interesting" because its
// implementation container always is.
@@ -1652,7 +1679,7 @@ static bool isConsumerInterestedIn(Decl *D) {
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->doesThisDeclarationHaveABody();
+ return Func->doesThisDeclarationHaveABody() || HasBody;
return false;
}
@@ -1719,8 +1746,10 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
TagDecl *TagY = cast<TagDecl>(Y);
return (TagX->getTagKind() == TagY->getTagKind()) ||
- ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
- (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
+ ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
+ TagX->getTagKind() == TTK_Interface) &&
+ (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
+ TagY->getTagKind() == TTK_Interface));
}
// Functions with the same type and linkage match.
@@ -1731,7 +1760,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
return (FuncX->getLinkage() == FuncY->getLinkage()) &&
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);
@@ -1744,7 +1773,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
return NamespaceX->isInline() == NamespaceY->isInline();
}
-
+
+ // Identical template names and kinds match.
+ if (isa<TemplateDecl>(X))
+ return true;
+
// FIXME: Many other cases to implement.
return false;
}
@@ -1753,11 +1786,13 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
- DeclContext *DC = New->getDeclContext()->getRedeclContext();
- if (DC->isTranslationUnit() && Reader.SemaObj) {
+ if (New->getDeclContext()->getRedeclContext()->isTranslationUnit()
+ && Reader.SemaObj) {
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
- } else if (DC->isNamespace()) {
- DC->addDecl(New);
+ } else {
+ DeclContext *DC = New->getLexicalDeclContext();
+ if (DC->isNamespace())
+ DC->addDecl(New);
}
}
@@ -1899,7 +1934,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *Loc.F, DeclsCursor, ID, RawLocation, Record,Idx);
+ ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
Decl *D = 0;
switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
@@ -2002,6 +2037,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
+ Record[Idx++]);
+ break;
case DECL_TYPE_ALIAS_TEMPLATE:
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;
@@ -2110,6 +2149,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
}
PendingVisibleUpdates.erase(I);
}
+
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
}
assert(Idx == Record.size());
@@ -2125,9 +2167,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D))
+ if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
InterestingDecls.push_back(D);
-
+
return D;
}
@@ -2152,7 +2194,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *F, Cursor, ID, 0, Record, Idx);
+ ASTDeclReader Reader(*this, *F, ID, 0, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
}
}
@@ -2207,10 +2249,8 @@ namespace {
if (!D)
return;
- if (Deserialized.count(D)) {
- Deserialized.erase(D);
+ if (Deserialized.erase(D))
Chain.push_back(D);
- }
}
void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
@@ -2275,7 +2315,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
}
MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
if (MergedPos != MergedDecls.end())
- SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
+ SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
// Build up the list of redeclarations.
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
@@ -2331,9 +2371,8 @@ namespace {
void add(ObjCCategoryDecl *Cat) {
// Only process each category once.
- if (!Deserialized.count(Cat))
+ if (!Deserialized.erase(Cat))
return;
- Deserialized.erase(Cat);
// Check for duplicate categories.
if (Cat->getDeclName()) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index c5325b5f7837..367f75f55eb0 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -288,7 +288,7 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
}
}
-void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
+void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitStmt(S);
unsigned NumOutputs = Record[Idx++];
unsigned NumInputs = Record[Idx++];
@@ -297,7 +297,6 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setRParenLoc(ReadSourceLocation(Record, Idx));
S->setVolatile(Record[Idx++]);
S->setSimple(Record[Idx++]);
- S->setMSAsm(Record[Idx++]);
S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
@@ -566,6 +565,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
E->setRHS(Reader.ReadSubExpr());
E->setOpcode((BinaryOperator::Opcode)Record[Idx++]);
E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->setFPContractable((bool)Record[Idx++]);
}
void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -627,7 +627,8 @@ void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
- E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
+ if (InitListExpr *SyntForm = cast_or_null<InitListExpr>(Reader.ReadSubStmt()))
+ E->setSyntacticForm(SyntForm);
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
bool isArrayFiller = Record[Idx++];
@@ -1087,6 +1088,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->Operator = (OverloadedOperatorKind)Record[Idx++];
E->Range = Reader.ReadSourceRange(F, Record, Idx);
+ E->setFPContractable((bool)Record[Idx++]);
}
void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -1242,7 +1244,7 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
E->TypeIdParens = ReadSourceRange(Record, Idx);
- E->StartLoc = ReadSourceLocation(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
E->DirectInitRange = ReadSourceRange(Record, Idx);
E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
@@ -1367,8 +1369,6 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
E->RequiresADL = Record[Idx++];
- if (E->RequiresADL)
- E->StdIsAssociatedNamespace = Record[Idx++];
E->Overloaded = Record[Idx++];
E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
}
@@ -1469,6 +1469,16 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
E->NameLoc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ E->NumParameters = Record[Idx++];
+ E->ParamPack = ReadDeclAs<ParmVarDecl>(Record, Idx);
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1);
+ for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
+ Parms[i] = ReadDeclAs<ParmVarDecl>(Record, Idx);
+}
+
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
E->Temporary = Reader.ReadSubExpr();
@@ -1701,8 +1711,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) DeclStmt(Empty);
break;
- case STMT_ASM:
- S = new (Context) AsmStmt(Empty);
+ case STMT_GCCASM:
+ S = new (Context) GCCAsmStmt(Empty);
+ break;
+
+ case STMT_MSASM:
+ S = new (Context) MSAsmStmt(Empty);
break;
case EXPR_PREDEFINED:
@@ -2180,6 +2194,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK:
S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
break;
+
+ case EXPR_FUNCTION_PARM_PACK:
+ S = FunctionParmPackExpr::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
case EXPR_MATERIALIZE_TEMPORARY:
S = new (Context) MaterializeTemporaryExpr(Empty);
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 425d2e32a7b1..a2e8b71123b1 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -25,9 +25,11 @@
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
@@ -35,6 +37,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APFloat.h"
@@ -485,6 +488,8 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
}
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
Writer.AddDeclRef(TL.getArg(i), Record);
@@ -667,7 +672,8 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_BREAK);
RECORD(STMT_RETURN);
RECORD(STMT_DECL);
- RECORD(STMT_ASM);
+ RECORD(STMT_GCCASM);
+ RECORD(STMT_MSASM);
RECORD(EXPR_PREDEFINED);
RECORD(EXPR_DECL_REF);
RECORD(EXPR_INTEGER_LITERAL);
@@ -763,14 +769,27 @@ void ASTWriter::WriteBlockInfoBlock() {
#define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record)
#define RECORD(X) EmitRecordID(X, #X, Stream, Record)
+ // Control Block.
+ BLOCK(CONTROL_BLOCK);
+ RECORD(METADATA);
+ RECORD(IMPORTS);
+ RECORD(LANGUAGE_OPTIONS);
+ RECORD(TARGET_OPTIONS);
+ RECORD(ORIGINAL_FILE);
+ RECORD(ORIGINAL_PCH_DIR);
+ RECORD(INPUT_FILE_OFFSETS);
+ RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(FILE_SYSTEM_OPTIONS);
+ RECORD(HEADER_SEARCH_OPTIONS);
+ RECORD(PREPROCESSOR_OPTIONS);
+
+ BLOCK(INPUT_FILES_BLOCK);
+ RECORD(INPUT_FILE);
+
// AST Top-Level Block.
BLOCK(AST_BLOCK);
- RECORD(ORIGINAL_FILE_NAME);
- RECORD(ORIGINAL_FILE_ID);
RECORD(TYPE_OFFSET);
RECORD(DECL_OFFSET);
- RECORD(LANGUAGE_OPTIONS);
- RECORD(METADATA);
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EXTERNAL_DEFINITIONS);
@@ -784,11 +803,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(PP_COUNTER_VALUE);
RECORD(SOURCE_LOCATION_OFFSETS);
RECORD(SOURCE_LOCATION_PRELOADS);
- RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
- RECORD(VERSION_CONTROL_BRANCH_REVISION);
RECORD(PPD_ENTITIES_OFFSETS);
- RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
RECORD(LOCAL_REDECLARATIONS_MAP);
@@ -803,11 +819,9 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
- RECORD(ORIGINAL_PCH_DIR);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
- RECORD(FILE_SOURCE_LOCATION_OFFSETS);
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
@@ -817,6 +831,8 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(MERGED_DECLARATIONS);
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
+ RECORD(MACRO_OFFSET);
+ RECORD(MACRO_UPDATES);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -972,25 +988,25 @@ adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) {
return Filename + Pos;
}
-/// \brief Write the AST metadata (e.g., i686-apple-darwin9).
-void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
- const std::string &OutputFile) {
+/// \brief Write the control block.
+void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
-
- // Metadata
- const TargetInfo &Target = Context.getTargetInfo();
- BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev();
- MetaAbbrev->Add(BitCodeAbbrevOp(METADATA));
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors
- MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
- unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
-
+ Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
RecordData Record;
+
+ // Metadata
+ BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev();
+ MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors
+ MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev);
Record.push_back(METADATA);
Record.push_back(VERSION_MAJOR);
Record.push_back(VERSION_MINOR);
@@ -998,9 +1014,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(!isysroot.empty());
Record.push_back(ASTHasCompilerErrors);
- const std::string &Triple = Target.getTriple().getTriple();
- Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
+ Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
+ getClangFullRepositoryVersion());
+ // Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
llvm::SmallVector<char, 128> ModulePaths;
@@ -1022,11 +1039,131 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Stream.EmitRecord(IMPORTS, Record);
}
+ // Language options.
+ Record.clear();
+ const LangOptions &LangOpts = Context.getLangOpts();
+#define LANGOPT(Name, Bits, Default, Description) \
+ Record.push_back(LangOpts.Name);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
+#include "clang/Basic/LangOptions.def"
+
+ Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
+ AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
+
+ Record.push_back(LangOpts.CurrentModule.size());
+ Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
+ Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
+
+ // Target options.
+ Record.clear();
+ const TargetInfo &Target = Context.getTargetInfo();
+ const TargetOptions &TargetOpts = Target.getTargetOpts();
+ AddString(TargetOpts.Triple, Record);
+ AddString(TargetOpts.CPU, Record);
+ AddString(TargetOpts.ABI, Record);
+ AddString(TargetOpts.CXXABI, Record);
+ AddString(TargetOpts.LinkerVersion, Record);
+ Record.push_back(TargetOpts.FeaturesAsWritten.size());
+ for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
+ AddString(TargetOpts.FeaturesAsWritten[I], Record);
+ }
+ Record.push_back(TargetOpts.Features.size());
+ for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) {
+ AddString(TargetOpts.Features[I], Record);
+ }
+ Stream.EmitRecord(TARGET_OPTIONS, Record);
+
+ // Diagnostic options.
+ Record.clear();
+ const DiagnosticOptions &DiagOpts
+ = Context.getDiagnostics().getDiagnosticOptions();
+#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
+#include "clang/Basic/DiagnosticOptions.def"
+ Record.push_back(DiagOpts.Warnings.size());
+ for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
+ AddString(DiagOpts.Warnings[I], Record);
+ // Note: we don't serialize the log or serialization file names, because they
+ // are generally transient files and will almost always be overridden.
+ Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
+
+ // File system options.
+ Record.clear();
+ const FileSystemOptions &FSOpts
+ = Context.getSourceManager().getFileManager().getFileSystemOptions();
+ AddString(FSOpts.WorkingDir, Record);
+ Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record);
+
+ // Header search options.
+ Record.clear();
+ const HeaderSearchOptions &HSOpts
+ = PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ AddString(HSOpts.Sysroot, Record);
+
+ // Include entries.
+ Record.push_back(HSOpts.UserEntries.size());
+ for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
+ const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
+ AddString(Entry.Path, Record);
+ Record.push_back(static_cast<unsigned>(Entry.Group));
+ Record.push_back(Entry.IsUserSupplied);
+ Record.push_back(Entry.IsFramework);
+ Record.push_back(Entry.IgnoreSysRoot);
+ Record.push_back(Entry.IsInternal);
+ Record.push_back(Entry.ImplicitExternC);
+ }
+
+ // System header prefixes.
+ Record.push_back(HSOpts.SystemHeaderPrefixes.size());
+ for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
+ AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
+ Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
+ }
+
+ AddString(HSOpts.ResourceDir, Record);
+ AddString(HSOpts.ModuleCachePath, Record);
+ Record.push_back(HSOpts.DisableModuleHash);
+ Record.push_back(HSOpts.UseBuiltinIncludes);
+ Record.push_back(HSOpts.UseStandardSystemIncludes);
+ Record.push_back(HSOpts.UseStandardCXXIncludes);
+ Record.push_back(HSOpts.UseLibcxx);
+ Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record);
+
+ // Preprocessor options.
+ Record.clear();
+ const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts();
+
+ // Macro definitions.
+ Record.push_back(PPOpts.Macros.size());
+ for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
+ AddString(PPOpts.Macros[I].first, Record);
+ Record.push_back(PPOpts.Macros[I].second);
+ }
+
+ // Includes
+ Record.push_back(PPOpts.Includes.size());
+ for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I)
+ AddString(PPOpts.Includes[I], Record);
+
+ // Macro includes
+ Record.push_back(PPOpts.MacroIncludes.size());
+ for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I)
+ AddString(PPOpts.MacroIncludes[I], Record);
+
+ Record.push_back(PPOpts.UsePredefines);
+ AddString(PPOpts.ImplicitPCHInclude, Record);
+ AddString(PPOpts.ImplicitPTHInclude, Record);
+ Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary));
+ Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record);
+
// Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
- FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE_NAME));
+ FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));
+ FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
@@ -1037,13 +1174,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
const char *MainFileNameStr = MainFilePath.c_str();
MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr,
isysroot);
- RecordData Record;
- Record.push_back(ORIGINAL_FILE_NAME);
- Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
-
Record.clear();
+ Record.push_back(ORIGINAL_FILE);
Record.push_back(SM.getMainFileID().getOpaqueValue());
- Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
// Original PCH directory
@@ -1063,32 +1197,86 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
- // Repository branch/version information.
- BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
- RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION));
- RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
- unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev);
- Record.clear();
- Record.push_back(VERSION_CONTROL_BRANCH_REVISION);
- Stream.EmitRecordWithBlob(RepoAbbrevCode, Record,
- getClangFullRepositoryVersion());
+ WriteInputFiles(Context.SourceMgr, isysroot);
+ Stream.ExitBlock();
}
-/// \brief Write the LangOptions structure.
-void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+ using namespace llvm;
+ Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
-#define LANGOPT(Name, Bits, Default, Description) \
- Record.push_back(LangOpts.Name);
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
-#include "clang/Basic/LangOptions.def"
+
+ // Create input-file abbreviation.
+ BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
+ IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
+
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
+ // Get this source location entry.
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
+ assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc);
- Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
- AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
+ // We only care about file entries that were not overridden.
+ if (!SLoc->isFile())
+ continue;
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (!Cache->OrigEntry)
+ continue;
+
+ // Record this entry's offset.
+ InputFileOffsets.push_back(Stream.GetCurrentBitNo());
+ InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
+
+ Record.clear();
+ Record.push_back(INPUT_FILE);
+ Record.push_back(InputFileOffsets.size());
+
+ // Emit size/modification time for this file.
+ Record.push_back(Cache->OrigEntry->getSize());
+ Record.push_back(Cache->OrigEntry->getModificationTime());
+
+ // Whether this file was overridden.
+ Record.push_back(Cache->BufferOverridden);
+
+ // Turn the file name into an absolute path, if it isn't already.
+ const char *Filename = Cache->OrigEntry->getName();
+ SmallString<128> FilePath(Filename);
+
+ // Ask the file manager to fixup the relative path for us. This will
+ // honor the working directory.
+ SourceMgr.getFileManager().FixupRelativePath(FilePath);
+
+ // FIXME: This call to make_absolute shouldn't be necessary, the
+ // call to FixupRelativePath should always return an absolute path.
+ llvm::sys::fs::make_absolute(FilePath);
+ Filename = FilePath.c_str();
+
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+
+ Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
+ }
- Record.push_back(LangOpts.CurrentModule.size());
- Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
- Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
+ Stream.ExitBlock();
+
+ // Create input file offsets abbreviation.
+ BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
+ unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
+
+ // Write input file offsets.
+ Record.clear();
+ Record.push_back(INPUT_FILE_OFFSETS);
+ Record.push_back(InputFileOffsets.size());
+ Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
@@ -1139,46 +1327,6 @@ public:
};
} // end anonymous namespace
-/// \brief Write the stat() system call cache to the AST file.
-void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
- // Build the on-disk hash table containing information about every
- // stat() call.
- OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator;
- unsigned NumStatEntries = 0;
- for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
- StatEnd = StatCalls.end();
- Stat != StatEnd; ++Stat, ++NumStatEntries) {
- StringRef Filename = Stat->first();
- Generator.insert(Filename.data(), Stat->second);
- }
-
- // Create the on-disk hash table in a buffer.
- SmallString<4096> StatCacheData;
- uint32_t BucketOffset;
- {
- llvm::raw_svector_ostream Out(StatCacheData);
- // Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
- BucketOffset = Generator.Emit(Out);
- }
-
- // Create a blob abbreviation
- using namespace llvm;
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
-
- // Write the stat cache
- RecordData Record;
- Record.push_back(STAT_CACHE);
- Record.push_back(BucketOffset);
- Record.push_back(NumStatEntries);
- Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str());
-}
-
//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
@@ -1194,13 +1342,10 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// FileEntry fields.
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@@ -1329,8 +1474,6 @@ namespace {
/// \brief Write the header search block for the list of files that
///
/// \param HS The header search structure to save.
-///
-/// \param Chain Whether we're creating a chained AST file.
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
@@ -1427,15 +1570,14 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
- // Write out the offsets of only source location file entries.
- // We will go through them in ASTReader::validateFileEntries().
- std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
+ FileID FID = FileID::get(I);
+ assert(&SourceMgr.getSLocEntry(FID) == SLoc);
// Record the offset of this source-location entry.
SLocEntryOffsets.push_back(Stream.GetCurrentBitNo());
@@ -1446,7 +1588,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
- SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
} else
Code = SM_SLOC_BUFFER_ENTRY;
} else
@@ -1467,16 +1608,13 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
assert(Content->OrigEntry == Content->ContentsEntry &&
"Writing to AST an overridden file is not supported");
- // The source location entry is a file. The blob associated
- // with this entry is the file name.
+ // The source location entry is a file. Emit input file ID.
+ assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
+ Record.push_back(InputFileIDs[Content->OrigEntry]);
- // Emit size/modification time for this file.
- Record.push_back(Content->OrigEntry->getSize());
- Record.push_back(Content->OrigEntry->getModificationTime());
- Record.push_back(Content->BufferOverridden);
Record.push_back(File.NumCreatedFIDs);
- FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc);
+ FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
if (FDI != FileDeclIDs.end()) {
Record.push_back(FDI->second->FirstDeclIndex);
Record.push_back(FDI->second->DeclIDs.size());
@@ -1485,21 +1623,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(0);
}
- // Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Content->OrigEntry->getName();
- SmallString<128> FilePath(Filename);
-
- // Ask the file manager to fixup the relative path for us. This will
- // honor the working directory.
- SourceMgr.getFileManager().FixupRelativePath(FilePath);
-
- // FIXME: This call to make_absolute shouldn't be necessary, the
- // call to FixupRelativePath should always return an absolute path.
- llvm::sys::fs::make_absolute(FilePath);
- Filename = FilePath.c_str();
-
- Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
- Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
+ Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record);
if (Content->BufferOverridden) {
Record.clear();
@@ -1570,18 +1694,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
- Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
- unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
-
- Record.clear();
- Record.push_back(FILE_SOURCE_LOCATION_OFFSETS);
- Record.push_back(SLocFileEntryOffsets.size());
- Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record,
- data(SLocFileEntryOffsets));
-
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
@@ -1675,102 +1787,129 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
MacrosToEmit;
llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
- for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
+ for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
E = PP.macro_end(Chain == 0);
I != E; ++I) {
- const IdentifierInfo *Name = I->first;
if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(Name);
+ MacroDefinitionsSeen.insert(I->first);
MacrosToEmit.push_back(std::make_pair(I->first, I->second));
}
}
-
+
// Sort the set of macro definitions that need to be serialized by the
// name of the macro, to provide a stable ordering.
- llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
+ llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
&compareMacroDefinitions);
-
- // Resolve any identifiers that defined macros at the time they were
- // deserialized, adding them to the list of macros to emit (if appropriate).
- for (unsigned I = 0, N = DeserializedMacroNames.size(); I != N; ++I) {
- IdentifierInfo *Name
- = const_cast<IdentifierInfo *>(DeserializedMacroNames[I]);
- if (Name->hasMacroDefinition() && MacroDefinitionsSeen.insert(Name))
- MacrosToEmit.push_back(std::make_pair(Name, PP.getMacroInfo(Name)));
- }
-
+
+ /// \brief Offsets of each of the macros into the bitstream, indexed by
+ /// the local macro ID
+ ///
+ /// For each identifier that is associated with a macro, this map
+ /// provides the offset into the bitstream where that macro is
+ /// defined.
+ std::vector<uint32_t> MacroOffsets;
+
for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
const IdentifierInfo *Name = MacrosToEmit[I].first;
- MacroInfo *MI = MacrosToEmit[I].second;
- if (!MI)
- continue;
-
- // Don't emit builtin macros like __LINE__ to the AST file unless they have
- // been redefined by the header (in which case they are not isBuiltinMacro).
- // Also skip macros from a AST file if we're chaining.
-
- // FIXME: There is a (probably minor) optimization we could do here, if
- // the macro comes from the original PCH but the identifier comes from a
- // chained PCH, by storing the offset into the original PCH rather than
- // writing the macro definition a second time.
- if (MI->isBuiltinMacro() ||
- (Chain &&
- Name->isFromAST() && !Name->hasChangedSinceDeserialization() &&
- MI->isFromAST() && !MI->hasChangedAfterLoad()))
- continue;
- AddIdentifierRef(Name, Record);
- MacroOffsets[Name] = Stream.GetCurrentBitNo();
- Record.push_back(MI->getDefinitionLoc().getRawEncoding());
- Record.push_back(MI->isUsed());
- Record.push_back(MI->isPublic());
- AddSourceLocation(MI->getVisibilityLocation(), Record);
- unsigned Code;
- if (MI->isObjectLike()) {
- Code = PP_MACRO_OBJECT_LIKE;
- } else {
- Code = PP_MACRO_FUNCTION_LIKE;
+ for (MacroInfo *MI = MacrosToEmit[I].second; MI;
+ MI = MI->getPreviousDefinition()) {
+ MacroID ID = getMacroRef(MI);
+ if (!ID)
+ continue;
- Record.push_back(MI->isC99Varargs());
- Record.push_back(MI->isGNUVarargs());
- Record.push_back(MI->getNumArgs());
- for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
- I != E; ++I)
- AddIdentifierRef(*I, Record);
- }
+ // Skip macros from a AST file if we're chaining.
+ if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
+ continue;
- // If we have a detailed preprocessing record, record the macro definition
- // ID that corresponds to this macro.
- if (PPRec)
- Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
+ if (ID < FirstMacroID) {
+ // This will have been dealt with via an update record.
+ assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
+ continue;
+ }
- Stream.EmitRecord(Code, Record);
- Record.clear();
+ // Record the local offset of this macro.
+ unsigned Index = ID - FirstMacroID;
+ if (Index == MacroOffsets.size())
+ MacroOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > MacroOffsets.size())
+ MacroOffsets.resize(Index + 1);
- // Emit the tokens array.
- for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
- // Note that we know that the preprocessor does not have any annotation
- // tokens in it because they are created by the parser, and thus can't be
- // in a macro definition.
- const Token &Tok = MI->getReplacementToken(TokNo);
-
- Record.push_back(Tok.getLocation().getRawEncoding());
- Record.push_back(Tok.getLength());
-
- // FIXME: When reading literal tokens, reconstruct the literal pointer if
- // it is needed.
- AddIdentifierRef(Tok.getIdentifierInfo(), Record);
- // FIXME: Should translate token kind to a stable encoding.
- Record.push_back(Tok.getKind());
- // FIXME: Should translate token flags to a stable encoding.
- Record.push_back(Tok.getFlags());
-
- Stream.EmitRecord(PP_TOKEN, Record);
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
+
+ AddIdentifierRef(Name, Record);
+ addMacroRef(MI, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
+ AddSourceLocation(MI->getDefinitionLoc(), Record);
+ AddSourceLocation(MI->getUndefLoc(), Record);
+ Record.push_back(MI->isUsed());
+ Record.push_back(MI->isPublic());
+ AddSourceLocation(MI->getVisibilityLocation(), Record);
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = PP_MACRO_FUNCTION_LIKE;
+
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
+
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
+
+ Stream.EmitRecord(Code, Record);
Record.clear();
+
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't
+ // be in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+
+ Record.push_back(Tok.getLocation().getRawEncoding());
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer
+ // if it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+ // FIXME: Should translate token kind to a stable encoding.
+ Record.push_back(Tok.getKind());
+ // FIXME: Should translate token flags to a stable encoding.
+ Record.push_back(Tok.getFlags());
+
+ Stream.EmitRecord(PP_TOKEN, Record);
+ Record.clear();
+ }
+ ++NumMacros;
}
- ++NumMacros;
}
Stream.ExitBlock();
+
+ // Write the offsets table for macro IDs.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+
+ unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+ Record.clear();
+ Record.push_back(MACRO_OFFSET);
+ Record.push_back(MacroOffsets.size());
+ Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS);
+ Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record,
+ data(MacroOffsets));
}
void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
@@ -1794,6 +1933,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
InclusionAbbrev = Stream.EmitAbbrev(Abbrev);
}
@@ -1836,6 +1976,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
Record.push_back(static_cast<unsigned>(ID->getKind()));
+ Record.push_back(ID->importedModule());
SmallString<64> Buffer;
Buffer += ID->getFileName();
// Check that the FileEntry is not null because it was not resolved and
@@ -1935,6 +2076,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -1944,6 +2090,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2005,6 +2156,19 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
Mod->Headers[I]->getName());
}
+ // Emit the excluded headers.
+ for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_EXCLUDED_HEADER);
+ Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
+ Mod->ExcludedHeaders[I]->getName());
+ }
+ for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_TOPHEADER);
+ Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
+ Mod->TopHeaders[I]->getName());
+ }
// Emit the imports.
if (!Mod->Imports.empty()) {
@@ -2067,24 +2231,35 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
}
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
+ // FIXME: Make it work properly with modules.
+ llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
+ DiagStateIDMap;
+ unsigned CurrID = 0;
+ DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one.
RecordData Record;
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
I != E; ++I) {
- const DiagnosticsEngine::DiagStatePoint &point = *I;
+ const DiagnosticsEngine::DiagStatePoint &point = *I;
if (point.Loc.isInvalid())
continue;
Record.push_back(point.Loc.getRawEncoding());
- for (DiagnosticsEngine::DiagState::const_iterator
- I = point.State->begin(), E = point.State->end(); I != E; ++I) {
- if (I->second.isPragma()) {
- Record.push_back(I->first);
- Record.push_back(I->second.getMapping());
+ unsigned &DiagStateID = DiagStateIDMap[point.State];
+ Record.push_back(DiagStateID);
+
+ if (DiagStateID == 0) {
+ DiagStateID = ++CurrID;
+ for (DiagnosticsEngine::DiagState::const_iterator
+ I = point.State->begin(), E = point.State->end(); I != E; ++I) {
+ if (I->second.isPragma()) {
+ Record.push_back(I->first);
+ Record.push_back(I->second.getMapping());
+ }
}
+ Record.push_back(-1); // mark the end of the diag/map pairs for this
+ // location.
}
- Record.push_back(-1); // mark the end of the diag/map pairs for this
- // location.
}
if (!Record.empty())
@@ -2238,9 +2413,11 @@ void ASTWriter::WriteFileDeclIDsMap() {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
Record.push_back(FILE_SORTED_DECLS);
+ Record.push_back(FileSortedIDs.size());
Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs));
}
@@ -2495,17 +2672,17 @@ class ASTIdentifierTableTrait {
II->getFETokenInfo<void>())
return true;
- return hasMacroDefinition(II, Macro);
+ return hadMacroDefinition(II, Macro);
}
-
- bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
- if (!II->hasMacroDefinition())
+
+ bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ if (!II->hadMacroDefinition())
return false;
-
- if (Macro || (Macro = PP.getMacroInfo(II)))
+
+ if (Macro || (Macro = PP.getMacroInfoHistory(II)))
return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
-
- return false;
+
+ return false;
}
public:
@@ -2529,10 +2706,17 @@ public:
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
MacroInfo *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
- DataLen += 2; // 2 bytes for builtin ID, flags
- if (hasMacroDefinition(II, Macro))
- DataLen += 8;
-
+ DataLen += 2; // 2 bytes for builtin ID
+ DataLen += 2; // 2 bytes for flags
+ if (hadMacroDefinition(II, Macro)) {
+ for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
+ if (Writer.getMacroRef(M) != 0)
+ DataLen += 4;
+ }
+
+ DataLen += 4;
+ }
+
for (IdentifierResolver::iterator D = IdResolver.begin(II),
DEnd = IdResolver.end();
D != DEnd; ++D)
@@ -2563,23 +2747,28 @@ public:
}
clang::io::Emit32(Out, (ID << 1) | 0x01);
- uint32_t Bits = 0;
- bool HasMacroDefinition = hasMacroDefinition(II, Macro);
- Bits = (uint32_t)II->getObjCOrBuiltinID();
- assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
- Bits = (Bits << 1) | unsigned(HasMacroDefinition);
+ uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID();
+ assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
+ clang::io::Emit16(Out, Bits);
+ Bits = 0;
+ bool HadMacroDefinition = hadMacroDefinition(II, Macro);
+ Bits = (Bits << 1) | unsigned(HadMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
clang::io::Emit16(Out, Bits);
- if (HasMacroDefinition) {
- clang::io::Emit32(Out, Writer.getMacroOffset(II));
- clang::io::Emit32(Out,
- Writer.inferSubmoduleIDFromLocation(Macro->getDefinitionLoc()));
+ if (HadMacroDefinition) {
+ // Write all of the macro IDs associated with this identifier.
+ for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
+ if (MacroID ID = Writer.getMacroRef(M))
+ clang::io::Emit32(Out, ID);
+ }
+
+ clang::io::Emit32(Out, 0);
}
-
+
// Emit the declaration IDs in reverse order, because the
// IdentifierResolver provides the declarations as they would be
// visible (e.g., the function "stat" would come before the struct
@@ -2756,30 +2945,32 @@ public:
void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
using namespace clang::io;
- assert(Name.getNameKind() < 0x100 && "Invalid name kind ?");
Emit8(Out, Name.getNameKind());
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
- break;
+ return;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
- break;
+ return;
case DeclarationName::CXXOperatorName:
- assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?");
+ assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS &&
+ "Invalid operator?");
Emit8(Out, Name.getCXXOverloadedOperator());
- break;
+ return;
case DeclarationName::CXXLiteralOperatorName:
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
- break;
+ return;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
- break;
+ return;
}
+
+ llvm_unreachable("Invalid name kind?");
}
void EmitData(raw_ostream& Out, key_type_ref,
@@ -3147,7 +3338,8 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
ASTHasCompilerErrors(false),
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
- FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID),
FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
NextSubmoduleID(FirstSubmoduleID),
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
@@ -3171,7 +3363,7 @@ ASTWriter::~ASTWriter() {
delete I->second;
}
-void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteAST(Sema &SemaRef,
const std::string &OutputFile,
Module *WritingModule, StringRef isysroot,
bool hasErrors) {
@@ -3190,7 +3382,7 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Context = &SemaRef.Context;
PP = &SemaRef.PP;
this->WritingModule = WritingModule;
- WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
+ WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
Context = 0;
PP = 0;
this->WritingModule = 0;
@@ -3207,7 +3399,7 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
}
}
-void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+void ASTWriter::WriteASTCore(Sema &SemaRef,
StringRef isysroot,
const std::string &OutputFile,
Module *WritingModule) {
@@ -3357,14 +3549,13 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (!I->second)
AddDeclRef(I->first, KnownNamespaces);
}
-
+
+ // Write the control block
+ WriteControlBlock(PP, Context, isysroot, OutputFile);
+
// Write the remaining AST contents.
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
- WriteMetadata(Context, isysroot, OutputFile);
- WriteLanguageOptions(Context.getLangOpts());
- if (StatCalls && isysroot.empty())
- WriteStatCache(*StatCalls);
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
@@ -3482,6 +3673,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Out.write(FileName.data(), FileName.size());
io::Emit32(Out, (*M)->SLocEntryBaseOffset);
io::Emit32(Out, (*M)->BaseIdentifierID);
+ io::Emit32(Out, (*M)->BaseMacroID);
io::Emit32(Out, (*M)->BasePreprocessedEntityID);
io::Emit32(Out, (*M)->BaseSubmoduleID);
io::Emit32(Out, (*M)->BaseSelectorID);
@@ -3595,7 +3787,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
}
}
-
+
+ WriteMacroUpdates();
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
WriteMergedDecls();
@@ -3612,6 +3805,21 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Stream.ExitBlock();
}
+void ASTWriter::WriteMacroUpdates() {
+ if (MacroUpdates.empty())
+ return;
+
+ RecordData Record;
+ for (MacroUpdatesMap::iterator I = MacroUpdates.begin(),
+ E = MacroUpdates.end();
+ I != E; ++I) {
+ addMacroRef(I->first, Record);
+ AddSourceLocation(I->second.UndefLoc, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc));
+ }
+ Stream.EmitRecord(MACRO_UPDATES, Record);
+}
+
/// \brief Go through the declaration update blocks and resolve declaration
/// pointers into declaration IDs.
void ASTWriter::ResolveDeclUpdatesBlocks() {
@@ -3707,6 +3915,10 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor
Record.push_back(getIdentifierRef(II));
}
+void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) {
+ Record.push_back(getMacroRef(MI));
+}
+
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
if (II == 0)
return 0;
@@ -3717,6 +3929,19 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
+MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
+ // Don't emit builtin macros like __LINE__ to the AST file unless they
+ // have been redefined by the header (in which case they are not
+ // isBuiltinMacro).
+ if (MI == 0 || MI->isBuiltinMacro())
+ return 0;
+
+ MacroID &ID = MacroIDs[MI];
+ if (ID == 0)
+ ID = NextMacroID++;
+ return ID;
+}
+
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3774,7 +3999,9 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
case TemplateArgument::Pack:
+ // FIXME: Is this right?
break;
}
}
@@ -3931,10 +4158,9 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
if (FID.isInvalid())
return;
- const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID);
- assert(Entry->isFile());
+ assert(SM.getSLocEntry(FID).isFile());
- DeclIDInFileInfo *&Info = FileDeclIDs[Entry];
+ DeclIDInFileInfo *&Info = FileDeclIDs[FID];
if (!Info)
Info = new DeclIDInFileInfo();
@@ -4191,6 +4417,10 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::Declaration:
AddDeclRef(Arg.getAsDecl(), Record);
+ Record.push_back(Arg.isDeclForReferenceParam());
+ break;
+ case TemplateArgument::NullPtr:
+ AddTypeRef(Arg.getNullPtrType(), Record);
break;
case TemplateArgument::Integral:
AddAPSInt(Arg.getAsIntegral(), Record);
@@ -4403,6 +4633,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Lambda.NumExplicitCaptures);
Record.push_back(Lambda.ManglingNumber);
AddDeclRef(Lambda.ContextDecl, Record);
+ AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
@@ -4423,6 +4654,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
assert(FirstDeclID == NextDeclID &&
FirstTypeID == NextTypeID &&
FirstIdentID == NextIdentID &&
+ FirstMacroID == NextMacroID &&
FirstSubmoduleID == NextSubmoduleID &&
FirstSelectorID == NextSelectorID &&
"Setting chain after writing has started.");
@@ -4432,19 +4664,23 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
+ FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros();
FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
NextDeclID = FirstDeclID;
NextTypeID = FirstTypeID;
NextIdentID = FirstIdentID;
+ NextMacroID = FirstMacroID;
NextSelectorID = FirstSelectorID;
NextSubmoduleID = FirstSubmoduleID;
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
IdentifierIDs[II] = ID;
- if (II->hasMacroDefinition())
- DeserializedMacroNames.push_back(II);
+}
+
+void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
+ MacroIDs[MI] = ID;
}
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
@@ -4468,15 +4704,15 @@ void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinitions[MD] = ID;
}
-void ASTWriter::MacroVisible(IdentifierInfo *II) {
- DeserializedMacroNames.push_back(II);
-}
-
void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
SubmoduleIDs[Mod] = ID;
}
+void ASTWriter::UndefinedMacro(MacroInfo *MI) {
+ MacroUpdates[MI].UndefLoc = MI->getUndefLoc();
+}
+
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
assert(D->isCompleteDefinition());
assert(!WritingAST && "Already writing the AST!");
@@ -4490,6 +4726,7 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
}
}
}
+
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
assert(!WritingAST && "Already writing the AST!");
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 602943b9ba58..74865657637c 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -416,7 +416,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
}
Record.push_back(D->isInstanceMethod());
Record.push_back(D->isVariadic());
- Record.push_back(D->isSynthesized());
+ Record.push_back(D->isPropertyAccessor());
Record.push_back(D->isDefined());
Record.push_back(D->IsOverriding);
@@ -606,6 +606,8 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Writer.AddDeclRef(D->getSuperClass(), Record);
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
+ Record.push_back(D->hasNonZeroConstructors());
+ Record.push_back(D->hasDestructors());
Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
Record);
Code = serialization::DECL_OBJC_IMPLEMENTATION;
@@ -675,6 +677,8 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
+ Record.push_back(D->isConstexpr());
+
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
Writer.AddStmt(D->getInit());
@@ -705,6 +709,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
D->getInitStyle() == VarDecl::CInit &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
+ !D->isConstexpr() &&
!SpecInfo)
AbbrevToUse = Writer.getDeclVarAbbrev();
@@ -945,11 +950,16 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
- Record.push_back(D->size_overridden_methods());
- for (CXXMethodDecl::method_iterator
- I = D->begin_overridden_methods(), E = D->end_overridden_methods();
- I != E; ++I)
- Writer.AddDeclRef(*I, Record);
+ if (D->isCanonicalDecl()) {
+ Record.push_back(D->size_overridden_methods());
+ for (CXXMethodDecl::method_iterator
+ I = D->begin_overridden_methods(), E = D->end_overridden_methods();
+ I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ } else {
+ // We only need to record overridden methods once for the canonical decl.
+ Record.push_back(0);
+ }
Code = serialization::DECL_CXX_METHOD;
}
@@ -981,6 +991,7 @@ void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
void ASTDeclWriter::VisitImportDecl(ImportDecl *D) {
VisitDecl(D);
+ Record.push_back(Writer.getSubmoduleID(D->getImportedModule()));
ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs();
Record.push_back(!IdentifierLocs.empty());
if (IdentifierLocs.empty()) {
@@ -1073,7 +1084,7 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Writer.AddDeclRef(&*I, Record);
}
- // InjectedClassNameType is computed, no need to write it.
+ Writer.AddTypeRef(D->getCommonPtr()->InjectedClassNameType, Record);
}
Code = serialization::DECL_CLASS_TEMPLATE;
}
@@ -1103,6 +1114,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
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.
@@ -1172,7 +1184,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
- // so that it's easier for
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTypes());
@@ -1201,15 +1214,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
}
void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ // For an expanded parameter pack, record the number of expansion types here
+ // so that it's easier for deserialization to allocate the right amount of
+ // memory.
+ if (D->isExpandedParameterPack())
+ Record.push_back(D->getNumExpansionTemplateParameters());
+
VisitTemplateDecl(D);
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
- // Rest of TemplateTemplateParmDecl.
- Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
- Record.push_back(D->defaultArgumentWasInherited());
- Record.push_back(D->isParameterPack());
- Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+
+ if (D->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
+ I != N; ++I)
+ Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I),
+ Record);
+ Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
+ } else {
+ // Rest of TemplateTemplateParmDecl.
+ Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
+ Record.push_back(D->defaultArgumentWasInherited());
+ Record.push_back(D->isParameterPack());
+ Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
+ }
}
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@@ -1462,6 +1490,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
+ Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
@@ -1540,6 +1569,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
+ Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
@@ -1603,7 +1633,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
Abv = new BitCodeAbbrev();
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index f63388fa2fd1..7e8ce42d7caf 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -218,7 +218,7 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) {
Code = serialization::STMT_DECL;
}
-void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
+void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitStmt(S);
Record.push_back(S->getNumOutputs());
Record.push_back(S->getNumInputs());
@@ -227,7 +227,6 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Record.push_back(S->isVolatile());
Record.push_back(S->isSimple());
- Record.push_back(S->isMSAsm());
Writer.AddStmt(S->getAsmString());
// Outputs
@@ -246,14 +245,16 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
// Clobbers
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
- Writer.AddStmt(S->getClobber(I));
+ Writer.AddStmt(S->getClobberStringLiteral(I));
- Code = serialization::STMT_ASM;
+ Code = serialization::STMT_GCCASM;
}
void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
// FIXME: Statement writer not yet implemented for MS style inline asm.
VisitStmt(S);
+
+ Code = serialization::STMT_MSASM;
}
void ASTStmtWriter::VisitExpr(Expr *E) {
@@ -535,6 +536,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
Writer.AddStmt(E->getRHS());
Record.push_back(E->getOpcode()); // FIXME: stable encoding
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Record.push_back(E->isFPContractable());
Code = serialization::EXPR_BINARY_OPERATOR;
}
@@ -604,6 +606,8 @@ void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
+ // NOTE: only add the (possibly null) syntactic form.
+ // No need to serialize the isSemanticForm flag and the semantic form.
Writer.AddStmt(E->getSyntacticForm());
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
@@ -1054,6 +1058,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
Writer.AddSourceRange(E->Range, Record);
+ Record.push_back(E->isFPContractable());
Code = serialization::EXPR_CXX_OPERATOR_CALL;
}
@@ -1233,7 +1238,7 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
Writer.AddDeclRef(E->getOperatorDelete(), Record);
Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record);
Writer.AddSourceRange(E->getTypeIdParens(), Record);
- Writer.AddSourceLocation(E->getStartLoc(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
Writer.AddSourceRange(E->getDirectInitRange(), Record);
for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
I != e; ++I)
@@ -1382,8 +1387,6 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
Record.push_back(E->requiresADL());
- if (E->requiresADL())
- Record.push_back(E->isStdAssociatedNamespace());
Record.push_back(E->isOverloaded());
Writer.AddDeclRef(E->getNamingClass(), Record);
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
@@ -1480,6 +1483,17 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
}
+void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumExpansions());
+ Writer.AddDeclRef(E->getParameterPack(), Record);
+ Writer.AddSourceLocation(E->getParameterPackLocation(), Record);
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = serialization::EXPR_FUNCTION_PARM_PACK;
+}
+
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->Temporary);
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 02aed103f1bf..870d65489584 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -32,11 +31,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
raw_ostream *OS)
: PP(PP), OutputFile(OutputFile), Module(Module),
isysroot(isysroot.str()), Out(OS),
- SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
- // Install a stat() listener to keep track of all of the stat()
- // calls.
- StatCalls = new MemorizeStatCalls();
- PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false);
+ SemaPtr(0), Stream(Buffer), Writer(Stream) {
}
PCHGenerator::~PCHGenerator() {
@@ -48,7 +43,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, Module, isysroot);
+ Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
@@ -60,6 +55,10 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
Buffer.clear();
}
+PPMutationListener *PCHGenerator::GetPPMutationListener() {
+ return &Writer;
+}
+
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
return &Writer;
}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index ff241d3d4105..5e42ab4211fa 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -21,12 +21,15 @@ using namespace serialization;
using namespace reader;
ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0),
+ : Kind(Kind), File(0), DirectlyImported(false),
+ Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
- SLocFileOffsets(0), LocalNumIdentifiers(0),
+ LocalNumIdentifiers(0),
IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0),
- IdentifierLookupTable(0), BasePreprocessedEntityID(0),
+ IdentifierLookupTable(0),
+ LocalNumMacros(0), MacroOffsets(0),
+ BasePreprocessedEntityID(0),
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
@@ -35,9 +38,10 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
+ FileSortedDecls(0), NumFileSortedDecls(0),
+ RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0),
- LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
+ LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0)
{}
ModuleFile::~ModuleFile() {
@@ -89,6 +93,10 @@ void ModuleFile::dump() {
<< " Number of identifiers: " << LocalNumIdentifiers << '\n';
dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap);
+ llvm::errs() << " Base macro ID: " << BaseMacroID << '\n'
+ << " Number of macros: " << LocalNumMacros << '\n';
+ dumpLocalRemap("Macro ID local -> global map", MacroRemap);
+
llvm::errs() << " Base submodule ID: " << BaseSubmoduleID << '\n'
<< " Number of submodules: " << LocalNumSubmodules << '\n';
dumpLocalRemap("Submodule ID local -> global map", SubmoduleRemap);
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index ab364b7ebd2c..efe442101bb6 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -50,6 +50,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Allocate a new module.
ModuleFile *New = new ModuleFile(Type, Generation);
New->FileName = FileName.str();
+ New->File = Entry;
Chain.push_back(New);
NewModule = true;
ModuleEntry = New;
@@ -87,6 +88,45 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return std::make_pair(ModuleEntry, NewModule);
}
+namespace {
+ /// \brief Predicate that checks whether a module file occurs within
+ /// the given set.
+ class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
+ llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
+
+ public:
+ IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
+ : Removed(Removed) { }
+
+ bool operator()(ModuleFile *MF) const {
+ return Removed.count(MF);
+ }
+ };
+}
+
+void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
+ if (first == last)
+ return;
+
+ // Collect the set of module file pointers that we'll be removing.
+ llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
+
+ // Remove any references to the now-destroyed modules.
+ IsInModuleFileSet checkInSet(victimSet);
+ for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
+ Chain[i]->ImportedBy.remove_if(checkInSet);
+ }
+
+ // Delete the modules and erase them from the various structures.
+ for (ModuleIterator victim = first; victim != last; ++victim) {
+ Modules.erase((*victim)->File);
+ delete *victim;
+ }
+
+ // Remove the modules from the chain.
+ Chain.erase(first, last);
+}
+
void ModuleManager::addInMemoryBuffer(StringRef FileName,
llvm::MemoryBuffer *Buffer) {
@@ -95,7 +135,7 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName,
InMemoryBuffers[Entry] = Buffer;
}
-ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
+ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { }
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
deleted file mode 100644
index 84ea8c709dd9..000000000000
--- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines AdjustedReturnValueChecker, a simple check to see if the
-// return value of a function call is different than the one the caller thinks
-// it is.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AdjustedReturnValueChecker :
- public Checker< check::PostStmt<CallExpr> > {
-public:
- void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
-};
-}
-
-void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
- CheckerContext &C) const {
-
- // Get the result type of the call.
- QualType expectedResultTy = CE->getType();
-
- // Fetch the signature of the called function.
- ProgramStateRef state = C.getState();
- const LocationContext *LCtx = C.getLocationContext();
-
- SVal V = state->getSVal(CE, LCtx);
-
- if (V.isUnknown())
- return;
-
- // Casting to void? Discard the value.
- if (expectedResultTy->isVoidType()) {
- C.addTransition(state->BindExpr(CE, LCtx, UnknownVal()));
- return;
- }
-
- const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion();
- if (!callee)
- return;
-
- QualType actualResultTy;
-
- if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
- const FunctionDecl *FD = FT->getDecl();
- actualResultTy = FD->getResultType();
- }
- else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
- const BlockTextRegion *BR = BD->getCodeRegion();
- const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
- actualResultTy = FT->getResultType();
- }
-
- // Can this happen?
- if (actualResultTy.isNull())
- return;
-
- // For now, ignore references.
- if (actualResultTy->getAs<ReferenceType>())
- return;
-
-
- // Are they the same?
- if (expectedResultTy != actualResultTy) {
- // FIXME: Do more checking and actual emit an error. At least performing
- // the cast avoids some assertion failures elsewhere.
- SValBuilder &svalBuilder = C.getSValBuilder();
- V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
- C.addTransition(state->BindExpr(CE, LCtx, V));
- }
-}
-
-void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
- mgr.registerChecker<AdjustedReturnValueChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index b2ad18472e06..535d8eede46a 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -78,7 +78,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
new BugReport(*BT, BT->getDescription(), N);
report->addRange(LoadS->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index c6efe941ec21..457c870943dd 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -208,7 +208,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
break;
}
- checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode));
+ checkerContext.emitReport(new BugReport(*BT, os.str(), errorNode));
}
void RegionRawOffsetV2::dump() const {
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index c582cfc4a81b..81e8dd885a34 100644
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
@@ -105,9 +105,9 @@ void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
// Highlight the range of the argument that was null.
R->addRange(Call.getArgSourceRange(idx));
if (const Expr *ArgE = Call.getArgExpr(idx))
- bugreporter::addTrackNullOrUndefValueVisitor(errorNode, ArgE, R);
+ bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R);
// Emit the bug report.
- C.EmitReport(R);
+ C.emitReport(R);
}
// Always return. Either we cached out or we just emitted an error.
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 955e79ae4661..eba534e08f6b 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -117,7 +117,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(msg.getArgSourceRange(Arg));
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -358,20 +358,20 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
//===----------------------------------------------------------------------===//
-// CFRetain/CFRelease checking for null arguments.
+// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
//===----------------------------------------------------------------------===//
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable OwningPtr<APIMisuse> BT;
- mutable IdentifierInfo *Retain, *Release;
+ mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
public:
- CFRetainReleaseChecker(): Retain(0), Release(0) {}
+ CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
@@ -392,12 +392,14 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
ASTContext &Ctx = C.getASTContext();
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
- BT.reset(new APIMisuse("null passed to CFRetain/CFRelease"));
+ MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
+ BT.reset(
+ new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
}
- // Check if we called CFRetain/CFRelease.
+ // Check if we called CFRetain/CFRelease/CFMakeCollectable.
const IdentifierInfo *FuncII = FD->getIdentifier();
- if (!(FuncII == Retain || FuncII == Release))
+ if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
return;
// FIXME: The rest of this just checks that the argument is non-null.
@@ -426,14 +428,20 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
if (!N)
return;
- const char *description = (FuncII == Retain)
- ? "Null pointer argument in call to CFRetain"
- : "Null pointer argument in call to CFRelease";
+ const char *description;
+ if (FuncII == Retain)
+ description = "Null pointer argument in call to CFRetain";
+ else if (FuncII == Release)
+ description = "Null pointer argument in call to CFRelease";
+ else if (FuncII == MakeCollectable)
+ description = "Null pointer argument in call to CFMakeCollectable";
+ else
+ llvm_unreachable("impossible case");
BugReport *report = new BugReport(*BT, description, N);
report->addRange(Arg->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, Arg, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, Arg, *report);
+ C.emitReport(report);
return;
}
@@ -491,7 +499,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(msg.getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
@@ -644,7 +652,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -716,6 +724,73 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
C.addTransition(State);
}
+namespace {
+/// \class ObjCNonNilReturnValueChecker
+/// \brief The checker restricts the return values of APIs known to
+/// never (or almost never) return 'nil'.
+class ObjCNonNilReturnValueChecker
+ : public Checker<check::PostObjCMessage> {
+ mutable bool Initialized;
+ mutable Selector ObjectAtIndex;
+ mutable Selector ObjectAtIndexedSubscript;
+
+public:
+ ObjCNonNilReturnValueChecker() : Initialized(false) {}
+ void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
+};
+}
+
+static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) {
+ SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
+ if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
+ return State->assume(*DV, true);
+ return State;
+}
+
+void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
+ CheckerContext &C)
+ const {
+ ProgramStateRef State = C.getState();
+
+ if (!Initialized) {
+ ASTContext &Ctx = C.getASTContext();
+ ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
+ ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
+ }
+
+ // Check the receiver type.
+ if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
+
+ // Assume that object returned from '[self init]' or '[super init]' is not
+ // 'nil' if we are processing an inlined function/method.
+ //
+ // A defensive callee will (and should) check if the object returned by
+ // '[super init]' is 'nil' before doing it's own initialization. However,
+ // since 'nil' is rarely returned in practice, we should not warn when the
+ // caller to the defensive constructor uses the object in contexts where
+ // 'nil' is not accepted.
+ if (!C.inTopFrame() && M.getDecl() &&
+ M.getDecl()->getMethodFamily() == OMF_init &&
+ M.isReceiverSelfOrSuper()) {
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+
+ // 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) {
+ // Go ahead and assume the value is non-nil.
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+ }
+ }
+ C.addTransition(State);
+}
//===----------------------------------------------------------------------===//
// Check registration.
@@ -744,3 +819,7 @@ void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
void ento::registerObjCLoopChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCLoopChecker>();
}
+
+void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCNonNilReturnValueChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index a4fc396c3edc..92edefe7b170 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -35,7 +35,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT)
BT.reset(new BuiltinBug("Assignment of a non-Boolean value"));
- C.EmitReport(new BugReport(*BT, BT->getDescription(), N));
+ C.emitReport(new BugReport(*BT, BT->getDescription(), N));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 509bc796fc3c..6ef022b60925 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -55,7 +55,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// FIXME: Refactor into StoreManager itself?
MemRegionManager& RM = C.getStoreManager().getRegionManager();
const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.getCurrentBlockCount(), C.getLocationContext());
+ RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
// Set the extent of the region in bytes. This enables us to use the
// SVal of the argument directly. If we save the extent in bits, we
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 7fe51d3a4ce3..8e455de3bf46 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -4,7 +4,6 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers
TARGET ClangSACheckers)
add_clang_library(clangStaticAnalyzerCheckers
- AdjustedReturnValueChecker.cpp
AnalyzerStatsChecker.cpp
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
@@ -28,12 +27,15 @@ add_clang_library(clangStaticAnalyzerCheckers
DeadStoresChecker.cpp
DebugCheckers.cpp
DereferenceChecker.cpp
+ DirectIvarAssignment.cpp
DivZeroChecker.cpp
DynamicTypePropagation.cpp
ExprInspectionChecker.cpp
+ SimpleStreamChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
+ IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
MacOSKeychainAPIChecker.cpp
MacOSXAPIChecker.cpp
@@ -43,10 +45,10 @@ add_clang_library(clangStaticAnalyzerCheckers
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
ObjCAtSyncChecker.cpp
ObjCContainersASTChecker.cpp
ObjCContainersChecker.cpp
+ ObjCMissingSuperCallChecker.cpp
ObjCSelfInitChecker.cpp
ObjCUnusedIVarsChecker.cpp
PointerArithChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 483082a37f44..eae9ddfc05b9 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -188,21 +188,9 @@ public:
NonLoc right) const;
};
-class CStringLength {
-public:
- typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap;
-};
} //end anonymous namespace
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<CStringLength>
- : public ProgramStatePartialTrait<CStringLength::EntryMap> {
- static void *GDMIndex() { return CStringChecker::getTag(); }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
//===----------------------------------------------------------------------===//
// Individual checks and utility methods.
@@ -252,8 +240,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(S->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, S, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, S, *report);
+ C.emitReport(report);
return NULL;
}
@@ -327,7 +315,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
// reference is outside the range.
report->addRange(S->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return NULL;
}
@@ -544,7 +532,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
report->addRange(First->getSourceRange());
report->addRange(Second->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
@@ -607,7 +595,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
// Generate a report for this bug.
BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N);
- C.EmitReport(report);
+ C.emitReport(report);
return NULL;
}
@@ -673,11 +661,11 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
}
// Otherwise, get a new symbol and update the state.
- unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
QualType sizeTy = svalBuilder.getContext().getSizeType();
SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
- MR, Ex, sizeTy, Count);
+ MR, Ex, sizeTy,
+ C.blockCount());
if (!hypothetical)
state = state->set<CStringLength>(MR, strLength);
@@ -714,7 +702,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
os.str(), N);
report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
return UndefinedVal();
@@ -778,7 +766,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
os.str(), N);
report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
return UndefinedVal();
@@ -826,15 +814,14 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
}
// Invalidate this region.
- unsigned Count = C.getCurrentBlockCount();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, Count, LCtx);
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx);
}
// If we have a non-region value by chance, just remove the binding.
// FIXME: is this necessary or correct? This handles the non-Region
// cases. Is it ever valid to store to these?
- return state->unbindLoc(*L);
+ return state->killBinding(*L);
}
bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
@@ -843,7 +830,7 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
@@ -957,9 +944,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
- unsigned Count = C.getCurrentBlockCount();
- SVal result =
- C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx,
+ C.blockCount());
state = state->BindExpr(CE, LCtx, result);
}
@@ -1093,8 +1079,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
state = CheckBufferAccess(C, state, Size, Left, Right);
if (state) {
// The return value is the comparison result, which we don't know.
- unsigned Count = C.getCurrentBlockCount();
- SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
state = state->BindExpr(CE, LCtx, CmpV);
C.addTransition(state);
}
@@ -1206,8 +1191,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// no guarantee the full string length will actually be returned.
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
- unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
NonLoc *resultNL = cast<NonLoc>(&result);
if (strLengthNL) {
@@ -1234,8 +1218,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
- unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
}
}
@@ -1612,8 +1595,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (returnEnd && Result.isUnknown()) {
- unsigned Count = C.getCurrentBlockCount();
- Result = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
}
// Set the return value.
@@ -1770,8 +1752,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (!canComputeResult) {
// Conjure a symbolic value. It's the best we can do.
- unsigned Count = C.getCurrentBlockCount();
- SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
state = state->BindExpr(CE, LCtx, resultVal);
}
@@ -1885,7 +1866,7 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
}
bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
@@ -1895,7 +1876,7 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1915,10 +1896,10 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
}
}
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
// Then loop over the entries in the current state.
- for (CStringLength::EntryMap::iterator I = Entries.begin(),
+ for (CStringLengthTy::iterator I = Entries.begin(),
E = Entries.end(); I != E; ++I) {
const MemRegion *MR = I.getKey();
@@ -1945,9 +1926,9 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
void CStringChecker::checkLiveSymbols(ProgramStateRef state,
SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
@@ -1963,12 +1944,12 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
return;
ProgramStateRef state = C.getState();
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return;
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
if (SymbolRef Sym = Len.getAsSymbol()) {
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index befc935d4f34..f1a3aacc7c4c 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -33,7 +33,6 @@ namespace {
class WalkAST: public StmtVisitor<WalkAST> {
BugReporter &BR;
AnalysisDeclContext* AC;
- ASTContext &ASTC;
/// Check if two expressions refer to the same declaration.
inline bool sameDecl(const Expr *A1, const Expr *A2) {
@@ -58,8 +57,8 @@ class WalkAST: public StmtVisitor<WalkAST> {
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return false;
- return (CheckerContext::isCLibraryFunction(FD, "strlen", ASTC)
- && sameDecl(CE->getArg(0), WithArg));
+ return (CheckerContext::isCLibraryFunction(FD, "strlen") &&
+ sameDecl(CE->getArg(0), WithArg));
}
return false;
}
@@ -83,7 +82,7 @@ class WalkAST: public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br, AnalysisDeclContext* ac) :
- BR(br), AC(ac), ASTC(AC->getASTContext()) {
+ BR(br), AC(ac) {
}
// Statement visitor methods.
@@ -136,7 +135,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (!FD)
return;
- if (CheckerContext::isCLibraryFunction(FD, "strncat", ASTC)) {
+ if (CheckerContext::isCLibraryFunction(FD, "strncat")) {
if (containsBadStrncatPattern(CE)) {
const Expr *DstArg = CE->getArg(0);
const Expr *LenArg = CE->getArg(2);
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 5edcf09f1150..82bc1361acfe 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -75,13 +75,13 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, BadE, R);
+ bugreporter::trackNullOrUndefValue(N, BadE, *R);
}
- C.EmitReport(R);
+ C.emitReport(R);
}
-StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
- bool IsFirstArgument) {
+static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
+ bool IsFirstArgument) {
switch (Call.getKind()) {
case CE_ObjCMessage: {
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
@@ -122,8 +122,8 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
BugReport *R = new BugReport(*BT, Desc, N);
R->addRange(argRange);
if (argEx)
- bugreporter::addTrackNullOrUndefValueVisitor(N, argEx, R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, argEx, *R);
+ C.emitReport(R);
}
return true;
}
@@ -207,7 +207,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
- C.EmitReport(R);
+ C.emitReport(R);
}
return true;
}
@@ -335,8 +335,8 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
if (const Expr *ReceiverE = ME->getInstanceReceiver())
- bugreporter::addTrackNullOrUndefValueVisitor(N, ReceiverE, R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
+ C.emitReport(R);
}
return;
} else {
@@ -377,9 +377,9 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
report->addRange(ME->getReceiverRange());
// FIXME: This won't track "self" in messages to super.
if (const Expr *receiver = ME->getInstanceReceiver()) {
- bugreporter::addTrackNullOrUndefValueVisitor(N, receiver, report);
+ bugreporter::trackNullOrUndefValue(N, receiver, *report);
}
- C.EmitReport(report);
+ C.emitReport(report);
}
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 2e184fbaf946..1cb8a8de7348 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -75,7 +75,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
BugReport *R = new BugReport(*BT, BT->getDescription(),
errorNode);
R->addRange(CE->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 1407638fcd69..d6d0e3c7b3b8 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -64,7 +64,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
"errors or data corruption."));
BugReport *R = new BugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 7a2586557168..90872058af55 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -85,7 +85,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
Expr::NPC_ValueDependentIsNull)) {
// This is only a 'release' if the property kind is not
// 'assign'.
- return PD->getSetterKind() != ObjCPropertyDecl::Assign;;
+ return PD->getSetterKind() != ObjCPropertyDecl::Assign;
}
// Recurse to children.
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index b8b7c367969c..5cd61941841d 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -270,6 +270,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
// Emit the error. First figure out which DeclRefExpr in the condition
// referenced the compared variable.
+ assert(drInc->getDecl());
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
SmallVector<SourceRange, 2> ranges;
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index 0e9efaa5ade8..efaec2b3f1e3 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -25,6 +25,7 @@ using namespace ento;
// All checkers should be placed into anonymous namespace.
// We place the CheckerDocumentation inside ento namespace to make the
// it visible in doxygen.
+namespace clang {
namespace ento {
/// This checker documents the callback functions checkers can use to implement
@@ -33,8 +34,8 @@ namespace ento {
/// checking.
///
/// \sa CheckerContext
-class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>,
- check::PostStmt<CallExpr>,
+class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
+ check::PostStmt<DeclStmt>,
check::PreObjCMessage,
check::PostObjCMessage,
check::PreCall,
@@ -64,8 +65,8 @@ public:
/// See checkBranchCondition() callback for performing custom processing of
/// the branching statements.
///
- /// check::PreStmt<DeclStmt>
- void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {}
+ /// check::PreStmt<ReturnStmt>
+ void checkPreStmt(const ReturnStmt *DS, CheckerContext &C) const {}
/// \brief Post-visit the Statement.
///
@@ -74,8 +75,8 @@ public:
/// which does not include the control flow statements such as IfStmt. The
/// callback can be specialized to be called with any subclass of Stmt.
///
- /// check::PostStmt<CallExpr>
- void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
+ /// check::PostStmt<DeclStmt>
+ void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
/// \brief Pre-visit the Objective C message.
///
@@ -98,8 +99,8 @@ public:
/// behavior for functions and methods no matter how they are being invoked.
///
/// Note that this includes ALL cross-body invocations, so if you want to
- /// limit your checks to, say, function calls, you can either test for that
- /// or fall back to the explicit callback (i.e. check::PreStmt).
+ /// limit your checks to, say, function calls, you should test for that at the
+ /// beginning of your callback function.
///
/// check::PreCall
void checkPreCall(const CallEvent &Call, CheckerContext &C) const {}
@@ -151,9 +152,8 @@ public:
/// check::DeadSymbols
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {}
- /// \brief Called when an end of path is reached in the ExplodedGraph.
- ///
- /// This callback should be used to check if the allocated resources are freed.
+ /// \brief Called when the analyzer core reaches the end of the top-level
+ /// function being analyzed.
///
/// check::EndPath
void checkEndPath(CheckerContext &Ctx) const {}
@@ -213,21 +213,35 @@ public:
/// check::LiveSymbols
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const {}
-
+ /// \brief Called to determine if the checker currently needs to know if when
+ /// contents of any regions change.
+ ///
+ /// Since it is not necessarily cheap to compute which regions are being
+ /// changed, this allows the analyzer core to skip the more expensive
+ /// #checkRegionChanges when no checkers are tracking any state.
bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
- /// \brief Allows tracking regions which get invalidated.
+ /// \brief Called when the contents of one or more regions change.
+ ///
+ /// This can occur in many different ways: an explicit bind, a blanket
+ /// invalidation of the region contents, or by passing a region to a function
+ /// call whose behavior the analyzer cannot model perfectly.
///
/// \param State The current program state.
/// \param Invalidated A set of all symbols potentially touched by the change.
/// \param ExplicitRegions The regions explicitly requested for invalidation.
- /// For example, in the case of a function call, these would be arguments.
- /// \param Regions The transitive closure of accessible regions,
- /// i.e. all regions that may have been touched by this change.
- /// \param Call The call expression wrapper if the regions are invalidated
- /// by a call, 0 otherwise.
- /// Note, in order to be notified, the checker should also implement the
- /// wantsRegionChangeUpdate callback.
+ /// For a function call, this would be the arguments. For a bind, this
+ /// would be the region being bound to.
+ /// \param Regions The transitive closure of regions accessible from,
+ /// \p ExplicitRegions, i.e. all regions that may have been touched
+ /// by this change. For a simple bind, this list will be the same as
+ /// \p ExplicitRegions, since a bind does not affect the contents of
+ /// anything accessible through the base region.
+ /// \param Call The opaque call triggering this invalidation. Will be 0 if the
+ /// change was not triggered by a call.
+ ///
+ /// Note that this callback will not be invoked unless
+ /// #wantsRegionChangeUpdate returns \c true.
///
/// check::RegionChanges
ProgramStateRef
@@ -256,9 +270,10 @@ public:
};
-void CheckerDocumentation::checkPostStmt(const CallExpr *DS,
+void CheckerDocumentation::checkPostStmt(const DeclStmt *DS,
CheckerContext &C) const {
return;
}
-} // end namespace
+} // end namespace ento
+} // end namespace clang
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 8110bd0e18c2..235e63306f04 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -13,33 +13,33 @@ include "clang/StaticAnalyzer/Checkers/CheckerBase.td"
// Packages.
//===----------------------------------------------------------------------===//
-def Experimental : Package<"experimental">;
+def Alpha : Package<"alpha">;
def Core : Package<"core">;
def CoreBuiltin : Package<"builtin">, InPackage<Core>;
def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
-def CoreExperimental : Package<"core">, InPackage<Experimental>, Hidden;
+def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
def Cplusplus : Package<"cplusplus">;
-def CplusplusExperimental : Package<"cplusplus">, InPackage<Experimental>, Hidden;
+def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden;
def DeadCode : Package<"deadcode">;
-def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden;
+def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
def Security : Package <"security">;
def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
-def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden;
-def Taint : Package<"taint">, InPackage<SecurityExperimental>, Hidden;
+def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
+def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden;
def Unix : Package<"unix">;
-def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden;
+def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
def CString : Package<"cstring">, InPackage<Unix>, Hidden;
-def CStringExperimental : Package<"cstring">, InPackage<UnixExperimental>, Hidden;
+def CStringAlpha : Package<"cstring">, InPackage<UnixAlpha>, Hidden;
def OSX : Package<"osx">;
-def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden;
+def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden;
def Cocoa : Package<"cocoa">, InPackage<OSX>;
-def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden;
+def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden;
def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
def Containers : Package<"containers">, InPackage<CoreFoundation>;
@@ -60,10 +60,6 @@ def CallAndMessageChecker : Checker<"CallAndMessage">,
HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
DescFile<"CallAndMessageChecker.cpp">;
-def AdjustedReturnValueChecker : Checker<"AdjustedReturnValue">,
- HelpText<"Check to see if the return value of a function call is different than the caller expects (e.g., from calls through function pointers)">,
- DescFile<"AdjustedReturnValueChecker.cpp">;
-
def AttrNonNullChecker : Checker<"AttributeNonNull">,
HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">,
DescFile<"AttrNonNullChecker.cpp">;
@@ -90,7 +86,7 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
} // end "core"
-let ParentPackage = CoreExperimental in {
+let ParentPackage = CoreAlpha in {
def BoolAssignmentChecker : Checker<"BoolAssignment">,
HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
@@ -120,7 +116,7 @@ def SizeofPointerChecker : Checker<"SizeofPtr">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
DescFile<"CheckSizeofPointer.cpp">;
-} // end "core.experimental"
+} // end "alpha.core"
//===----------------------------------------------------------------------===//
// Evaluate "builtin" functions.
@@ -170,13 +166,13 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
// C++ checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = CplusplusExperimental in {
+let ParentPackage = CplusplusAlpha in {
def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">;
-} // end: "cplusplus.experimental"
+} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
// Deadcode checkers.
@@ -189,7 +185,7 @@ def DeadStoresChecker : Checker<"DeadStores">,
DescFile<"DeadStoresChecker.cpp">;
} // end DeadCode
-let ParentPackage = DeadCodeExperimental in {
+let ParentPackage = DeadCodeAlpha in {
def IdempotentOperationChecker : Checker<"IdempotentOperations">,
HelpText<"Warn about idempotent operations">,
@@ -199,7 +195,7 @@ def UnreachableCodeChecker : Checker<"UnreachableCode">,
HelpText<"Check unreachable code">,
DescFile<"UnreachableCodeChecker.cpp">;
-} // end "deadcode.experimental"
+} // end "alpha.deadcode"
//===----------------------------------------------------------------------===//
// Security checkers.
@@ -237,7 +233,7 @@ let ParentPackage = Security in {
DescFile<"CheckSecuritySyntaxOnly.cpp">;
}
-let ParentPackage = SecurityExperimental in {
+let ParentPackage = SecurityAlpha in {
def ArrayBoundChecker : Checker<"ArrayBound">,
HelpText<"Warn about buffer overflows (older checker)">,
@@ -255,7 +251,7 @@ def MallocOverflowSecurityChecker : Checker<"MallocOverflow">,
HelpText<"Check for overflows in the arguments to malloc()">,
DescFile<"MallocOverflowSecurityChecker.cpp">;
-} // end "security.experimental"
+} // end "alpha.security"
//===----------------------------------------------------------------------===//
// Taint checkers.
@@ -267,7 +263,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">,
HelpText<"Generate taint information used by other checkers">,
DescFile<"GenericTaintChecker.cpp">;
-} // end "experimental.security.taint"
+} // end "alpha.security.taint"
//===----------------------------------------------------------------------===//
// Unix API checkers.
@@ -289,7 +285,7 @@ def MallocSizeofChecker : Checker<"MallocSizeof">,
} // end "unix"
-let ParentPackage = UnixExperimental in {
+let ParentPackage = UnixAlpha in {
def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
@@ -307,7 +303,11 @@ def StreamChecker : Checker<"Stream">,
HelpText<"Check stream handling functions">,
DescFile<"StreamChecker.cpp">;
-} // end "unix.experimental"
+def SimpleStreamChecker : Checker<"SimpleStream">,
+ HelpText<"Check for misuses of stream APIs">,
+ DescFile<"SimpleStreamChecker.cpp">;
+
+} // end "alpha.unix"
let ParentPackage = CString in {
@@ -320,7 +320,7 @@ def CStringSyntaxChecker : Checker<"BadSizeArg">,
DescFile<"CStringSyntaxChecker.cpp">;
}
-let ParentPackage = CStringExperimental in {
+let ParentPackage = CStringAlpha in {
def CStringOutOfBounds : Checker<"OutOfBounds">,
HelpText<"Check for out-of-bounds access in string functions">,
@@ -346,11 +346,6 @@ def MacOSXAPIChecker : Checker<"API">,
HelpText<"Check for proper uses of various Mac OS X APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
-def OSAtomicChecker : Checker<"AtomicCAS">,
- InPackage<OSX>,
- HelpText<"Evaluate calls to OSAtomic functions">,
- DescFile<"OSAtomicChecker.cpp">;
-
def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
InPackage<OSX>,
HelpText<"Check for proper uses of Secure Keychain APIs">,
@@ -397,6 +392,10 @@ def ObjCLoopChecker : Checker<"Loops">,
HelpText<"Improved modeling of loops using Cocoa collection types">,
DescFile<"BasicObjCFoundationChecks.cpp">;
+def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">,
+ HelpText<"Model the APIs that are guaranteed to return a non-nil value">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;
@@ -407,13 +406,25 @@ def RetainCountChecker : Checker<"RetainCount">,
} // end "osx.cocoa"
-let ParentPackage = CocoaExperimental in {
+let ParentPackage = CocoaAlpha in {
def ObjCDeallocChecker : Checker<"Dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
-} // end "cocoa.experimental"
+def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">,
+ HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
+ DescFile<"IvarInvalidationChecker.cpp">;
+
+def DirectIvarAssignment : Checker<"DirectIvarAssignment">,
+ HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
+ HelpText<"Warn about Objective-C methods that lack a necessary call to super">,
+ DescFile<"ObjCMissingSuperCallChecker.cpp">;
+
+} // end "alpha.osx.cocoa"
let ParentPackage = CoreFoundation in {
@@ -422,7 +433,7 @@ def CFNumberCreateChecker : Checker<"CFNumber">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
- HelpText<"Check for null arguments to CFRetain/CFRelease">,
+ HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def CFErrorChecker : Checker<"CFError">,
@@ -479,6 +490,10 @@ def CallGraphDumper : Checker<"DumpCallGraph">,
HelpText<"Display Call Graph">,
DescFile<"DebugCheckers.cpp">;
+def ConfigDumper : Checker<"ConfigDumper">,
+ HelpText<"Dump config table">,
+ DescFile<"DebugCheckers.cpp">;
+
def TraversalDumper : Checker<"DumpTraversal">,
HelpText<"Print branch conditions as they are traversed by the engine">,
DescFile<"TraversalChecker.cpp">;
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 30d060996ea7..c8856162fe89 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -147,7 +147,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
"after chroot"));
BugReport *R = new BugReport(*BT_BreakJail,
BT_BreakJail->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return;
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 510e8cd8104b..59e03ecd5c61 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -13,22 +13,54 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
-#include "llvm/ADT/SmallPtrSet.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"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
-namespace {
+namespace {
+
+/// A simple visitor to record what VarDecls occur in EH-handling code.
+class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
+public:
+ bool inEH;
+ llvm::DenseSet<const VarDecl *> &S;
+
+ bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
+ SaveAndRestore<bool> inFinally(inEH, true);
+ return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
+ }
+
+ bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
+ SaveAndRestore<bool> inCatch(inEH, true);
+ return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
+ }
+
+ bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
+ SaveAndRestore<bool> inCatch(inEH, true);
+ return TraverseStmt(S->getHandlerBlock());
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *DR) {
+ if (inEH)
+ if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
+ S.insert(D);
+ return true;
+ }
+
+ EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
+ inEH(false), S(S) {}
+};
// FIXME: Eventually migrate into its own file, and have it managed by
// AnalysisManager.
@@ -93,6 +125,7 @@ class DeadStoreObs : public LiveVariables::Observer {
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
OwningPtr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
+ llvm::OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
@@ -105,6 +138,23 @@ public:
virtual ~DeadStoreObs() {}
+ bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
+ if (Live.isLive(D))
+ return true;
+ // Lazily construct the set that records which VarDecls are in
+ // EH code.
+ if (!InEH.get()) {
+ InEH.reset(new llvm::DenseSet<const VarDecl *>());
+ EHCodeVisitor V(*InEH.get());
+ V.TraverseStmt(AC->getBody());
+ }
+ // Treat all VarDecls that occur in EH code as being "always live"
+ // when considering to suppress dead stores. Frequently stores
+ // are followed by reads in EH code, but we don't have the ability
+ // to analyze that yet.
+ return InEH->count(D);
+ }
+
void Report(const VarDecl *V, DeadStoreKind dsk,
PathDiagnosticLocation L, SourceRange R) {
if (Escaped.count(V))
@@ -159,7 +209,7 @@ public:
if (VD->getType()->getAs<ReferenceType>())
return;
- if (!Live.isLive(VD) &&
+ if (!isLive(Live, VD) &&
!(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) {
PathDiagnosticLocation ExLoc =
@@ -285,7 +335,7 @@ public:
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
// marked 'unused'.
- if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) {
+ if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) {
// Special case: check for initializations with constants.
//
// e.g. : int x = 0;
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 34053cdad638..7ad9c59a1bb2 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -144,3 +144,38 @@ public:
void ento::registerCallGraphDumper(CheckerManager &mgr) {
mgr.registerChecker<CallGraphDumper>();
}
+
+
+//===----------------------------------------------------------------------===//
+// ConfigDumper
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
+public:
+ void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
+ AnalysisManager& mgr,
+ BugReporter &BR) const {
+
+ const AnalyzerOptions::ConfigTable &Config = mgr.options.Config;
+ AnalyzerOptions::ConfigTable::const_iterator I =
+ Config.begin(), E = Config.end();
+
+ 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';
+ }
+ llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
+ }
+};
+}
+
+void ento::registerConfigDumper(CheckerManager &mgr) {
+ mgr.registerChecker<ConfigDumper>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index e98c131ce97d..3ace4be44804 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -39,7 +39,7 @@ public:
CheckerContext &C) const;
void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
- static const MemRegion *AddDerefSource(raw_ostream &os,
+ static void AddDerefSource(raw_ostream &os,
SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex, const ProgramState *state,
const LocationContext *LCtx,
@@ -47,7 +47,7 @@ public:
};
} // end anonymous namespace
-const MemRegion *
+void
DereferenceChecker::AddDerefSource(raw_ostream &os,
SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex,
@@ -55,7 +55,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
const LocationContext *LCtx,
bool loadedFrom) {
Ex = Ex->IgnoreParenLValueCasts();
- const MemRegion *sourceR = 0;
switch (Ex->getStmtClass()) {
default:
break;
@@ -65,7 +64,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
os << " (" << (loadedFrom ? "loaded from" : "from")
<< " variable '" << VD->getName() << "')";
Ranges.push_back(DR->getSourceRange());
- sourceR = state->getLValue(VD, LCtx).getAsRegion();
}
break;
}
@@ -78,7 +76,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
break;
}
}
- return sourceR;
}
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
@@ -94,6 +91,8 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
BT_null.reset(new BuiltinBug("Dereference of null pointer"));
SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
SmallVector<SourceRange, 2> Ranges;
// Walk through lvalue casts to get the original expression
@@ -101,8 +100,6 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
if (const Expr *expr = dyn_cast<Expr>(S))
S = expr->IgnoreParenLValueCasts();
- const MemRegion *sourceR = 0;
-
if (IsBind) {
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
if (BO->isAssignmentOp())
@@ -117,68 +114,55 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
switch (S->getStmtClass()) {
case Stmt::ArraySubscriptExprClass: {
- llvm::raw_svector_ostream os(buf);
os << "Array access";
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
- sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext());
+ AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext());
os << " results in a null pointer dereference";
break;
}
case Stmt::UnaryOperatorClass: {
- llvm::raw_svector_ostream os(buf);
os << "Dereference of null pointer";
const UnaryOperator *U = cast<UnaryOperator>(S);
- sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
- State.getPtr(), N->getLocationContext(), true);
+ AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
+ State.getPtr(), N->getLocationContext(), true);
break;
}
case Stmt::MemberExprClass: {
const MemberExpr *M = cast<MemberExpr>(S);
- if (M->isArrow()) {
- llvm::raw_svector_ostream os(buf);
+ if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) {
os << "Access to field '" << M->getMemberNameInfo()
<< "' results in a dereference of a null pointer";
- sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext(), true);
}
break;
}
case Stmt::ObjCIvarRefExprClass: {
const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
- if (const DeclRefExpr *DR =
- dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- llvm::raw_svector_ostream os(buf);
- os << "Instance variable access (via '" << VD->getName()
- << "') results in a null pointer dereference";
- }
- }
- Ranges.push_back(IV->getSourceRange());
+ os << "Access to instance variable '" << *IV->getDecl()
+ << "' results in a dereference of a null pointer";
+ AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
+ State.getPtr(), N->getLocationContext(), true);
break;
}
default:
break;
}
+ os.flush();
BugReport *report =
new BugReport(*BT_null,
buf.empty() ? BT_null->getDescription() : buf.str(),
N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N),
- report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report);
for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
report->addRange(*I);
- if (sourceR) {
- report->markInteresting(sourceR);
- report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR)));
- }
-
- C.EmitReport(report);
+ C.emitReport(report);
}
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -191,11 +175,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDerefExpr(N),
- report);
- report->disablePathPruning();
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N),
+ *report);
+ C.emitReport(report);
}
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
new file mode 100644
index 000000000000..dc90b67e20fa
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -0,0 +1,180 @@
+//=- DirectIvarAssignment.cpp - Check rules on ObjC properties -*- C++ ----*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Check that Objective C properties follow the following rules:
+// - The property should be set with the setter, not though a direct
+// assignment.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class DirectIvarAssignment :
+ public Checker<check::ASTDecl<ObjCImplementationDecl> > {
+
+ typedef llvm::DenseMap<const ObjCIvarDecl*,
+ const ObjCPropertyDecl*> IvarToPropertyMapTy;
+
+ /// A helper class, which walks the AST and locates all assignments to ivars
+ /// in the given function.
+ class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
+ const IvarToPropertyMapTy &IvarToPropMap;
+ const ObjCMethodDecl *MD;
+ const ObjCInterfaceDecl *InterfD;
+ BugReporter &BR;
+ LocationOrAnalysisDeclContext DCtx;
+
+ public:
+ MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
+ const ObjCInterfaceDecl *InID,
+ BugReporter &InBR, AnalysisDeclContext *InDCtx)
+ : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {}
+
+ void VisitStmt(const Stmt *S) { VisitChildren(S); }
+
+ void VisitBinaryOperator(const BinaryOperator *BO);
+
+ void VisitChildren(const Stmt *S) {
+ for (Stmt::const_child_range I = S->children(); I; ++I)
+ if (*I)
+ this->Visit(*I);
+ }
+ };
+
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const;
+};
+
+static const ObjCIvarDecl *findPropertyBackingIvar(const ObjCPropertyDecl *PD,
+ const ObjCInterfaceDecl *InterD,
+ ASTContext &Ctx) {
+ // Check for synthesized ivars.
+ ObjCIvarDecl *ID = PD->getPropertyIvarDecl();
+ if (ID)
+ return ID;
+
+ ObjCInterfaceDecl *NonConstInterD = const_cast<ObjCInterfaceDecl*>(InterD);
+
+ // Check for existing "_PropName".
+ ID = NonConstInterD->lookupInstanceVariable(PD->getDefaultSynthIvarName(Ctx));
+ if (ID)
+ return ID;
+
+ // Check for existing "PropName".
+ IdentifierInfo *PropIdent = PD->getIdentifier();
+ ID = NonConstInterD->lookupInstanceVariable(PropIdent);
+
+ return ID;
+}
+
+void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
+ AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ const ObjCInterfaceDecl *InterD = D->getClassInterface();
+
+
+ IvarToPropertyMapTy IvarToPropMap;
+
+ // Find all properties for this class.
+ for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(),
+ E = InterD->prop_end(); I != E; ++I) {
+ ObjCPropertyDecl *PD = *I;
+
+ // Find the corresponding IVar.
+ const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
+ Mgr.getASTContext());
+
+ if (!ID)
+ continue;
+
+ // Store the IVar to property mapping.
+ IvarToPropMap[ID] = PD;
+ }
+
+ if (IvarToPropMap.empty())
+ return;
+
+ for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
+ E = D->instmeth_end(); I != E; ++I) {
+
+ ObjCMethodDecl *M = *I;
+ AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
+
+ // Skip the init, dealloc functions and any functions that might be doing
+ // initialization based on their name.
+ 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)
+ continue;
+
+ const Stmt *Body = M->getBody();
+ assert(Body);
+
+ MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx);
+ MC.VisitStmt(Body);
+ }
+}
+
+void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
+ const BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+
+ const ObjCIvarRefExpr *IvarRef =
+ dyn_cast<ObjCIvarRefExpr>(BO->getLHS()->IgnoreParenCasts());
+
+ if (!IvarRef)
+ return;
+
+ if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
+ IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
+ if (I != IvarToPropMap.end()) {
+ const ObjCPropertyDecl *PD = I->second;
+
+ ObjCMethodDecl *GetterMethod =
+ InterfD->getInstanceMethod(PD->getGetterName());
+ ObjCMethodDecl *SetterMethod =
+ InterfD->getInstanceMethod(PD->getSetterName());
+
+ if (SetterMethod && SetterMethod->getCanonicalDecl() == MD)
+ return;
+
+ if (GetterMethod && GetterMethod->getCanonicalDecl() == MD)
+ return;
+
+ BR.EmitBasicReport(MD,
+ "Property access",
+ categories::CoreFoundationObjectiveC,
+ "Direct assignment to an instance variable backing a property; "
+ "use the setter instead", PathDiagnosticLocation(IvarRef,
+ BR.getSourceManager(),
+ DCtx));
+ }
+ }
+}
+}
+
+void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
+ mgr.registerChecker<DirectIvarAssignment>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index dcf6a8603ec7..76fb3f2b288e 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -39,13 +39,9 @@ void DivZeroChecker::reportBug(const char *Msg,
if (!BT)
BT.reset(new BuiltinBug("Division by zero"));
- BugReport *R =
- new BugReport(*BT, Msg, N);
-
- bugreporter::addTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDenomExpr(N),
- R);
- C.EmitReport(R);
+ BugReport *R = new BugReport(*BT, Msg, N);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index b636efbe35a1..b0a4bc67485e 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -83,14 +83,14 @@ void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
// C++11 [class.cdtor]p4 (see above)
+ if (!Dtor->isBaseDestructor())
+ return;
const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
if (!Target)
return;
- // FIXME: getRuntimeDefinition() can be expensive. It would be better to do
- // this when we are entering the stack frame for the destructor.
- const Decl *D = Dtor->getRuntimeDefinition().getDecl();
+ const Decl *D = Dtor->getDecl();
if (!D)
return;
@@ -105,8 +105,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
// Get the returned value if it's a region.
- SVal Result = C.getSVal(Call.getOriginExpr());
- const MemRegion *RetReg = Result.getAsRegion();
+ const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
if (!RetReg)
return;
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 7acf223e63d6..e7e316281faa 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -93,7 +93,7 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
BT.reset(new BugType("Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
@@ -113,7 +113,7 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
BT.reset(new BugType("Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index a1f2f3b2ba98..7fde68923124 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -58,7 +58,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
"environments or platforms."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index afb862cd6c9a..a9e02173c3a9 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -192,13 +192,7 @@ const char GenericTaintChecker::MsgTaintedBufferSize[] =
/// to the call post-visit. The values are unsigned integers, which are either
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
/// points to data, which should be tainted on return.
-namespace { struct TaintArgsOnPostVisit{}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<TaintArgsOnPostVisit>
- : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > {
- static void *GDMIndex() { return GenericTaintChecker::getTag(); }
-};
-}}
+REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
@@ -337,7 +331,7 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
// Depending on what was tainted at pre-visit, we determined a set of
// arguments which should be tainted after the function returns. These are
// stored in the state as TaintArgsOnPostVisit set.
- llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>();
+ TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
if (TaintArgs.isEmpty())
return false;
@@ -653,7 +647,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
initBugType();
BugReport *report = new BugReport(*BT, Msg, N);
report->addRange(E->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return true;
}
return false;
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 9d0b83f40b34..ffbbb8b68d8a 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -430,7 +430,7 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS);
}
- BR.EmitReport(report);
+ BR.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
new file mode 100644
index 000000000000..bf256cd9fa45
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -0,0 +1,550 @@
+//=- IvarInvalidationChecker.cpp - -*- C++ -------------------------------*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker implements annotation driven invalidation checking. If a class
+// contains a method annotated with 'objc_instance_variable_invalidator',
+// - (void) foo
+// __attribute__((annotate("objc_instance_variable_invalidator")));
+// all the "ivalidatable" instance variables of this class should be
+// invalidated. We call an instance variable ivalidatable if it is an object of
+// a class which contains an invalidation method. There could be multiple
+// methods annotated with such annotations per class, either one can be used
+// to invalidate the ivar. An ivar or property are considered to be
+// invalidated if they are being assigned 'nil' or an invalidation method has
+// been called on them. An invalidation method should either invalidate all
+// the ivars or call another invalidation method (on self).
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class IvarInvalidationChecker :
+ public Checker<check::ASTDecl<ObjCMethodDecl> > {
+
+ typedef llvm::DenseSet<const ObjCMethodDecl*> MethodSet;
+ typedef llvm::DenseMap<const ObjCMethodDecl*,
+ const ObjCIvarDecl*> MethToIvarMapTy;
+ typedef llvm::DenseMap<const ObjCPropertyDecl*,
+ const ObjCIvarDecl*> PropToIvarMapTy;
+ typedef llvm::DenseMap<const ObjCIvarDecl*,
+ const ObjCPropertyDecl*> IvarToPropMapTy;
+
+
+ struct IvarInfo {
+ /// Has the ivar been invalidated?
+ bool IsInvalidated;
+
+ /// The methods which can be used to invalidate the ivar.
+ MethodSet InvalidationMethods;
+
+ IvarInfo() : IsInvalidated(false) {}
+ void addInvalidationMethod(const ObjCMethodDecl *MD) {
+ InvalidationMethods.insert(MD);
+ }
+
+ bool needsInvalidation() const {
+ return !InvalidationMethods.empty();
+ }
+
+ void markInvalidated() {
+ IsInvalidated = true;
+ }
+
+ bool markInvalidated(const ObjCMethodDecl *MD) {
+ if (IsInvalidated)
+ return true;
+ for (MethodSet::iterator I = InvalidationMethods.begin(),
+ E = InvalidationMethods.end(); I != E; ++I) {
+ if (*I == MD) {
+ IsInvalidated = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isInvalidated() const {
+ return IsInvalidated;
+ }
+ };
+
+ typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet;
+
+ /// Statement visitor, which walks the method body and flags the ivars
+ /// referenced in it (either directly or via property).
+ class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
+ /// The set of Ivars which need to be invalidated.
+ IvarSet &IVars;
+
+ /// Flag is set as the result of a message send to another
+ /// invalidation method.
+ bool &CalledAnotherInvalidationMethod;
+
+ /// Property setter to ivar mapping.
+ const MethToIvarMapTy &PropertySetterToIvarMap;
+
+ /// Property getter to ivar mapping.
+ const MethToIvarMapTy &PropertyGetterToIvarMap;
+
+ /// Property to ivar mapping.
+ const PropToIvarMapTy &PropertyToIvarMap;
+
+ /// The invalidation method being currently processed.
+ const ObjCMethodDecl *InvalidationMethod;
+
+ ASTContext &Ctx;
+
+ /// Peel off parens, casts, OpaqueValueExpr, and PseudoObjectExpr.
+ const Expr *peel(const Expr *E) const;
+
+ /// Does this expression represent zero: '0'?
+ bool isZero(const Expr *E) const;
+
+ /// Mark the given ivar as invalidated.
+ void markInvalidated(const ObjCIvarDecl *Iv);
+
+ /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as
+ /// invalidated.
+ void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef);
+
+ /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks
+ /// it as invalidated.
+ void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA);
+
+ /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar,
+ /// if yes, marks it as invalidated.
+ void checkObjCMessageExpr(const ObjCMessageExpr *ME);
+
+ /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated.
+ void check(const Expr *E);
+
+ public:
+ MethodCrawler(IvarSet &InIVars,
+ bool &InCalledAnotherInvalidationMethod,
+ const MethToIvarMapTy &InPropertySetterToIvarMap,
+ const MethToIvarMapTy &InPropertyGetterToIvarMap,
+ const PropToIvarMapTy &InPropertyToIvarMap,
+ ASTContext &InCtx)
+ : IVars(InIVars),
+ CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod),
+ PropertySetterToIvarMap(InPropertySetterToIvarMap),
+ PropertyGetterToIvarMap(InPropertyGetterToIvarMap),
+ PropertyToIvarMap(InPropertyToIvarMap),
+ InvalidationMethod(0),
+ Ctx(InCtx) {}
+
+ void VisitStmt(const Stmt *S) { VisitChildren(S); }
+
+ void VisitBinaryOperator(const BinaryOperator *BO);
+
+ void VisitObjCMessageExpr(const ObjCMessageExpr *ME);
+
+ void VisitChildren(const Stmt *S) {
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ if (CalledAnotherInvalidationMethod)
+ return;
+ }
+ }
+ };
+
+ /// Check if the any of the methods inside the interface are annotated with
+ /// the invalidation annotation, update the IvarInfo accordingly.
+ static void containsInvalidationMethod(const ObjCContainerDecl *D,
+ IvarInfo &Out);
+
+ /// Check if ivar should be tracked and add to TrackedIvars if positive.
+ /// Returns true if ivar should be tracked.
+ static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars);
+
+ /// Given the property declaration, and the list of tracked ivars, finds
+ /// the ivar backing the property when possible. Returns '0' when no such
+ /// ivar could be found.
+ static const ObjCIvarDecl *findPropertyBackingIvar(
+ const ObjCPropertyDecl *Prop,
+ const ObjCInterfaceDecl *InterfaceD,
+ IvarSet &TrackedIvars);
+
+public:
+ void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const;
+
+ // TODO: We are currently ignoring the ivars coming from class extensions.
+};
+
+static bool isInvalidationMethod(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_instance_variable_invalidator")
+ return true;
+ }
+ return false;
+}
+
+void IvarInvalidationChecker::containsInvalidationMethod(
+ const ObjCContainerDecl *D, IvarInfo &OutInfo) {
+
+ // TODO: Cache the results.
+
+ if (!D)
+ return;
+
+ // Check all methods.
+ for (ObjCContainerDecl::method_iterator
+ I = D->meth_begin(),
+ E = D->meth_end(); I != E; ++I) {
+ const ObjCMethodDecl *MDI = *I;
+ if (isInvalidationMethod(MDI))
+ OutInfo.addInvalidationMethod(
+ cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
+ }
+
+ // If interface, check all parent protocols and super.
+ // TODO: Visit all categories in case the invalidation method is declared in
+ // a category.
+ if (const ObjCInterfaceDecl *InterfaceD = dyn_cast<ObjCInterfaceDecl>(D)) {
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = InterfaceD->protocol_begin(),
+ E = InterfaceD->protocol_end(); I != E; ++I) {
+ containsInvalidationMethod(*I, OutInfo);
+ }
+ containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo);
+ return;
+ }
+
+ // If protocol, check all parent protocols.
+ if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) {
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = ProtD->protocol_begin(),
+ E = ProtD->protocol_end(); I != E; ++I) {
+ containsInvalidationMethod(*I, OutInfo);
+ }
+ return;
+ }
+
+ llvm_unreachable("One of the casts above should have succeeded.");
+}
+
+bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
+ IvarSet &TrackedIvars) {
+ QualType IvQTy = Iv->getType();
+ const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
+ if (!IvTy)
+ return false;
+ const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
+
+ IvarInfo Info;
+ containsInvalidationMethod(IvInterf, Info);
+ if (Info.needsInvalidation()) {
+ TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
+ return true;
+ }
+ return false;
+}
+
+const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
+ const ObjCPropertyDecl *Prop,
+ const ObjCInterfaceDecl *InterfaceD,
+ IvarSet &TrackedIvars) {
+ const ObjCIvarDecl *IvarD = 0;
+
+ // Lookup for the synthesized case.
+ IvarD = Prop->getPropertyIvarDecl();
+ if (IvarD) {
+ if (TrackedIvars.count(IvarD)) {
+ return IvarD;
+ }
+ // If the ivar is synthesized we still want to track it.
+ if (trackIvar(IvarD, TrackedIvars))
+ return IvarD;
+ }
+
+ // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars.
+ StringRef PropName = Prop->getIdentifier()->getName();
+ for (IvarSet::const_iterator I = TrackedIvars.begin(),
+ E = TrackedIvars.end(); I != E; ++I) {
+ const ObjCIvarDecl *Iv = I->first;
+ StringRef IvarName = Iv->getName();
+
+ if (IvarName == PropName)
+ return Iv;
+
+ SmallString<128> PropNameWithUnderscore;
+ {
+ llvm::raw_svector_ostream os(PropNameWithUnderscore);
+ os << '_' << PropName;
+ }
+ if (IvarName == PropNameWithUnderscore.str())
+ return Iv;
+ }
+
+ // Note, this is a possible source of false positives. We could look at the
+ // getter implementation to find the ivar when its name is not derived from
+ // the property name.
+ return 0;
+}
+
+void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
+ AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ // We are only interested in checking the cleanup methods.
+ if (!D->hasBody() || !isInvalidationMethod(D))
+ return;
+
+ // Collect all ivars that need cleanup.
+ IvarSet Ivars;
+ const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
+
+ // Collect ivars declared in this class, its extensions and its implementation
+ ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
+ for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
+ Iv= Iv->getNextIvar())
+ trackIvar(Iv, Ivars);
+
+ // Construct Property/Property Accessor to Ivar maps to assist checking if an
+ // ivar which is backing a property has been reset.
+ MethToIvarMapTy PropSetterToIvarMap;
+ MethToIvarMapTy PropGetterToIvarMap;
+ PropToIvarMapTy PropertyToIvarMap;
+ IvarToPropMapTy IvarToPopertyMap;
+
+ ObjCInterfaceDecl::PropertyMap PropMap;
+ InterfaceD->collectPropertiesToImplement(PropMap);
+
+ for (ObjCInterfaceDecl::PropertyMap::iterator
+ I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
+ const ObjCPropertyDecl *PD = I->second;
+
+ const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars);
+ if (!ID) {
+ continue;
+ }
+
+ // Store the mappings.
+ PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
+ PropertyToIvarMap[PD] = ID;
+ IvarToPopertyMap[ID] = PD;
+
+ // Find the setter and the getter.
+ const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl();
+ if (SetterD) {
+ SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl());
+ PropSetterToIvarMap[SetterD] = ID;
+ }
+
+ const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl();
+ if (GetterD) {
+ GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl());
+ PropGetterToIvarMap[GetterD] = ID;
+ }
+ }
+
+
+ // Check which ivars have been invalidated in the method body.
+ bool CalledAnotherInvalidationMethod = false;
+ MethodCrawler(Ivars,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap,
+ BR.getContext()).VisitStmt(D->getBody());
+
+ if (CalledAnotherInvalidationMethod)
+ return;
+
+ // Warn on the ivars that were not accessed by the method.
+ for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){
+ if (!I->second.isInvalidated()) {
+ const ObjCIvarDecl *IvarDecl = I->first;
+
+ PathDiagnosticLocation IvarDecLocation =
+ PathDiagnosticLocation::createEnd(D->getBody(), BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(D));
+
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+
+ // Construct the warning message.
+ if (IvarDecl->getSynthesize()) {
+ const ObjCPropertyDecl *PD = IvarToPopertyMap[IvarDecl];
+ assert(PD &&
+ "Do we synthesize ivars for something other than properties?");
+ os << "Property "<< PD->getName() <<
+ " needs to be invalidated or set to nil";
+ } else {
+ os << "Instance variable "<< IvarDecl->getName()
+ << " needs to be invalidated or set to nil";
+ }
+
+ BR.EmitBasicReport(D,
+ "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ IvarDecLocation);
+ }
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::markInvalidated(
+ const ObjCIvarDecl *Iv) {
+ IvarSet::iterator I = IVars.find(Iv);
+ if (I != IVars.end()) {
+ // If InvalidationMethod is present, we are processing the message send and
+ // should ensure we are invalidating with the appropriate method,
+ // otherwise, we are processing setting to 'nil'.
+ if (InvalidationMethod)
+ I->second.markInvalidated(InvalidationMethod);
+ else
+ I->second.markInvalidated();
+ }
+}
+
+const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+ E = E->IgnoreParenCasts();
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ E = POE->getSyntacticForm()->IgnoreParenCasts();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ E = OVE->getSourceExpr()->IgnoreParenCasts();
+ return E;
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+ const ObjCIvarRefExpr *IvarRef) {
+ if (const Decl *D = IvarRef->getDecl())
+ markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
+ const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
+ const ObjCPropertyRefExpr *PA) {
+
+ if (PA->isExplicitProperty()) {
+ const ObjCPropertyDecl *PD = PA->getExplicitProperty();
+ if (PD) {
+ PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
+ PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD);
+ if (IvI != PropertyToIvarMap.end())
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+
+ if (PA->isImplicitProperty()) {
+ const ObjCMethodDecl *MD = PA->getImplicitPropertySetter();
+ if (MD) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD);
+ if (IvI != PropertyGetterToIvarMap.end())
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+}
+
+bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
+ E = peel(E);
+
+ return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)
+ != Expr::NPCK_NotNull);
+}
+
+void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
+ E = peel(E);
+
+ if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
+ checkObjCIvarRefExpr(IvarRef);
+ return;
+ }
+
+ if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ checkObjCPropertyRefExpr(PropRef);
+ return;
+ }
+
+ if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
+ checkObjCMessageExpr(MsgExpr);
+ return;
+ }
+}
+
+void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+ const BinaryOperator *BO) {
+ VisitStmt(BO);
+
+ if (BO->getOpcode() != BO_Assign)
+ return;
+
+ // Do we assign zero?
+ if (!isZero(BO->getRHS()))
+ return;
+
+ // Check the variable we are assigning to.
+ check(BO->getLHS());
+}
+
+void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
+ const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ const Expr *Receiver = ME->getInstanceReceiver();
+
+ // Stop if we are calling '[self invalidate]'.
+ if (Receiver && isInvalidationMethod(MD))
+ if (Receiver->isObjCSelfExpr()) {
+ CalledAnotherInvalidationMethod = true;
+ return;
+ }
+
+ // Check if we call a setter and set the property to 'nil'.
+ if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) {
+ MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
+ MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD);
+ if (IvI != PropertySetterToIvarMap.end()) {
+ markInvalidated(IvI->second);
+ return;
+ }
+ }
+
+ // Check if we call the 'invalidation' routine on the ivar.
+ if (Receiver) {
+ InvalidationMethod = MD;
+ check(Receiver->IgnoreParenCasts());
+ InvalidationMethod = 0;
+ }
+
+ VisitStmt(ME);
+}
+}
+
+// Register the checker.
+void ento::registerIvarInvalidationChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IvarInvalidationChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 969f2ddeb4ca..76f20b6e2e51 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -158,16 +158,9 @@ private:
/// ProgramState traits to store the currently allocated (and not yet freed)
/// symbols. This is a map from the allocated content symbol to the
/// corresponding AllocationState.
-typedef llvm::ImmutableMap<SymbolRef,
- MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy;
-
-namespace { struct AllocatedData {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<AllocatedData>
- : public ProgramStatePartialTrait<AllocatedSetTy > {
- static void *GDMIndex() { static int index = 0; return &index; }
-};
-}}
+REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData,
+ SymbolRef,
+ MacOSKeychainAPIChecker::AllocationState)
static bool isEnclosingFunctionParam(const Expr *E) {
E = E->IgnoreParenCasts();
@@ -282,7 +275,7 @@ void MacOSKeychainAPIChecker::
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
Report->addRange(ArgExpr->getSourceRange());
markInteresting(Report, AP);
- C.EmitReport(Report);
+ C.emitReport(Report);
}
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
@@ -323,7 +316,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addVisitor(new SecKeychainBugVisitor(V));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
}
}
return;
@@ -376,7 +369,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addRange(ArgExpr->getSourceRange());
if (AS)
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
return;
}
@@ -440,7 +433,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
- C.EmitReport(Report);
+ C.emitReport(Report);
return;
}
@@ -571,13 +564,13 @@ BugReport *MacOSKeychainAPIChecker::
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- AllocatedSetTy ASet = State->get<AllocatedData>();
+ AllocatedDataTy ASet = State->get<AllocatedData>();
if (ASet.isEmpty())
return;
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
+ for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
if (SR.isLive(I->first))
continue;
@@ -585,7 +578,9 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
State = State->remove<AllocatedData>(I->first);
// If the allocated symbol is null or if the allocation call might have
// returned an error, do not report.
- if (State->getSymVal(I->first) ||
+ ConstraintManager &CMgr = State->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey());
+ if (AllocFailed.isConstrainedTrue() ||
definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
continue;
Errors.push_back(std::make_pair(I->first, &I->second));
@@ -602,7 +597,7 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
+ C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
// Generate the new, cleaned up state.
@@ -617,7 +612,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
if (C.getLocationContext()->getParent() != 0)
return;
- AllocatedSetTy AS = state->get<AllocatedData>();
+ AllocatedDataTy AS = state->get<AllocatedData>();
if (AS.isEmpty())
return;
@@ -625,12 +620,14 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
// found here, so report it.
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
+ for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
Changed = true;
state = state->remove<AllocatedData>(I->first);
// If the allocated symbol is null or if error code was returned at
// allocation, do not report.
- if (state->getSymVal(I.getKey()) ||
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue() ||
definitelyReturnedError(I->second.Region, state,
C.getSValBuilder())) {
continue;
@@ -650,7 +647,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
+ C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
C.addTransition(state, N);
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index cfdb55df730d..467b8b1d815c 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -70,6 +70,16 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
"Mac OS X API"));
+ // Handle _dispatch_once. In some versions of the OS X SDK we have the case
+ // that dispatch_once is a macro that wraps a call to _dispatch_once.
+ // _dispatch_once is then a function which then calls the real dispatch_once.
+ // Users do not care; they just want the warning at the top-level call.
+ if (CE->getLocStart().isMacroID()) {
+ StringRef TrimmedFName = FName.ltrim("_");
+ if (TrimmedFName != FName)
+ FName = TrimmedFName;
+ }
+
SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << FName << "' uses";
@@ -84,7 +94,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
@@ -99,7 +109,9 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
SubChecker SC =
llvm::StringSwitch<SubChecker>(Name)
- .Cases("dispatch_once", "dispatch_once_f",
+ .Cases("dispatch_once",
+ "_dispatch_once",
+ "dispatch_once_f",
&MacOSXAPIChecker::CheckDispatchOnce)
.Default(NULL);
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index dfcedf640821..caf70ca3706f 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include <climits>
using namespace clang;
@@ -70,17 +71,31 @@ public:
}
};
+enum ReallocPairKind {
+ RPToBeFreedAfterFailure,
+ // The symbol has been freed when reallocation failed.
+ RPIsFreeOnFailure,
+ // The symbol does not need to be freed after reallocation fails.
+ RPDoNotTrackAfterFailure
+};
+
+/// \class ReallocPair
+/// \brief Stores information about the symbol being reallocated by a call to
+/// 'realloc' to allow modeling failed reallocation later in the path.
struct ReallocPair {
+ // \brief The symbol which realloc reallocated.
SymbolRef ReallocatedSym;
- bool IsFreeOnFailure;
- ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+ ReallocPairKind Kind;
+
+ ReallocPair(SymbolRef S, ReallocPairKind K) :
+ ReallocatedSym(S), Kind(K) {}
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(IsFreeOnFailure);
+ ID.AddInteger(Kind);
ID.AddPointer(ReallocatedSym);
}
bool operator==(const ReallocPair &X) const {
return ReallocatedSym == X.ReallocatedSym &&
- IsFreeOnFailure == X.IsFreeOnFailure;
+ Kind == X.Kind;
}
};
@@ -92,7 +107,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
check::PostStmt<BlockExpr>,
- check::PreObjCMessage,
+ check::PostObjCMessage,
check::Location,
check::Bind,
eval::Assume,
@@ -120,7 +135,7 @@ public:
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPreObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
+ void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndPath(CheckerContext &C) const;
@@ -177,11 +192,15 @@ private:
const OwnershipAttr* Att) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, unsigned Num,
- bool Hold) const;
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure = false) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg,
const Expr *ParentExpr,
- ProgramStateRef state,
- bool Hold) const;
+ ProgramStateRef State,
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure = false) const;
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure) const;
@@ -301,13 +320,14 @@ private:
: StackHintGeneratorForSymbol(S, M) {}
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << "Reallocation of ";
- // Printed parameters start at 1, not 0.
- printOrdinal(++ArgIndex, os);
- os << " parameter failed";
+ os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+ << " parameter failed";
return os.str();
}
@@ -320,25 +340,12 @@ private:
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
-class RegionState {};
-class ReallocPairs {};
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<RegionState>
- : public ProgramStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { static int x; return &x; }
- };
+REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
+REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
- template <>
- struct ProgramStateTrait<ReallocPairs>
- : public ProgramStatePartialTrait<ReallocMap> {
- static void *GDMIndex() { static int x; return &x; }
- };
-}
-}
+// A map from the freed symbol to the symbol representing the return value of
+// the free function.
+REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
namespace {
class StopTrackingCallback : public SymbolVisitor {
@@ -426,11 +433,15 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
}
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
+ if (C.wasInlined)
+ return;
+
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
ProgramStateRef State = C.getState();
+ bool ReleasedAllocatedMemory = false;
if (FD->getKind() == Decl::Function) {
initIdentifierInfo(C.getASTContext());
@@ -447,7 +458,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
} else if (FunI == II_calloc) {
State = CallocMem(C, CE);
} else if (FunI == II_free) {
- State = FreeMemAux(C, CE, State, 0, false);
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup) {
State = MallocUpdateRefState(C, CE, State);
} else if (FunI == II_strndup) {
@@ -487,21 +498,26 @@ static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
return false;
}
-void MallocChecker::checkPreObjCMessage(const ObjCMethodCall &Call,
- CheckerContext &C) const {
+void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
+ CheckerContext &C) const {
// If the first selector is dataWithBytesNoCopy, assume that the memory will
// be released with 'free' by the new object.
// Ex: [NSData dataWithBytesNoCopy:bytes length:10];
// Unless 'freeWhenDone' param set to 0.
// TODO: Check that the memory was allocated with malloc.
+ bool ReleasedAllocatedMemory = false;
Selector S = Call.getSelector();
if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithBytesNoCopy" ||
S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
!isFreeWhenDoneSetToZero(Call)){
unsigned int argIdx = 0;
- C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx),
- Call.getOriginExpr(), C.getState(), true));
+ ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx),
+ Call.getOriginExpr(), C.getState(), true,
+ ReleasedAllocatedMemory,
+ /* RetNullOnFailure*/ true);
+
+ C.addTransition(State);
}
}
@@ -526,7 +542,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// Bind the return value to the symbolic value from the heap region.
// TODO: We could rewrite post visit to eval call; 'malloc' does not have
// side effects other than what we model here.
- unsigned Count = C.getCurrentBlockCount();
+ unsigned Count = C.blockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
@@ -584,11 +600,13 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
return 0;
ProgramStateRef State = C.getState();
+ bool ReleasedAllocated = false;
for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
I != E; ++I) {
ProgramStateRef StateI = FreeMemAux(C, CE, State, *I,
- Att->getOwnKind() == OwnershipAttr::Holds);
+ Att->getOwnKind() == OwnershipAttr::Holds,
+ ReleasedAllocated);
if (StateI)
State = StateI;
}
@@ -599,20 +617,40 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const CallExpr *CE,
ProgramStateRef state,
unsigned Num,
- bool Hold) const {
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure) const {
if (CE->getNumArgs() < (Num + 1))
return 0;
- return FreeMemAux(C, CE->getArg(Num), CE, state, Hold);
+ return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
+ ReleasedAllocated, ReturnsNullOnFailure);
+}
+
+/// Checks if the previous call to free on the given symbol failed - if free
+/// failed, returns true. Also, returns the corresponding return value symbol.
+bool didPreviousFreeFail(ProgramStateRef State,
+ SymbolRef Sym, SymbolRef &RetStatusSymbol) {
+ const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
+ if (Ret) {
+ assert(*Ret && "We should not store the null return symbol");
+ ConstraintManager &CMgr = State->getConstraintManager();
+ ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);
+ RetStatusSymbol = *Ret;
+ return FreeFailed.isConstrainedTrue();
+ }
+ return false;
}
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *ArgExpr,
const Expr *ParentExpr,
- ProgramStateRef state,
- bool Hold) const {
+ ProgramStateRef State,
+ bool Hold,
+ bool &ReleasedAllocated,
+ bool ReturnsNullOnFailure) const {
- SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
+ SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
if (!isa<DefinedOrUnknownSVal>(ArgVal))
return 0;
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
@@ -623,7 +661,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// The explicit NULL case, no operation is performed.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
+ llvm::tie(notNullState, nullState) = State->assume(location);
if (nullState && !notNullState)
return 0;
@@ -672,10 +710,14 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
return 0;
SymbolRef Sym = SR->getSymbol();
- const RefState *RS = state->get<RegionState>(Sym);
+ const RefState *RS = State->get<RegionState>(Sym);
+ SymbolRef PreviousRetStatusSymbol = 0;
// Check double free.
- if (RS && (RS->isReleased() || RS->isRelinquished())) {
+ if (RS &&
+ (RS->isReleased() || RS->isRelinquished()) &&
+ !didPreviousFreeFail(State, Sym, PreviousRetStatusSymbol)) {
+
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
BT_DoubleFree.reset(
@@ -685,16 +727,34 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
"Attempt to free non-owned memory"), N);
R->addRange(ArgExpr->getSourceRange());
R->markInteresting(Sym);
+ if (PreviousRetStatusSymbol)
+ R->markInteresting(PreviousRetStatusSymbol);
R->addVisitor(new MallocBugVisitor(Sym));
- C.EmitReport(R);
+ C.emitReport(R);
}
return 0;
}
+ ReleasedAllocated = (RS != 0);
+
+ // Clean out the info on previous call to free return info.
+ State = State->remove<FreeReturnValue>(Sym);
+
+ // Keep track of the return value. If it is NULL, we will know that free
+ // failed.
+ if (ReturnsNullOnFailure) {
+ SVal RetVal = C.getSVal(ParentExpr);
+ SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
+ if (RetStatusSymbol) {
+ C.getSymbolManager().addSymbolDependency(Sym, RetStatusSymbol);
+ State = State->set<FreeReturnValue>(Sym, RetStatusSymbol);
+ }
+ }
+
// Normal free.
if (Hold)
- return state->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
- return state->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
+ return State->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
+ return State->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -714,7 +774,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
@@ -819,7 +879,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
R->markInteresting(MR);
R->addRange(range);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -886,9 +946,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
if (!FromPtr || !ToPtr)
return 0;
+ bool ReleasedAllocated = false;
+
// If the size is 0, free the memory.
if (SizeIsZero)
- if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0,
+ false, ReleasedAllocated)){
// The semantics of the return value are:
// If size was equal to 0, either NULL or a pointer suitable to be passed
// to free() is returned. We just free the input pointer and do not add
@@ -897,14 +960,25 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
}
// Default behavior.
- if (ProgramStateRef stateFree = FreeMemAux(C, CE, state, 0, false)) {
- // FIXME: We should copy the content of the original buffer.
+ if (ProgramStateRef stateFree =
+ FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) {
+
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
if (!stateRealloc)
return 0;
+
+ ReallocPairKind Kind = RPToBeFreedAfterFailure;
+ if (FreesOnFail)
+ Kind = RPIsFreeOnFailure;
+ else if (!ReleasedAllocated)
+ Kind = RPDoNotTrackAfterFailure;
+
+ // Record the info about the reallocated symbol so that we could properly
+ // process failed reallocation.
stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
- ReallocPair(FromPtr, FreesOnFail));
+ ReallocPair(FromPtr, Kind));
+ // The reallocated symbol should stay alive for as long as the new symbol.
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
return stateRealloc;
}
@@ -1004,7 +1078,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym, true));
- C.EmitReport(R);
+ C.emitReport(R);
}
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
@@ -1017,14 +1091,11 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
- bool generateReport = false;
llvm::SmallVector<SymbolRef, 2> Errors;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
- if (I->second.isAllocated()) {
- generateReport = true;
+ if (I->second.isAllocated())
Errors.push_back(I->first);
- }
// Remove the dead symbol from the map.
RS = F.remove(RS, I->first);
@@ -1032,24 +1103,34 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
// Cleanup the Realloc Pairs Map.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
if (SymReaper.isDead(I->first) ||
SymReaper.isDead(I->second.ReallocatedSym)) {
state = state->remove<ReallocPairs>(I->first);
}
}
- // Generate leak node.
- static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
+ // Cleanup the FreeReturnValue Map.
+ FreeReturnValueTy FR = state->get<FreeReturnValue>();
+ for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) {
+ if (SymReaper.isDead(I->first) ||
+ SymReaper.isDead(I->second)) {
+ state = state->remove<FreeReturnValue>(I->first);
+ }
+ }
- if (generateReport) {
+ // Generate leak node.
+ ExplodedNode *N = C.getPredecessor();
+ if (!Errors.empty()) {
+ static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
+ N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
for (llvm::SmallVector<SymbolRef, 2>::iterator
- I = Errors.begin(), E = Errors.end(); I != E; ++I) {
+ I = Errors.begin(), E = Errors.end(); I != E; ++I) {
reportLeak(*I, N, C);
}
}
+
C.addTransition(state->set<RegionState>(RS), N);
}
@@ -1182,7 +1263,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
R->addRange(S->getSourceRange());
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym));
- C.EmitReport(R);
+ C.emitReport(R);
return true;
}
}
@@ -1249,28 +1330,36 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
bool Assumption) const {
RegionStateTy RS = state->get<RegionState>();
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- // If the symbol is assumed to NULL or another constant, this will
- // return an APSInt*.
- if (state->getSymVal(I.getKey()))
+ // If the symbol is assumed to be NULL, remove it from consideration.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue())
state = state->remove<RegionState>(I.getKey());
}
// Realloc returns 0 when reallocation fails, which means that we should
// restore the state of the pointer being reallocated.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
- // If the symbol is assumed to NULL or another constant, this will
- // return an APSInt*.
- if (state->getSymVal(I.getKey())) {
- SymbolRef ReallocSym = I.getData().ReallocatedSym;
- const RefState *RS = state->get<RegionState>(ReallocSym);
- if (RS) {
- if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ // If the symbol is assumed to be NULL, remove it from consideration.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (!AllocFailed.isConstrainedTrue())
+ continue;
+
+ SymbolRef ReallocSym = I.getData().ReallocatedSym;
+ if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
+ if (RS->isReleased()) {
+ if (I.getData().Kind == RPToBeFreedAfterFailure)
state = state->set<RegionState>(ReallocSym,
- RefState::getAllocated(RS->getStmt()));
+ RefState::getAllocated(RS->getStmt()));
+ else if (I.getData().Kind == RPDoNotTrackAfterFailure)
+ state = state->remove<RegionState>(ReallocSym);
+ else
+ assert(I.getData().Kind == RPIsFreeOnFailure);
}
- state = state->remove<ReallocPairs>(I.getKey());
}
+ state = state->remove<ReallocPairs>(I.getKey());
}
return state;
@@ -1463,10 +1552,10 @@ MallocChecker::checkRegionChanges(ProgramStateRef State,
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
ProgramStateRef prevState) {
- ReallocMap currMap = currState->get<ReallocPairs>();
- ReallocMap prevMap = prevState->get<ReallocPairs>();
+ ReallocPairsTy currMap = currState->get<ReallocPairs>();
+ ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
- for (ReallocMap::iterator I = prevMap.begin(), E = prevMap.end();
+ for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end();
I != E; ++I) {
SymbolRef sym = I.getKey();
if (!currMap.lookup(sym))
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index 6292a4725128..fb40f222b846 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -146,9 +146,9 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
if (const PointerType *ptrA = A->getAs<PointerType>())
if (const PointerType *ptrB = B->getAs<PointerType>()) {
- A = ptrA->getPointeeType();
- B = ptrB->getPointeeType();
- continue;
+ A = ptrA->getPointeeType();
+ B = ptrB->getPointeeType();
+ continue;
}
break;
@@ -157,6 +157,18 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
return false;
}
+static bool compatibleWithArrayType(ASTContext &C, QualType PT, QualType T) {
+ // Ex: 'int a[10][2]' is compatible with 'int', 'int[2]', 'int[10][2]'.
+ while (const ArrayType *AT = T->getAsArrayTypeUnsafe()) {
+ QualType ElemType = AT->getElementType();
+ if (typesCompatible(C, PT, AT->getElementType()))
+ return true;
+ T = ElemType;
+ }
+
+ return false;
+}
+
class MallocSizeofChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
@@ -184,38 +196,49 @@ public:
continue;
QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument();
- if (!typesCompatible(BR.getContext(), PointeeType, SizeofType)) {
- const TypeSourceInfo *TSI = 0;
- if (i->CastedExprParent.is<const VarDecl *>()) {
- TSI =
+
+ if (typesCompatible(BR.getContext(), PointeeType, SizeofType))
+ continue;
+
+ // If the argument to sizeof is an array, the result could be a
+ // pointer to any array element.
+ if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType))
+ continue;
+
+ const TypeSourceInfo *TSI = 0;
+ if (i->CastedExprParent.is<const VarDecl *>()) {
+ TSI =
i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo();
- } else {
- TSI = i->ExplicitCastType;
- }
-
- SmallString<64> buf;
- llvm::raw_svector_ostream OS(buf);
-
- OS << "Result of '"
- << i->AllocCall->getDirectCallee()->getIdentifier()->getName()
- << "' is converted to a pointer of type '"
- << PointeeType.getAsString() << "', which is incompatible with "
- << "sizeof operand type '" << SizeofType.getAsString() << "'";
- llvm::SmallVector<SourceRange, 4> Ranges;
- Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
- Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
- if (TSI)
- Ranges.push_back(TSI->getTypeLoc().getSourceRange());
-
- PathDiagnosticLocation L =
+ } else {
+ TSI = i->ExplicitCastType;
+ }
+
+ SmallString<64> buf;
+ llvm::raw_svector_ostream OS(buf);
+
+ OS << "Result of ";
+ const FunctionDecl *Callee = i->AllocCall->getDirectCallee();
+ if (Callee && Callee->getIdentifier())
+ OS << '\'' << Callee->getIdentifier()->getName() << '\'';
+ else
+ OS << "call";
+ OS << " is converted to a pointer of type '"
+ << PointeeType.getAsString() << "', which is incompatible with "
+ << "sizeof operand type '" << SizeofType.getAsString() << "'";
+ llvm::SmallVector<SourceRange, 4> Ranges;
+ Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
+ Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
+ if (TSI)
+ Ranges.push_back(TSI->getTypeLoc().getSourceRange());
+
+ PathDiagnosticLocation L =
PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(),
- BR.getSourceManager(), ADC);
+ BR.getSourceManager(), ADC);
- BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
- categories::UnixAPI,
- OS.str(),
- L, Ranges.data(), Ranges.size());
- }
+ BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
+ categories::UnixAPI,
+ OS.str(),
+ L, Ranges.data(), Ranges.size());
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index aad3b0f5f277..3331bc8a9a8d 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -71,7 +71,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when "
"using NSAutoreleasePool and garbage collection", N);
Report->addRange(msg.getSourceRange());
- C.EmitReport(Report);
+ C.emitReport(Report);
}
void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index f826573c9ecb..7a66ec3a934f 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -163,23 +163,9 @@ public:
};
}
-namespace { struct NSErrorOut {}; }
-namespace { struct CFErrorOut {}; }
-
typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
-
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<NSErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
- template <>
- struct ProgramStateTrait<CFErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-}
-}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag)
template <typename T>
static bool hasFlag(SVal val, ProgramStateRef state) {
@@ -285,7 +271,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
bug = new CFErrorDerefBug();
BugReport *report = new BugReport(*bug, os.str(),
event.SinkNode);
- BR.EmitReport(report);
+ BR.emitReport(report);
}
static bool IsNSError(QualType T, IdentifierInfo *II) {
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
deleted file mode 100644
index 7b724d2be9b7..000000000000
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker evaluates OSAtomic functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/Basic/Builtins.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class OSAtomicChecker : public Checker<eval::InlineCall> {
-public:
- bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
-
-private:
- bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const;
-};
-}
-
-static StringRef getCalleeName(ProgramStateRef State,
- const CallExpr *CE,
- const LocationContext *LCtx) {
- const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee, LCtx);
- const FunctionDecl *funDecl = L.getAsFunctionDecl();
- if (!funDecl)
- return StringRef();
- IdentifierInfo *funI = funDecl->getIdentifier();
- if (!funI)
- return StringRef();
- return funI->getName();
-}
-
-bool OSAtomicChecker::inlineCall(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const {
- StringRef FName = getCalleeName(Pred->getState(),
- CE, Pred->getLocationContext());
- if (FName.empty())
- return false;
-
- // Check for compare and swap.
- if (FName.startswith("OSAtomicCompareAndSwap") ||
- FName.startswith("objc_atomicCompareAndSwap"))
- return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
-
- // FIXME: Other atomics.
- return false;
-}
-
-bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
- ExprEngine &Eng,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) const {
- // Not enough arguments to match OSAtomicCompareAndSwap?
- if (CE->getNumArgs() != 3)
- return false;
-
- ASTContext &Ctx = Eng.getContext();
- const Expr *oldValueExpr = CE->getArg(0);
- QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
-
- const Expr *newValueExpr = CE->getArg(1);
- QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
-
- // Do the types of 'oldValue' and 'newValue' match?
- if (oldValueType != newValueType)
- return false;
-
- const Expr *theValueExpr = CE->getArg(2);
- const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
-
- // theValueType not a pointer?
- if (!theValueType)
- return false;
-
- QualType theValueTypePointee =
- Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
-
- // The pointee must match newValueType and oldValueType.
- if (theValueTypePointee != newValueType)
- return false;
-
- static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
- static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
-
- // Load 'theValue'.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr, LCtx);
- // Here we should use the value type of the region as the load type, because
- // we are simulating the semantics of the function, not the semantics of
- // passing argument. So the type of theValue expr is not we are loading.
- // But usually the type of the varregion is not the type we want either,
- // we still need to do a CastRetrievedVal in store manager. So actually this
- // LoadTy specifying can be omitted. But we put it here to emphasize the
- // semantics.
- QualType LoadTy;
- if (const TypedValueRegion *TR =
- dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
- LoadTy = TR->getValueType();
- }
- Eng.evalLoad(Tmp, CE, theValueExpr, Pred,
- state, location, &OSAtomicLoadTag, LoadTy);
-
- if (Tmp.empty()) {
- // If no nodes were generated, other checkers must have generated sinks.
- // We return an empty Dst.
- return true;
- }
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
- I != E; ++I) {
-
- ExplodedNode *N = *I;
- ProgramStateRef stateLoad = N->getState();
-
- // Use direct bindings from the environment since we are forcing a load
- // from a location that the Environment would typically not be used
- // to bind a value.
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
-
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
-
- // FIXME: Issue an error.
- if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
- return false;
- }
-
- DefinedOrUnknownSVal theValueVal =
- cast<DefinedOrUnknownSVal>(theValueVal_untested);
- DefinedOrUnknownSVal oldValueVal =
- cast<DefinedOrUnknownSVal>(oldValueVal_untested);
-
- SValBuilder &svalBuilder = Eng.getSValBuilder();
-
- // Perform the comparison.
- DefinedOrUnknownSVal Cmp =
- svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
-
- ProgramStateRef stateEqual = stateLoad->assume(Cmp, true);
-
- // Were they equal?
- if (stateEqual) {
- // Perform the store.
- ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr, LCtx);
-
- // Handle implicit value casts.
- if (const TypedValueRegion *R =
- dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
- val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
- }
-
- Eng.evalStore(TmpStore, CE, theValueExpr, N,
- stateEqual, location, val, &OSAtomicStoreTag);
-
- if (TmpStore.empty()) {
- // If no nodes were generated, other checkers must have generated sinks.
- // We return an empty Dst.
- return true;
- }
-
- StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
- // Now bind the result of the comparison.
- for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
- E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode *predNew = *I2;
- ProgramStateRef stateNew = predNew->getState();
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Eng.getSValBuilder().makeTruthVal(true, T);
- B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
- false, this);
- }
- }
-
- // Were they not equal?
- if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) {
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
- StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
- B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
- false, this);
- }
- }
-
- return true;
-}
-
-void ento::registerOSAtomicChecker(CheckerManager &mgr) {
- mgr.registerChecker<OSAtomicChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 4cc92ce9e958..9d84f52f934e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -18,7 +18,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -50,8 +49,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
"for @synchronized"));
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
+ C.emitReport(report);
}
return;
}
@@ -73,9 +72,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
"(no synchronization will occur)"));
BugReport *report =
new BugReport(*BT_null, BT_null->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index f2929c03cc0b..63a84805e73e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -31,8 +31,6 @@ class WalkAST : public StmtVisitor<WalkAST> {
ASTContext &ASTC;
uint64_t PtrWidth;
- static const unsigned InvalidArgIndex = UINT_MAX;
-
/// Check if the type has pointer size (very conservative).
inline bool isPointerSize(const Type *T) {
if (!T)
@@ -102,16 +100,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
return;
const Expr *Arg = 0;
- unsigned ArgNum = InvalidArgIndex;
+ unsigned ArgNum;
if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
+ if (CE->getNumArgs() != 4)
+ return;
ArgNum = 1;
Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
if (hasPointerToPointerSizedType(Arg))
return;
- }
-
- if (Arg == 0 && Name.equals("CFDictionaryCreate")) {
+ } else if (Name.equals("CFDictionaryCreate")) {
+ if (CE->getNumArgs() != 6)
+ return;
// Check first argument.
ArgNum = 1;
Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
@@ -125,17 +125,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
}
}
- if (ArgNum != InvalidArgIndex) {
+ if (Arg) {
assert(ArgNum == 1 || ArgNum == 2);
- SmallString<256> BufName;
+ SmallString<64> BufName;
llvm::raw_svector_ostream OsName(BufName);
- assert(ArgNum == 1 || ArgNum == 2);
OsName << " Invalid use of '" << Name << "'" ;
SmallString<256> Buf;
llvm::raw_svector_ostream Os(Buf);
- Os << " The "<< ((ArgNum == 1) ? "first" : "second") << " argument to '"
+ // Use "second" and "third" since users will expect 1-based indexing
+ // for parameter names when mentioned in prose.
+ Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '"
<< Name << "' must be a C array of pointer-sized values, not '"
<< Arg->getType().getAsString() << "'";
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 2ab49ed12a14..999c994cb1c6 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -55,16 +55,8 @@ public:
};
} // end anonymous namespace
-// ProgramState trait - a map from array symbol to it's state.
-typedef llvm::ImmutableMap<SymbolRef, DefinedSVal> ArraySizeM;
-
-namespace { struct ArraySizeMap {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<ArraySizeMap>
- : public ProgramStatePartialTrait<ArraySizeM > {
- static void *GDMIndex() { return ObjCContainersChecker::getTag(); }
-};
-}}
+// ProgramState trait - a map from array symbol to its state.
+REGISTER_MAP_WITH_PROGRAMSTATE(ArraySizeMap, SymbolRef, DefinedSVal)
void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
CheckerContext &C) const {
@@ -146,7 +138,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
initBugType();
BugReport *R = new BugReport(*BT, "Index is out of bounds", N);
R->addRange(IdxExpr->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
return;
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
new file mode 100644
index 000000000000..e906e8aa3016
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -0,0 +1,203 @@
+//==- ObjCMissingSuperCallChecker.cpp - Check missing super-calls in ObjC --==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a ObjCMissingSuperCallChecker, a checker that
+// analyzes a UIViewController implementation to determine if it
+// correctly calls super in the methods where this is mandatory.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+static bool isUIViewControllerSubclass(ASTContext &Ctx,
+ const ObjCImplementationDecl *D) {
+ IdentifierInfo *ViewControllerII = &Ctx.Idents.get("UIViewController");
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
+
+ for ( ; ID; ID = ID->getSuperClass())
+ if (ID->getIdentifier() == ViewControllerII)
+ return true;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// FindSuperCallVisitor - Identify specific calls to the superclass.
+//===----------------------------------------------------------------------===//
+
+class FindSuperCallVisitor : public RecursiveASTVisitor<FindSuperCallVisitor> {
+public:
+ explicit FindSuperCallVisitor(Selector S) : DoesCallSuper(false), Sel(S) {}
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getSelector() == Sel)
+ if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
+ DoesCallSuper = true;
+
+ // Recurse if we didn't find the super call yet.
+ return !DoesCallSuper;
+ }
+
+ bool DoesCallSuper;
+
+private:
+ Selector Sel;
+};
+
+//===----------------------------------------------------------------------===//
+// ObjCSuperCallChecker
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ObjCSuperCallChecker : public Checker<
+ check::ASTDecl<ObjCImplementationDecl> > {
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
+ BugReporter &BR) const;
+};
+}
+
+void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
+ AnalysisManager &Mgr,
+ BugReporter &BR) const {
+ ASTContext &Ctx = BR.getContext();
+
+ if (!isUIViewControllerSubclass(Ctx, D))
+ return;
+
+ const char *SelectorNames[] =
+ {"addChildViewController", "viewDidAppear", "viewDidDisappear",
+ "viewWillAppear", "viewWillDisappear", "removeFromParentViewController",
+ "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload",
+ "viewDidLoad"};
+ const unsigned SelectorArgumentCounts[] =
+ {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
+ const size_t SelectorCount = llvm::array_lengthof(SelectorNames);
+ assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount);
+
+ // Fill the Selectors SmallSet with all selectors we want to check.
+ llvm::SmallSet<Selector, 16> Selectors;
+ for (size_t i = 0; i < SelectorCount; i++) {
+ unsigned ArgumentCount = SelectorArgumentCounts[i];
+ const char *SelectorCString = SelectorNames[i];
+
+ // Get the selector.
+ IdentifierInfo *II = &Ctx.Idents.get(SelectorCString);
+ Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II));
+ }
+
+ // Iterate over all instance methods.
+ for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
+ E = D->instmeth_end();
+ I != E; ++I) {
+ Selector S = (*I)->getSelector();
+ // Find out whether this is a selector that we want to check.
+ if (!Selectors.count(S))
+ continue;
+
+ ObjCMethodDecl *MD = *I;
+
+ // Check if the method calls its superclass implementation.
+ if (MD->getBody())
+ {
+ FindSuperCallVisitor Visitor(S);
+ Visitor.TraverseDecl(MD);
+
+ // It doesn't call super, emit a diagnostic.
+ if (!Visitor.DoesCallSuper) {
+ PathDiagnosticLocation DLoc =
+ PathDiagnosticLocation::createEnd(MD->getBody(),
+ BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(D));
+
+ const char *Name = "Missing call to superclass";
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream os(Buf);
+
+ os << "The '" << S.getAsString()
+ << "' instance method in UIViewController subclass '" << *D
+ << "' is missing a [super " << S.getAsString() << "] call";
+
+ BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
+ os.str(), DLoc);
+ }
+ }
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<ObjCSuperCallChecker>();
+}
+
+
+/*
+ ToDo list for expanding this check in the future, the list is not exhaustive.
+ There are also cases where calling super is suggested but not "mandatory".
+ In addition to be able to check the classes and methods below, architectural
+ improvements like being able to allow for the super-call to be done in a called
+ method would be good too.
+
+*** trivial cases:
+UIResponder subclasses
+- resignFirstResponder
+
+NSResponder subclasses
+- cursorUpdate
+
+*** more difficult cases:
+
+UIDocument subclasses
+- finishedHandlingError:recovered: (is multi-arg)
+- finishedHandlingError:recovered: (is multi-arg)
+
+UIViewController subclasses
+- loadView (should *never* call super)
+- transitionFromViewController:toViewController:
+ duration:options:animations:completion: (is multi-arg)
+
+UICollectionViewController subclasses
+- loadView (take care because UIViewController subclasses should NOT call super
+ in loadView, but UICollectionViewController subclasses should)
+
+NSObject subclasses
+- doesNotRecognizeSelector (it only has to call super if it doesn't throw)
+
+UIPopoverBackgroundView subclasses (some of those are class methods)
+- arrowDirection (should *never* call super)
+- arrowOffset (should *never* call super)
+- arrowBase (should *never* call super)
+- arrowHeight (should *never* call super)
+- contentViewInsets (should *never* call super)
+
+UITextSelectionRect subclasses (some of those are properties)
+- rect (should *never* call super)
+- range (should *never* call super)
+- writingDirection (should *never* call super)
+- isVertical (should *never* call super)
+- containsStart (should *never* call super)
+- containsEnd (should *never* call super)
+*/
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index be45da1be066..98d2a85ace36 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -72,6 +72,8 @@ public:
void checkPreCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
+ void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const;
};
} // end anonymous namespace
@@ -97,31 +99,14 @@ enum SelfFlagEnum {
};
}
-typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
-namespace { struct CalledInit {}; }
-namespace { struct PreCallSelfFlags {}; }
-
-namespace clang {
-namespace ento {
- template<>
- struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
- template <>
- struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-
- /// \brief A call receiving a reference to 'self' invalidates the object that
- /// 'self' contains. This keeps the "self flags" assigned to the 'self'
- /// object before the call so we can assign them to the new object that 'self'
- /// points to after the call.
- template <>
- struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> {
- static void *GDMIndex() { static int index = 0; return &index; }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool)
+
+/// \brief A call receiving a reference to 'self' invalidates the object that
+/// 'self' contains. This keeps the "self flags" assigned to the 'self'
+/// object before the call so we can assign them to the new object that 'self'
+/// points to after the call.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned)
static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) {
if (SymbolRef sym = val.getAsSymbol())
@@ -138,7 +123,8 @@ static void addSelfFlag(ProgramStateRef state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
- C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag));
+ state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag);
+ C.addTransition(state);
}
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
@@ -176,7 +162,7 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
BugReport *report =
new BugReport(*new InitSelfBug(), errorStr, N);
- C.EmitReport(report);
+ C.emitReport(report);
}
void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
@@ -305,13 +291,12 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
// returns 'self'. So assign the flags, which were set on 'self' to the
// return value.
// EX: self = performMoreInitialization(self)
- const Expr *CallExpr = CE.getOriginExpr();
- if (CallExpr)
- addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()),
- prevFlags, C);
+ addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
return;
}
}
+
+ C.addTransition(state);
}
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
@@ -346,6 +331,53 @@ void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
}
}
+void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+ SelfFlagTy FlagMap = State->get<SelfFlag>();
+ bool DidCallInit = State->get<CalledInit>();
+ SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>();
+
+ if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
+ return;
+
+ Out << Sep << NL << "ObjCSelfInitChecker:" << NL;
+
+ if (DidCallInit)
+ Out << " An init method has been called." << NL;
+
+ if (PreCallFlags != SelfFlag_None) {
+ if (PreCallFlags & SelfFlag_Self) {
+ Out << " An argument of the current call came from the 'self' variable."
+ << NL;
+ }
+ if (PreCallFlags & SelfFlag_InitRes) {
+ Out << " An argument of the current call came from an init method."
+ << NL;
+ }
+ }
+
+ Out << NL;
+ for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end();
+ I != E; ++I) {
+ Out << I->first << " : ";
+
+ if (I->second == SelfFlag_None)
+ Out << "none";
+
+ if (I->second & SelfFlag_Self)
+ Out << "self variable";
+
+ if (I->second & SelfFlag_InitRes) {
+ if (I->second != SelfFlag_InitRes)
+ Out << " | ";
+ Out << "result of init method";
+ }
+
+ Out << NL;
+ }
+}
+
+
// FIXME: A callback should disable checkers at the start of functions.
static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
if (!ND)
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index fe4845bd8894..b5d9959b8531 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -59,7 +59,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
"dangerous."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index fa5c6a30a683..47da87f0bcc6 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -67,7 +67,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
"the same memory chunk may cause incorrect result."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
- C.EmitReport(R);
+ C.emitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 2d018ef9264d..d9b638469525 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -43,15 +43,7 @@ public:
} // end anonymous namespace
// GDM Entry for tracking lock state.
-namespace { class LockSet {}; }
-namespace clang {
-namespace ento {
-template <> struct ProgramStateTrait<LockSet> :
- public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > {
- static void *GDMIndex() { static int x = 0; return &x; }
-};
-} // end of ento (ProgramState) namespace
-} // end clang namespace
+REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
@@ -118,7 +110,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
"This lock has already "
"been acquired", N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
@@ -163,7 +155,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
- llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>();
+ LockSetTy LS = state->get<LockSet>();
// FIXME: Better analysis requires IPA for wrappers.
// FIXME: check for double unlocks
@@ -183,7 +175,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
"Possible lock order "
"reversal", N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 3c00d9915b4a..304051c1394c 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -40,24 +40,6 @@ using namespace clang;
using namespace ento;
using llvm::StrInStrNoCase;
-namespace {
-/// Wrapper around different kinds of node builder, so that helper functions
-/// can have a common interface.
-class GenericNodeBuilderRefCount {
- CheckerContext *C;
- const ProgramPointTag *tag;
-public:
- GenericNodeBuilderRefCount(CheckerContext &c,
- const ProgramPointTag *t = 0)
- : C(&c), tag(t){}
-
- ExplodedNode *MakeNode(ProgramStateRef state, ExplodedNode *Pred,
- bool MarkAsSink = false) {
- return C->addTransition(state, Pred, tag, MarkAsSink);
- }
-};
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//
@@ -66,9 +48,23 @@ public:
/// particular argument.
enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
DecRefBridgedTransfered,
- DecRefAndStopTracking, DecRefMsgAndStopTracking,
IncRefMsg, IncRef, MakeCollectable, MayEscape,
- NewAutoreleasePool, StopTracking };
+ NewAutoreleasePool,
+
+ // 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> {
@@ -90,7 +86,13 @@ class RetEffect {
public:
enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
- OwnedWhenTrackedReceiver };
+ 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 };
@@ -133,6 +135,9 @@ public:
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
+ static RetEffect MakeNoRetHard() {
+ return RetEffect(NoRetHard);
+ }
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned) K);
@@ -337,20 +342,7 @@ void RefVal::print(raw_ostream &Out) const {
// RefBindings - State used to track object reference counts.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<RefBindings>
- : public ProgramStatePartialTrait<RefBindings> {
- static void *GDMIndex() {
- static int RefBIndex = 0;
- return &RefBIndex;
- }
-};
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
static inline const RefVal *getRefBinding(ProgramStateRef State,
SymbolRef Sym) {
@@ -893,7 +885,7 @@ static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
return FName.find("MakeCollectable") != StringRef::npos;
}
-static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
+static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
switch (E) {
case DoNothing:
case Autorelease:
@@ -904,13 +896,14 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
case MayEscape:
case NewAutoreleasePool:
case StopTracking:
- return StopTracking;
+ case StopTrackingHard:
+ return StopTrackingHard;
case DecRef:
- case DecRefAndStopTracking:
- return DecRefAndStopTracking;
+ case DecRefAndStopTrackingHard:
+ return DecRefAndStopTrackingHard;
case DecRefMsg:
- case DecRefMsgAndStopTracking:
- return DecRefMsgAndStopTracking;
+ case DecRefMsgAndStopTrackingHard:
+ return DecRefMsgAndStopTrackingHard;
case Dealloc:
return Dealloc;
}
@@ -921,33 +914,65 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) {
void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
const CallEvent &Call) {
if (Call.hasNonZeroCallbackArg()) {
- ArgEffect RecEffect = getStopTrackingEquivalent(S->getReceiverEffect());
- ArgEffect DefEffect = getStopTrackingEquivalent(S->getDefaultArgEffect());
+ ArgEffect RecEffect =
+ getStopTrackingHardEquivalent(S->getReceiverEffect());
+ ArgEffect DefEffect =
+ getStopTrackingHardEquivalent(S->getDefaultArgEffect());
ArgEffects CustomArgEffects = S->getArgEffects();
for (ArgEffects::iterator I = CustomArgEffects.begin(),
E = CustomArgEffects.end();
I != E; ++I) {
- ArgEffect Translated = getStopTrackingEquivalent(I->second);
+ ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
if (Translated != DefEffect)
ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
}
- RetEffect RE = RetEffect::MakeNoRet();
+ RetEffect RE = RetEffect::MakeNoRetHard();
// Special cases where the callback argument CANNOT free the return value.
// This can generally only happen if we know that the callback will only be
// called when the return value is already being deallocated.
if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) {
- IdentifierInfo *Name = FC->getDecl()->getIdentifier();
-
- // This callback frees the associated buffer.
- if (Name->isStr("CGBitmapContextCreateWithData"))
- RE = S->getRetEffect();
+ if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
+ // When the CGBitmapContext is deallocated, the callback here will free
+ // the associated data buffer.
+ if (Name->isStr("CGBitmapContextCreateWithData"))
+ RE = S->getRetEffect();
+ }
}
S = getPersistentSummary(RE, RecEffect, DefEffect);
}
+
+ // Special case '[super init];' and '[self init];'
+ //
+ // Even though calling '[super init]' without assigning the result to self
+ // and checking if the parent returns 'nil' is a bad pattern, it is common.
+ // Additionally, our Self Init checker already warns about it. To avoid
+ // overwhelming the user with messages from both checkers, we model the case
+ // of '[super init]' in cases when it is not consumed by another expression
+ // as if the call preserves the value of 'self'; essentially, assuming it can
+ // never fail and return 'nil'.
+ // Note, we don't want to just stop tracking the value since we want the
+ // RetainCount checker to report leaks and use-after-free if SelfInit checker
+ // is turned off.
+ if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) {
+ if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) {
+
+ // Check if the message is not consumed, we know it will not be used in
+ // an assignment, ex: "self = [super init]".
+ const Expr *ME = MC->getOriginExpr();
+ const LocationContext *LCtx = MC->getLocationContext();
+ ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap();
+ if (!PM.isConsumedExpr(ME)) {
+ RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
+ ModifiableSummaryTemplate->setReceiverEffect(DoNothing);
+ ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
+ }
+ }
+
+ }
}
const RetainSummary *
@@ -1036,6 +1061,8 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// The headers on OS X 10.8 use cf_consumed/ns_returns_retained,
// but we can fully model NSMakeCollectable ourselves.
AllowAnnotations = false;
+ } else if (FName == "CFPlugInInstanceCreate") {
+ S = getPersistentSummary(RetEffect::MakeNoRet());
} else if (FName == "IOBSDNameMatching" ||
FName == "IOServiceMatching" ||
FName == "IOServiceNameMatching" ||
@@ -1108,6 +1135,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
if (RetTy->isPointerType()) {
+ if (FD->getAttr<CFAuditedTransferAttr>()) {
+ S = getCFCreateGetRuleSummary(FD);
+ break;
+ }
+
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
@@ -1347,22 +1379,6 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const RetainSummary *
RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy) {
-
- if (MD) {
- // Scan the method decl for 'void*' arguments. These should be treated
- // as 'StopTracking' because they are often used with delegates.
- // Delegates are a frequent form of false positives with the retain
- // count checker.
- unsigned i = 0;
- for (ObjCMethodDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I, ++i)
- if (const ParmVarDecl *PD = *I) {
- QualType Ty = Ctx.getCanonicalType(PD->getType());
- if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
- ScratchArgs = AF.add(ScratchArgs, i, StopTracking);
- }
- }
-
// Any special effects?
ArgEffect ReceiverEff = DoNothing;
RetEffect ResultEff = RetEffect::MakeNoRet();
@@ -1441,9 +1457,9 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
StringRef Slot = S.getNameForSlot(i);
if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) {
if (ResultEff == ObjCInitRetE)
- ResultEff = RetEffect::MakeNoRet();
+ ResultEff = RetEffect::MakeNoRetHard();
else
- ReceiverEff = StopTracking;
+ ReceiverEff = StopTrackingHard;
}
}
}
@@ -2174,6 +2190,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
// If allocation happened in a function different from the leak node context,
// do not report the binding.
+ assert(N && "Could not find allocation node");
if (N->getLocationContext() != LeakContext) {
FirstBinding = 0;
}
@@ -2229,27 +2246,36 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
// Get the retain count.
const RefVal* RV = getRefBinding(EndN->getState(), Sym);
+ assert(RV);
if (RV->getKind() == RefVal::ErrorLeakReturned) {
// FIXME: Per comments in rdar://6320065, "create" only applies to CF
// objects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects.
const Decl *D = &EndN->getCodeDecl();
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- os << " is returned from a method whose name ('"
- << MD->getSelector().getAsString()
- << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
- " This violates the naming convention rules"
- " given in the Memory Management Guide for Cocoa";
- }
+
+ os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
+ : " is returned from a function ");
+
+ if (D->getAttr<CFReturnsNotRetainedAttr>())
+ os << "that is annotated as CF_RETURNS_NOT_RETAINED";
+ else if (D->getAttr<NSReturnsNotRetainedAttr>())
+ os << "that is annotated as NS_RETURNS_NOT_RETAINED";
else {
- const FunctionDecl *FD = cast<FunctionDecl>(D);
- os << " is returned from a function whose name ('"
- << *FD
- << "') does not contain 'Copy' or 'Create'. This violates the naming"
- " convention rules given in the Memory Management Guide for Core"
- " Foundation";
- }
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ os << "whose name ('" << MD->getSelector().getAsString()
+ << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
+ " This violates the naming convention rules"
+ " given in the Memory Management Guide for Cocoa";
+ }
+ else {
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ os << "whose name ('" << *FD
+ << "') does not contain 'Copy' or 'Create'. This violates the naming"
+ " convention rules given in the Memory Management Guide for Core"
+ " Foundation";
+ }
+ }
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
@@ -2474,6 +2500,10 @@ public:
void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
CheckerContext &C) const;
+ void processSummaryOfInlined(const RetainSummary &Summ,
+ const CallEvent &Call,
+ CheckerContext &C) const;
+
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
@@ -2499,8 +2529,8 @@ public:
void checkEndPath(CheckerContext &C) const;
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
- RefVal V, ArgEffect E, RefVal::Kind &hasErr,
- CheckerContext &C) const;
+ RefVal V, ArgEffect E, RefVal::Kind &hasErr,
+ CheckerContext &C) const;
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym,
@@ -2515,13 +2545,12 @@ public:
SmallVectorImpl<SymbolRef> &Leaked) const;
std::pair<ExplodedNode *, ProgramStateRef >
- handleAutoreleaseCounts(ProgramStateRef state,
- GenericNodeBuilderRefCount Bd, ExplodedNode *Pred,
- CheckerContext &Ctx, SymbolRef Sym, RefVal V) const;
+ handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
+ const ProgramPointTag *Tag, CheckerContext &Ctx,
+ SymbolRef Sym, RefVal V) const;
ExplodedNode *processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
CheckerContext &Ctx,
ExplodedNode *Pred = 0) const;
};
@@ -2685,11 +2714,13 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
void RetainCountChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- if (C.wasInlined)
- return;
-
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ = Summaries.getSummary(Call, C.getState());
+
+ if (C.wasInlined) {
+ processSummaryOfInlined(*Summ, Call, C);
+ return;
+ }
checkSummary(*Summ, Call, C);
}
@@ -2721,6 +2752,45 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
+// We don't always get the exact modeling of the function with regards to the
+// retain count checker even when the function is inlined. For example, we need
+// to stop tracking the symbols which were marked with StopTrackingHard.
+void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
+ const CallEvent &CallOrMsg,
+ CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+
+ // Evaluate the effect of the arguments.
+ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
+ if (Summ.getArg(idx) == StopTrackingHard) {
+ SVal V = CallOrMsg.getArgSVal(idx);
+ if (SymbolRef Sym = V.getAsLocSymbol()) {
+ state = removeRefBinding(state, Sym);
+ }
+ }
+ }
+
+ // Evaluate the effect on the message receiver.
+ const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg);
+ if (MsgInvocation) {
+ if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
+ if (Summ.getReceiverEffect() == StopTrackingHard) {
+ state = removeRefBinding(state, Sym);
+ }
+ }
+ }
+
+ // Consult the summary for the return value.
+ RetEffect RE = Summ.getRetEffect();
+ if (RE.getKind() == RetEffect::NoRetHard) {
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
+ if (Sym)
+ state = removeRefBinding(state, Sym);
+ }
+
+ C.addTransition(state);
+}
+
void RetainCountChecker::checkSummary(const RetainSummary &Summ,
const CallEvent &CallOrMsg,
CheckerContext &C) const {
@@ -2755,7 +2825,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
if (const RefVal *T = getRefBinding(state, Sym)) {
ReceiverIsTracked = true;
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
- hasErr, C);
+ hasErr, C);
if (hasErr) {
ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
ErrorSym = Sym;
@@ -2786,13 +2856,13 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
llvm_unreachable("Unhandled RetEffect.");
case RetEffect::NoRet:
+ case RetEffect::NoRetHard:
// No work necessary.
break;
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
- SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
- C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
@@ -2811,10 +2881,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
- SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
-
+ assert(Ex);
// Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
QualType ResultTy = GetReturnType(Ex, C.getASTContext());
state = setRefBinding(state, Sym, RefVal::makeNotOwned(RE.getObjKind(),
@@ -2864,8 +2934,8 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRefMsg:
E = IgnoreRetainMsg ? DoNothing : DecRef;
break;
- case DecRefMsgAndStopTracking:
- E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTracking;
+ case DecRefMsgAndStopTrackingHard:
+ E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTrackingHard;
break;
case MakeCollectable:
E = C.isObjCGCEnabled() ? DecRef : DoNothing;
@@ -2886,7 +2956,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRefMsg:
case IncRefMsg:
case MakeCollectable:
- case DecRefMsgAndStopTracking:
+ case DecRefMsgAndStopTrackingHard:
llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
case Dealloc:
@@ -2935,6 +3005,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
break;
case StopTracking:
+ case StopTrackingHard:
return removeRefBinding(state, sym);
case IncRef:
@@ -2955,7 +3026,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case DecRef:
case DecRefBridgedTransfered:
- case DecRefAndStopTracking:
+ case DecRefAndStopTrackingHard:
switch (V.getKind()) {
default:
// case 'RefVal::Released' handled above.
@@ -2966,7 +3037,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
if (V.getCount() == 1)
V = V ^ (E == DecRefBridgedTransfered ?
RefVal::NotOwned : RefVal::Released);
- else if (E == DecRefAndStopTracking)
+ else if (E == DecRefAndStopTrackingHard)
return removeRefBinding(state, sym);
V = V - 1;
@@ -2974,7 +3045,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case RefVal::NotOwned:
if (V.getCount() > 0) {
- if (E == DecRefAndStopTracking)
+ if (E == DecRefAndStopTrackingHard)
return removeRefBinding(state, sym);
V = V - 1;
} else {
@@ -3035,7 +3106,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
C.isObjCGCEnabled(), SummaryLog,
N, Sym);
report->addRange(ErrorRange);
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
@@ -3090,8 +3161,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (RetVal.isUnknown()) {
// If the receiver is unknown, conjure a return value.
SValBuilder &SVB = C.getSValBuilder();
- unsigned Count = C.getCurrentBlockCount();
- RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
+ RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount());
}
state = state->BindExpr(CE, LCtx, RetVal, false);
@@ -3105,8 +3175,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- unsigned Count = C.getCurrentBlockCount();
- state = state->invalidateRegions(ArgRegion, CE, Count, LCtx);
+ state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx);
// Restore the refcount status of the argument.
if (Binding)
@@ -3121,12 +3190,6 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Handle return statements.
//===----------------------------------------------------------------------===//
-// Return true if the current LocationContext has no caller context.
-static bool inTopFrame(CheckerContext &C) {
- const LocationContext *LC = C.getLocationContext();
- return LC->getParent() == 0;
-}
-
void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
CheckerContext &C) const {
@@ -3135,7 +3198,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// better checking even for inlined calls, and see if they match
// with their expected semantics (e.g., the method should return a retained
// object, etc.).
- if (!inTopFrame(C))
+ if (!C.inTopFrame())
return;
const Expr *RetE = S->getRetValue();
@@ -3196,8 +3259,8 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// Update the autorelease counts.
static SimpleProgramPointTag
AutoreleaseTag("RetainCountChecker : Autorelease");
- GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag);
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C, Sym, X);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag,
+ C, Sym, X);
// Did we cache out?
if (!Pred)
@@ -3267,7 +3330,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled),
LOpts, GCEnabled, SummaryLog,
N, Sym, C);
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
@@ -3288,7 +3351,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
new CFRefReport(*returnNotOwnedForOwned,
C.getASTContext().getLangOpts(),
C.isObjCGCEnabled(), SummaryLog, N, Sym);
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
@@ -3354,18 +3417,19 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
// too bad since the number of symbols we will track in practice are
// probably small and evalAssume is only called at branches and a few
// other places.
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
if (B.isEmpty())
return state;
bool changed = false;
- RefBindings::Factory &RefBFactory = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- // Check if the symbol is null (or equal to any constant).
- // If this is the case, stop tracking the symbol.
- if (state->getSymVal(I.getKey())) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ // Check if the symbol is null stop tracking the symbol.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
+ if (AllocFailed.isConstrainedTrue()) {
changed = true;
B = RefBFactory.remove(B, I.getKey());
}
@@ -3410,8 +3474,8 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
std::pair<ExplodedNode *, ProgramStateRef >
RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
- GenericNodeBuilderRefCount Bd,
ExplodedNode *Pred,
+ const ProgramPointTag *Tag,
CheckerContext &Ctx,
SymbolRef Sym, RefVal V) const {
unsigned ACnt = V.getAutoreleaseCount();
@@ -3440,7 +3504,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
V.setAutoreleaseCount(0);
}
state = setRefBinding(state, Sym, V);
- ExplodedNode *N = Bd.MakeNode(state, Pred);
+ ExplodedNode *N = Ctx.addTransition(state, Pred, Tag);
if (N == 0)
state = 0;
return std::make_pair(N, state);
@@ -3451,7 +3515,8 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
V = V ^ RefVal::ErrorOverAutorelease;
state = setRefBinding(state, Sym, V);
- if (ExplodedNode *N = Bd.MakeNode(state, Pred, true)) {
+ ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
+ if (N) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Object over-autoreleased: object was sent -autorelease ";
@@ -3466,7 +3531,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
CFRefReport *report =
new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false,
SummaryLog, N, Sym, os.str());
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0);
@@ -3492,14 +3557,13 @@ RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
ExplodedNode *
RetainCountChecker::processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
- GenericNodeBuilderRefCount &Builder,
CheckerContext &Ctx,
ExplodedNode *Pred) const {
if (Leaked.empty())
return Pred;
// Generate an intermediate node representing the leak point.
- ExplodedNode *N = Builder.MakeNode(state, Pred);
+ ExplodedNode *N = Ctx.addTransition(state, Pred);
if (N) {
for (SmallVectorImpl<SymbolRef>::iterator
@@ -3513,7 +3577,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled,
SummaryLog, N, *I, Ctx);
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
}
@@ -3522,13 +3586,12 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
- GenericNodeBuilderRefCount Bd(Ctx);
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Ctx,
- I->first, I->second);
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, /*Tag=*/0,
+ Ctx, I->first, I->second);
if (!state)
return;
}
@@ -3543,10 +3606,10 @@ void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
B = state->get<RefBindings>();
SmallVector<SymbolRef, 10> Leaked;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I)
state = handleSymbolDeath(state, I->first, I->second, Leaked);
- processLeaks(state, Leaked, Bd, Ctx, Pred);
+ processLeaks(state, Leaked, Ctx, Pred);
}
const ProgramPointTag *
@@ -3567,7 +3630,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ExplodedNode *Pred = C.getPredecessor();
ProgramStateRef state = C.getState();
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
@@ -3576,8 +3639,8 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (const RefVal *T = B.lookup(Sym)){
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
- GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym));
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C,
+ const ProgramPointTag *Tag = getDeadSymbolTag(Sym);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, Tag, C,
Sym, *T);
if (!state)
return;
@@ -3593,17 +3656,14 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
state = handleSymbolDeath(state, *I, *T, Leaked);
}
- {
- GenericNodeBuilderRefCount Bd(C, this);
- Pred = processLeaks(state, Leaked, Bd, C, Pred);
- }
+ Pred = processLeaks(state, Leaked, C, Pred);
// Did we cache out?
if (!Pred)
return;
// Now generate a new node that nukes the old bindings.
- RefBindings::Factory &F = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &F = state->get_context<RefBindings>();
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I)
@@ -3616,12 +3676,12 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const {
- RefBindings B = State->get<RefBindings>();
+ RefBindingsTy B = State->get<RefBindings>();
if (!B.isEmpty())
Out << Sep << NL;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
Out << I->first << " : ";
I->second.print(Out);
Out << NL;
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 6e565932d556..f3560aad8de2 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -82,7 +82,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
new BugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index ca2a55d1e7bb..37ec1aa7bea0 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -16,6 +16,7 @@
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -41,6 +42,19 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef())
return;
+ // "return;" is modeled to evaluate to an UndefinedValue. Allow UndefinedValue
+ // to be returned in functions returning void to support the following pattern:
+ // void foo() {
+ // return;
+ // }
+ // void test() {
+ // return foo();
+ // }
+ const StackFrameContext *SFC = C.getStackFrame();
+ QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl());
+ if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void))
+ return;
+
ExplodedNode *N = C.generateSink();
if (!N)
@@ -53,11 +67,10 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
BugReport *report =
new BugReport(*BT, BT->getDescription(), N);
- report->disablePathPruning();
report->addRange(RetE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, RetE, report);
+ bugreporter::trackNullOrUndefValue(N, RetE, *report);
- C.EmitReport(report);
+ C.emitReport(report);
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
new file mode 100644
index 000000000000..ee055adf6e4d
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -0,0 +1,348 @@
+//===-- SimpleStreamChecker.cpp -----------------------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for proper use of fopen/fclose APIs.
+// - If a file has been closed with fclose, it should not be accessed again.
+// Accessing a closed file results in undefined behavior.
+// - If a file was opened with fopen, it must be closed with fclose before
+// the execution ends. Failing to do so results in a resource leak.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+typedef llvm::SmallVector<SymbolRef, 2> SymbolVector;
+
+struct StreamState {
+private:
+ enum Kind { Opened, Closed } K;
+ StreamState(Kind InK) : K(InK) { }
+
+public:
+ bool isOpened() const { return K == Opened; }
+ bool isClosed() const { return K == Closed; }
+
+ static StreamState getOpened() { return StreamState(Opened); }
+ static StreamState getClosed() { return StreamState(Closed); }
+
+ bool operator==(const StreamState &X) const {
+ return K == X.K;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ }
+};
+
+class SimpleStreamChecker : public Checker<check::PostCall,
+ check::PreCall,
+ check::DeadSymbols,
+ check::Bind,
+ check::RegionChanges> {
+
+ mutable IdentifierInfo *IIfopen, *IIfclose;
+
+ OwningPtr<BugType> DoubleCloseBugType;
+ OwningPtr<BugType> LeakBugType;
+
+ void initIdentifierInfo(ASTContext &Ctx) const;
+
+ void reportDoubleClose(SymbolRef FileDescSym,
+ const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void reportLeaks(SymbolVector LeakedStreams,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const;
+
+ bool guaranteedNotToCloseFile(const CallEvent &Call) const;
+
+public:
+ SimpleStreamChecker();
+
+ /// Process fopen.
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ /// Process fclose.
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+
+ /// Deal with symbol escape as a byproduct of a bind.
+ void checkBind(SVal location, SVal val, const Stmt*S,
+ CheckerContext &C) const;
+
+ /// Deal with symbol escape as a byproduct of a region change.
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call) const;
+ bool wantsRegionChangeUpdate(ProgramStateRef state) const {
+ return true;
+ }
+};
+
+} // end anonymous namespace
+
+/// The state of the checker is a map from tracked stream symbols to their
+/// state. Let's store it in the ProgramState.
+REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
+
+namespace {
+class StopTrackingCallback : public SymbolVisitor {
+ ProgramStateRef state;
+public:
+ StopTrackingCallback(ProgramStateRef st) : state(st) {}
+ ProgramStateRef getState() const { return state; }
+
+ bool VisitSymbol(SymbolRef sym) {
+ state = state->remove<StreamMap>(sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+
+SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) {
+ // Initialize the bug types.
+ DoubleCloseBugType.reset(new BugType("Double fclose",
+ "Unix Stream API Error"));
+
+ LeakBugType.reset(new BugType("Resource Leak",
+ "Unix Stream API Error"));
+ // Sinks are higher importance bugs as well as calls to assert() or exit(0).
+ LeakBugType->setSuppressOnSink(true);
+}
+
+void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+
+ if (!Call.isGlobalCFunction())
+ return;
+
+ if (Call.getCalleeIdentifier() != IIfopen)
+ return;
+
+ // Get the symbolic value corresponding to the file handle.
+ SymbolRef FileDesc = Call.getReturnValue().getAsSymbol();
+ if (!FileDesc)
+ return;
+
+ // Generate the next transition (an edge in the exploded graph).
+ ProgramStateRef State = C.getState();
+ State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
+ C.addTransition(State);
+}
+
+void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+
+ if (!Call.isGlobalCFunction())
+ return;
+
+ if (Call.getCalleeIdentifier() != IIfclose)
+ return;
+
+ if (Call.getNumArgs() != 1)
+ return;
+
+ // Get the symbolic value corresponding to the file handle.
+ SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol();
+ if (!FileDesc)
+ return;
+
+ // Check if the stream has already been closed.
+ ProgramStateRef State = C.getState();
+ const StreamState *SS = State->get<StreamMap>(FileDesc);
+ if (SS && SS->isClosed()) {
+ reportDoubleClose(FileDesc, Call, C);
+ return;
+ }
+
+ // Generate the next transition, in which the stream is closed.
+ State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
+ C.addTransition(State);
+}
+
+static bool isLeaked(SymbolRef Sym, const StreamState &SS,
+ bool IsSymDead, ProgramStateRef State) {
+ if (IsSymDead && SS.isOpened()) {
+ // If a symbol is NULL, assume that fopen failed on this path.
+ // A symbol should only be considered leaked if it is non-null.
+ ConstraintManager &CMgr = State->getConstraintManager();
+ ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym);
+ return !OpenFailed.isConstrainedTrue();
+ }
+ return false;
+}
+
+void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolVector LeakedStreams;
+ StreamMapTy TrackedStreams = State->get<StreamMap>();
+ for (StreamMapTy::iterator I = TrackedStreams.begin(),
+ E = TrackedStreams.end(); I != E; ++I) {
+ SymbolRef Sym = I->first;
+ bool IsSymDead = SymReaper.isDead(Sym);
+
+ // Collect leaked symbols.
+ if (isLeaked(Sym, I->second, IsSymDead, State))
+ LeakedStreams.push_back(Sym);
+
+ // Remove the dead symbol from the streams map.
+ if (IsSymDead)
+ State = State->remove<StreamMap>(Sym);
+ }
+
+ ExplodedNode *N = C.addTransition(State);
+ reportLeaks(LeakedStreams, C, N);
+}
+
+void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ // We reached a bug, stop exploring the path here by generating a sink.
+ ExplodedNode *ErrNode = C.generateSink();
+ // If we've already reached this node on another path, return.
+ if (!ErrNode)
+ return;
+
+ // Generate the report.
+ BugReport *R = new BugReport(*DoubleCloseBugType,
+ "Closing a previously closed file stream", ErrNode);
+ R->addRange(Call.getSourceRange());
+ R->markInteresting(FileDescSym);
+ C.emitReport(R);
+}
+
+void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
+ CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ // Attach bug reports to the leak node.
+ // TODO: Identify the leaked file descriptor.
+ for (llvm::SmallVector<SymbolRef, 2>::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);
+ C.emitReport(R);
+ }
+}
+
+// Check various ways a symbol can be invalidated.
+// Stop tracking symbols when a value escapes as a result of checkBind.
+// A value escapes in three possible cases:
+// (1) We are binding to something that is not a memory region.
+// (2) We are binding to a MemRegion that does not have stack storage
+// (3) We are binding to a MemRegion with stack storage that the store
+// does not understand.
+void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S,
+ CheckerContext &C) const {
+ // Are we storing to something that causes the value to "escape"?
+ bool escapes = true;
+ ProgramStateRef state = C.getState();
+
+ if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
+ escapes = !regionLoc->getRegion()->hasStackStorage();
+
+ if (!escapes) {
+ // To test (3), generate a new state with the binding added. If it is
+ // the same state, then it escapes (since the store cannot represent
+ // the binding). Do this only if we know that the store is not supposed
+ // to generate the same state.
+ SVal StoredVal = state->getSVal(regionLoc->getRegion());
+ if (StoredVal != val)
+ escapes = (state == (state->bindLoc(*regionLoc, val)));
+ }
+ }
+
+ // If our store can represent the binding and we aren't storing to something
+ // that doesn't have local storage then just return the state and
+ // continue as is.
+ if (!escapes)
+ return;
+
+ // Otherwise, find all symbols referenced by 'val' that we are tracking
+ // and stop tracking them.
+ state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
+ C.addTransition(state);
+}
+
+bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
+ // If it's not in a system header, assume it might close a file.
+ if (!Call.isInSystemHeader())
+ return false;
+
+ // Handle cases where we know a buffer's /address/ can escape.
+ if (Call.argumentsMayEscape())
+ return false;
+
+ // Note, even though fclose closes the file, we do not list it here
+ // since the checker is modeling the call.
+
+ return true;
+}
+
+// If the symbol we are tracking is invalidated, do not track the symbol as
+// we cannot reason about it anymore.
+ProgramStateRef
+SimpleStreamChecker::checkRegionChanges(ProgramStateRef State,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call) const {
+
+ if (!invalidated || invalidated->empty())
+ return State;
+
+ // If it's a call which might close the file, we assume that all regions
+ // (explicit and implicit) escaped. Otherwise, whitelist explicit pointers
+ // (the parameters to the call); we still can track them.
+ llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+ if (!Call || guaranteedNotToCloseFile(*Call)) {
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end(); I != E; ++I) {
+ if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
+ WhitelistedSymbols.insert(R->getSymbol());
+ }
+ }
+
+ for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ E = invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (WhitelistedSymbols.count(sym))
+ continue;
+ // The symbol escaped. Optimistically, assume that the corresponding file
+ // handle will be closed somewhere else.
+ State = State->remove<StreamMap>(sym);
+ }
+ return State;
+}
+
+void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const {
+ if (IIfopen)
+ return;
+ IIfopen = &Ctx.Idents.get("fopen");
+ IIfclose = &Ctx.Idents.get("fclose");
+}
+
+void ento::registerSimpleStreamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<SimpleStreamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 54cf5690c9ea..0c2f26683745 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -109,7 +109,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
if (range.isValid())
report->addRange(range);
- C.EmitReport(report);
+ C.emitReport(report);
}
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
@@ -118,8 +118,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
-
- SVal V = C.getState()->getSVal(RetE, C.getLocationContext());
+ RetE = RetE->IgnoreParens();
+
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal V = C.getState()->getSVal(RetE, LCtx);
const MemRegion *R = V.getAsRegion();
if (!R)
@@ -132,8 +134,9 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
return;
// Return stack memory in an ancestor stack frame is fine.
- const StackFrameContext *SFC = SS->getStackFrame();
- if (SFC != C.getLocationContext()->getCurrentStackFrame())
+ const StackFrameContext *CurFrame = LCtx->getCurrentStackFrame();
+ const StackFrameContext *MemFrame = SS->getStackFrame();
+ if (MemFrame != CurFrame)
return;
// Automatic reference counting automatically copies blocks.
@@ -141,6 +144,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
isa<BlockDataRegion>(R))
return;
+ // Returning a record by value is fine. (In this case, the returned
+ // expression will be a copy-constructor, possibly wrapped in an
+ // ExprWithCleanups node.)
+ if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
+ RetE = Cleanup->getSubExpr();
+ if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType())
+ return;
+
EmitStackError(C, R, RetE);
}
@@ -221,7 +232,7 @@ void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
if (range.isValid())
report->addRange(range);
- Ctx.EmitReport(report);
+ Ctx.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 731dd66b460b..c06ba7c304e6 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -104,15 +104,8 @@ private:
} // end anonymous namespace
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<StreamState>
- : public ProgramStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { static int x; return &x; }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
+
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const FunctionDecl *FD = C.getCalleeDecl(CE);
@@ -219,11 +212,11 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef state = C.getState();
- unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, LCtx, Count));
+ cast<DefinedSVal>(svalBuilder.conjureSymbolVal(0, CE, LCtx,
+ C.blockCount()));
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
@@ -235,9 +228,9 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
if (SymbolRef Sym = RetVal.getAsSymbol()) {
// if RetVal is not NULL, set the symbol's state to Opened.
stateNotNull =
- stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
+ stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
stateNull =
- stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
+ stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
C.addTransition(stateNotNull);
C.addTransition(stateNull);
@@ -287,7 +280,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
"SEEK_SET, SEEK_END, or SEEK_CUR."));
BugReport *R = new BugReport(*BT_illegalwhence,
BT_illegalwhence->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
@@ -363,7 +356,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
BT_nullfp.reset(new BuiltinBug("NULL stream pointer",
"Stream pointer might be NULL."));
BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return 0;
}
@@ -378,7 +371,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
if (!Sym)
return state;
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
// If the file stream is not tracked, return.
if (!SS)
@@ -395,22 +388,24 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
" closed. Cause undefined behaviour."));
BugReport *R = new BugReport(*BT_doubleclose,
BT_doubleclose->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
return NULL;
}
// Close the File Descriptor.
- return state->set<StreamState>(Sym, StreamState::getClosed(CE));
+ return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
}
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const {
+ // TODO: Clean up the state.
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
ProgramStateRef state = C.getState();
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
+ // TODO: Shouldn't we have a continue here?
if (!SS)
return;
@@ -422,7 +417,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
"Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
@@ -430,10 +425,9 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
- typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
- SymMap M = state->get<StreamState>();
+ StreamMapTy M = state->get<StreamMap>();
- for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ for (StreamMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
StreamState SS = I->second;
if (SS.isOpened()) {
ExplodedNode *N = Ctx.addTransition(state);
@@ -443,7 +437,7 @@ void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
"Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
- Ctx.EmitReport(R);
+ Ctx.emitReport(R);
}
}
}
@@ -460,12 +454,12 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (!Sym)
return;
- const StreamState *SS = state->get<StreamState>(Sym);
+ const StreamState *SS = state->get<StreamMap>(Sym);
if(!SS)
return;
if (SS->isOpened())
- state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
+ state = state->set<StreamMap>(Sym, StreamState::getEscaped(S));
C.addTransition(state);
}
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 113368254d67..382be8475bb8 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -52,7 +52,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
initBugType();
BugReport *report = new BugReport(*BT, "tainted",N);
report->addRange(E->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 70a33c76db0c..70e141e574cd 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -99,11 +99,10 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
// Emit the bug report.
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, R);
+ bugreporter::trackNullOrUndefValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
- R->disablePathPruning();
- Ctx.EmitReport(R);
+ Ctx.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 675b38a5df26..30ccffaab055 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -96,7 +96,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
R->disablePathPruning();
// need location of block
- C.EmitReport(R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index e220499d73f4..415bab57287e 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -76,13 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
BugReport *report = new BugReport(*BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report);
+ bugreporter::trackNullOrUndefValue(N, Ex, *report);
}
else
- bugreporter::addTrackNullOrUndefValueVisitor(N, B, report);
+ bugreporter::trackNullOrUndefValue(N, B, *report);
- report->disablePathPruning();
- C.EmitReport(report);
+ C.emitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index 6ae3c1875fbf..b3a83e8e9179 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -42,8 +42,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
// Generate a report for this bug.
BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(A->getIdx()->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, A->getIdx(), R);
- C.EmitReport(R);
+ bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
+ C.emitReport(R);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 14a884e01b64..410010a335c3 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -78,10 +78,9 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
BugReport *R = new BugReport(*BT, str, N);
if (ex) {
R->addRange(ex->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, ex, R);
+ bugreporter::trackNullOrUndefValue(N, ex, *R);
}
- R->disablePathPruning();
- C.EmitReport(R);
+ C.emitReport(R);
}
void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index d35455c2191b..171e15b85ae7 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -41,6 +41,7 @@ public:
void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
@@ -138,7 +139,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
"Call to 'open' requires a third argument when "
"the 'O_CREAT' flag is set", N);
report->addRange(oflagsEx->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
}
@@ -183,11 +184,12 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
+ C.emitReport(report);
}
//===----------------------------------------------------------------------===//
-// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0
+// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
+// with allocation size 0
//===----------------------------------------------------------------------===//
// FIXME: Eventually these should be rolled into the MallocChecker, but right now
// they're more basic and valuable for widespread use.
@@ -224,8 +226,8 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);
report->addRange(arg->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, arg, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, arg, *report);
+ C.emitReport(report);
return true;
}
@@ -307,6 +309,11 @@ void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
BasicAllocationCheck(C, CE, 2, 1, "realloc");
}
+void UnixAPIChecker::CheckReallocfZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 2, 1, "reallocf");
+}
+
void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
const CallExpr *CE) const {
BasicAllocationCheck(C, CE, 1, 0, "alloca");
@@ -339,6 +346,7 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
.Case("calloc", &UnixAPIChecker::CheckCallocZero)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)
.Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
.Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
.Case("valloc", &UnixAPIChecker::CheckVallocZero)
.Default(NULL);
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index fab4adf3e0e2..58f9ec0f9b9b 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -69,8 +69,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(SizeE->getSourceRange());
- bugreporter::addTrackNullOrUndefValueVisitor(N, SizeE, report);
- C.EmitReport(report);
+ bugreporter::trackNullOrUndefValue(N, SizeE, *report);
+ C.emitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index efeba17a62ba..011d4c09a23f 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -20,33 +20,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr,
- unsigned maxnodes, unsigned maxvisit,
- bool vizdot, bool vizubi,
- AnalysisPurgeMode purge,
- bool eager, bool trim,
- bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool eagerlyTrimEGraph,
- AnalysisIPAMode ipa,
- unsigned inlineMaxStack,
- unsigned inlineMaxFunctionSize,
- AnalysisInliningMode IMode,
- bool NoRetry)
- : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, /*addInitializers=*/true),
- Ctx(ctx), Diags(diags), LangOpts(lang),
+ AnalyzerOptions &Options)
+ : AnaCtxMgr(Options.UnoptimizedCFG,
+ /*AddImplicitDtors=*/true,
+ /*AddInitializers=*/true,
+ Options.includeTemporaryDtorsInCFG(),
+ Options.shouldSynthesizeBodies()),
+ Ctx(ctx),
+ Diags(diags),
+ LangOpts(lang),
PathConsumers(PDC),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- CheckerMgr(checkerMgr),
- MaxNodes(maxnodes), MaxVisit(maxvisit),
- VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim),
- EagerlyTrimEGraph(eagerlyTrimEGraph),
- IPAMode(ipa),
- InlineMaxStackDepth(inlineMaxStack),
- InlineMaxFunctionSize(inlineMaxFunctionSize),
- InliningMode(IMode),
- NoRetryExhausted(NoRetry)
-{
+ CheckerMgr(checkerMgr),
+ options(Options) {
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
new file mode 100644
index 000000000000..da88589c8696
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -0,0 +1,138 @@
+//===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains special accessors for analyzer configuration options
+// with string representations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace llvm;
+
+bool
+AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
+ if (IPAMode < Inlining)
+ return false;
+
+ if (!CXXMemberInliningMode) {
+ static const char *ModeKey = "c++-inlining";
+
+ StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
+ "methods").getValue());
+
+ CXXInlineableMemberKind &MutableMode =
+ const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
+
+ MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr)
+ .Case("constructors", CIMK_Constructors)
+ .Case("destructors", CIMK_Destructors)
+ .Case("none", CIMK_None)
+ .Case("methods", CIMK_MemberFunctions)
+ .Default(CXXInlineableMemberKind());
+
+ if (!MutableMode) {
+ // FIXME: We should emit a warning here about an unknown inlining kind,
+ // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+ MutableMode = CIMK_None;
+ }
+ }
+
+ return CXXMemberInliningMode >= K;
+}
+
+static StringRef toString(bool b) { return b ? "true" : "false"; }
+
+bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
+ // FIXME: We should emit a warning here if the value is something other than
+ // "true", "false", or the empty string (meaning the default value),
+ // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+ StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue());
+ return llvm::StringSwitch<bool>(V)
+ .Case("true", true)
+ .Case("false", false)
+ .Default(DefaultVal);
+}
+
+bool AnalyzerOptions::getBooleanOption(llvm::Optional<bool> &V,
+ StringRef Name,
+ bool DefaultVal) {
+ if (!V.hasValue())
+ V = getBooleanOption(Name, DefaultVal);
+ return V.getValue();
+}
+
+bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
+ return getBooleanOption(IncludeTemporaryDtorsInCFG,
+ "cfg-temporary-dtors",
+ /* Default = */ false);
+}
+
+bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
+ return getBooleanOption(InlineCXXStandardLibrary,
+ "c++-stdlib-inlining",
+ /*Default=*/true);
+}
+
+bool AnalyzerOptions::mayInlineTemplateFunctions() {
+ return getBooleanOption(InlineTemplateFunctions,
+ "c++-template-inlining",
+ /*Default=*/true);
+}
+
+bool AnalyzerOptions::mayInlineObjCMethod() {
+ return getBooleanOption(ObjCInliningMode,
+ "objc-inlining",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldPruneNullReturnPaths() {
+ return getBooleanOption(PruneNullReturnPaths,
+ "suppress-null-return-paths",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
+ return getBooleanOption(AvoidSuppressingNullArgumentPaths,
+ "avoid-suppressing-null-argument-paths",
+ /* Default = */ false);
+}
+
+int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
+ llvm::SmallString<10> StrBuf;
+ llvm::raw_svector_ostream OS(StrBuf);
+ OS << DefaultVal;
+
+ StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue());
+ int Res = DefaultVal;
+ bool b = V.getAsInteger(10, Res);
+ assert(!b && "analyzer-config option should be numeric");
+ (void) b;
+ return Res;
+}
+
+unsigned AnalyzerOptions::getAlwaysInlineSize() {
+ if (!AlwaysInlineSize.hasValue())
+ AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
+ return AlwaysInlineSize.getValue();
+}
+
+unsigned AnalyzerOptions::getGraphTrimInterval() {
+ if (!GraphTrimInterval.hasValue())
+ GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
+ return GraphTrimInterval.getValue();
+}
+
+bool AnalyzerOptions::shouldSynthesizeBodies() {
+ return getBooleanOption("faux-bodies", true);
+}
diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
deleted file mode 100644
index 8897756a92d9..000000000000
--- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-//== BasicConstraintManager.cpp - Manage basic constraints.------*- 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 BasicConstraintManager, a class that tracks simple
-// equality and inequality constraints on symbolic values of ProgramState.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SimpleConstraintManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-
-namespace { class ConstNotEq {}; }
-namespace { class ConstEq {}; }
-
-typedef llvm::ImmutableMap<SymbolRef,ProgramState::IntSetTy> ConstNotEqTy;
-typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
-
-static int ConstEqIndex = 0;
-static int ConstNotEqIndex = 0;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<ConstNotEq> :
- public ProgramStatePartialTrait<ConstNotEqTy> {
- static inline void *GDMIndex() { return &ConstNotEqIndex; }
-};
-
-template<>
-struct ProgramStateTrait<ConstEq> : public ProgramStatePartialTrait<ConstEqTy> {
- static inline void *GDMIndex() { return &ConstEqIndex; }
-};
-}
-}
-
-namespace {
-// BasicConstraintManager only tracks equality and inequality constraints of
-// constants and integer variables.
-class BasicConstraintManager
- : public SimpleConstraintManager {
- ProgramState::IntSetTy::Factory ISetFactory;
-public:
- BasicConstraintManager(ProgramStateManager &statemgr, SubEngine &subengine)
- : SimpleConstraintManager(subengine, statemgr.getBasicVals()),
- ISetFactory(statemgr.getAllocator()) {}
-
- ProgramStateRef assumeSymEquality(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment,
- bool Assumption);
-
- ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- return assumeSymEquality(State, Sym, V, Adjustment, false);
- }
-
- ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- return assumeSymEquality(State, Sym, V, Adjustment, true);
- }
-
- ProgramStateRef assumeSymLT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymGT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymGE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef assumeSymLE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V,
- const llvm::APSInt& Adjustment);
-
- ProgramStateRef AddEQ(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V);
-
- ProgramStateRef AddNE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V);
-
- const llvm::APSInt* getSymVal(ProgramStateRef state,
- SymbolRef sym) const;
-
- bool isNotEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const;
-
- bool isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const;
-
- ProgramStateRef removeDeadBindings(ProgramStateRef state,
- SymbolReaper& SymReaper);
-
- bool performTest(llvm::APSInt SymVal, llvm::APSInt Adjustment,
- BinaryOperator::Opcode Op, llvm::APSInt ComparisonVal);
-
- void print(ProgramStateRef state,
- raw_ostream &Out,
- const char* nl,
- const char *sep);
-};
-
-} // end anonymous namespace
-
-ConstraintManager*
-ento::CreateBasicConstraintManager(ProgramStateManager& statemgr,
- SubEngine &subengine) {
- return new BasicConstraintManager(statemgr, subengine);
-}
-
-// FIXME: This is a more general utility and should live somewhere else.
-bool BasicConstraintManager::performTest(llvm::APSInt SymVal,
- llvm::APSInt Adjustment,
- BinaryOperator::Opcode Op,
- llvm::APSInt ComparisonVal) {
- APSIntType Type(Adjustment);
- Type.apply(SymVal);
- Type.apply(ComparisonVal);
- SymVal += Adjustment;
-
- assert(BinaryOperator::isComparisonOp(Op));
- BasicValueFactory &BVF = getBasicVals();
- const llvm::APSInt *Result = BVF.evalAPSInt(Op, SymVal, ComparisonVal);
- assert(Result && "Comparisons should always have valid results.");
-
- return Result->getBoolValue();
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymEquality(ProgramStateRef State, SymbolRef Sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment,
- bool Assumption) {
- // Before we do any real work, see if the value can even show up.
- APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(V) != APSIntType::RTR_Within)
- return Assumption ? NULL : State;
-
- // Get the symbol type.
- BasicValueFactory &BVF = getBasicVals();
- ASTContext &Ctx = BVF.getContext();
- APSIntType SymbolType = BVF.getAPSIntType(Sym->getType(Ctx));
-
- // First, see if the adjusted value is within range for the symbol.
- llvm::APSInt Adjusted = AdjustmentType.convert(V) - Adjustment;
- if (SymbolType.testInRange(Adjusted) != APSIntType::RTR_Within)
- return Assumption ? NULL : State;
-
- // Now we can do things properly in the symbol space.
- SymbolType.apply(Adjusted);
-
- // Second, determine if sym == X, where X+Adjustment != V.
- if (const llvm::APSInt *X = getSymVal(State, Sym)) {
- bool IsFeasible = (*X == Adjusted);
- return (IsFeasible == Assumption) ? State : NULL;
- }
-
- // Third, determine if we already know sym+Adjustment != V.
- if (isNotEqual(State, Sym, Adjusted))
- return Assumption ? NULL : State;
-
- // If we reach here, sym is not a constant and we don't know if it is != V.
- // Make the correct assumption.
- if (Assumption)
- return AddEQ(State, Sym, Adjusted);
- else
- return AddNE(State, Sym, Adjusted);
-}
-
-// The logic for these will be handled in another ConstraintManager.
-// Approximate it here anyway by handling some edge cases.
-ProgramStateRef
-BasicConstraintManager::assumeSymLT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V > ComparisonType.convert(Max)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Is 'V' the smallest possible value, or out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V <= ComparisonType.convert(Min)) {
- // sym cannot be any value less than 'V'. This path is infeasible.
- return NULL;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj < V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_LT, V);
- return isFeasible ? state : NULL;
- }
-
- // FIXME: For now have assuming x < y be the same as assuming sym != V;
- return assumeSymNE(state, sym, V, Adjustment);
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymGT(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' the largest possible value, or out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V >= ComparisonType.convert(Max)) {
- // sym cannot be any value greater than 'V'. This path is infeasible.
- return NULL;
- }
-
- // Is 'V' out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V < ComparisonType.convert(Min)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj > V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_GT, V);
- return isFeasible ? state : NULL;
- }
-
- // FIXME: For now have assuming x > y be the same as assuming sym != V;
- return assumeSymNE(state, sym, V, Adjustment);
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymGE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' the largest possible value, or out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- ComparisonType.apply(Max);
-
- if (V > Max) {
- // sym cannot be any value greater than 'V'. This path is infeasible.
- return NULL;
- } else if (V == Max) {
- // If the path is feasible then as a consequence we know that
- // 'sym+Adjustment == V' because there are no larger values.
- // Add this constraint.
- return assumeSymEQ(state, sym, V, Adjustment);
- }
-
- // Is 'V' out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- if (V < ComparisonType.convert(Min)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_GE, V);
- return isFeasible ? state : NULL;
- }
-
- return state;
-}
-
-ProgramStateRef
-BasicConstraintManager::assumeSymLE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt &V,
- const llvm::APSInt &Adjustment) {
- APSIntType ComparisonType(V), AdjustmentType(Adjustment);
-
- // Is 'V' out of range above the type?
- llvm::APSInt Max = AdjustmentType.getMaxValue();
- if (V > ComparisonType.convert(Max)) {
- // This path is trivially feasible.
- return state;
- }
-
- // Is 'V' the smallest possible value, or out of range below the type?
- llvm::APSInt Min = AdjustmentType.getMinValue();
- ComparisonType.apply(Min);
-
- if (V < Min) {
- // sym cannot be any value less than 'V'. This path is infeasible.
- return NULL;
- } else if (V == Min) {
- // If the path is feasible then as a consequence we know that
- // 'sym+Adjustment == V' because there are no smaller values.
- // Add this constraint.
- return assumeSymEQ(state, sym, V, Adjustment);
- }
-
- // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
- if (const llvm::APSInt *X = getSymVal(state, sym)) {
- bool isFeasible = performTest(*X, Adjustment, BO_LE, V);
- return isFeasible ? state : NULL;
- }
-
- return state;
-}
-
-ProgramStateRef BasicConstraintManager::AddEQ(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) {
- // Now that we have an actual value, we can throw out the NE-set.
- // Create a new state with the old bindings replaced.
- state = state->remove<ConstNotEq>(sym);
- return state->set<ConstEq>(sym, &getBasicVals().getValue(V));
-}
-
-ProgramStateRef BasicConstraintManager::AddNE(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) {
-
- // First, retrieve the NE-set associated with the given symbol.
- ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
- ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
-
- // Now add V to the NE set.
- S = ISetFactory.add(S, &getBasicVals().getValue(V));
-
- // Create a new state with the old binding replaced.
- return state->set<ConstNotEq>(sym, S);
-}
-
-const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state,
- SymbolRef sym) const {
- const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
- return T ? *T : NULL;
-}
-
-bool BasicConstraintManager::isNotEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const {
-
- // Retrieve the NE-set associated with the given symbol.
- const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
-
- // See if V is present in the NE-set.
- return T ? T->contains(&getBasicVals().getValue(V)) : false;
-}
-
-bool BasicConstraintManager::isEqual(ProgramStateRef state,
- SymbolRef sym,
- const llvm::APSInt& V) const {
- // Retrieve the EQ-set associated with the given symbol.
- const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
- // See if V is present in the EQ-set.
- return T ? **T == V : false;
-}
-
-/// Scan all symbols referenced by the constraints. If the symbol is not alive
-/// as marked in LSymbols, mark it as dead in DSymbols.
-ProgramStateRef
-BasicConstraintManager::removeDeadBindings(ProgramStateRef state,
- SymbolReaper& SymReaper) {
-
- ConstEqTy CE = state->get<ConstEq>();
- ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>();
-
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
- SymbolRef sym = I.getKey();
- if (SymReaper.maybeDead(sym))
- CE = CEFactory.remove(CE, sym);
- }
- state = state->set<ConstEq>(CE);
-
- ConstNotEqTy CNE = state->get<ConstNotEq>();
- ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>();
-
- for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
- SymbolRef sym = I.getKey();
- if (SymReaper.maybeDead(sym))
- CNE = CNEFactory.remove(CNE, sym);
- }
-
- return state->set<ConstNotEq>(CNE);
-}
-
-void BasicConstraintManager::print(ProgramStateRef state,
- raw_ostream &Out,
- const char* nl, const char *sep) {
- // Print equality constraints.
-
- ConstEqTy CE = state->get<ConstEq>();
-
- if (!CE.isEmpty()) {
- Out << nl << sep << "'==' constraints:";
- for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
- Out << nl << " $" << I.getKey() << " : " << *I.getData();
- }
-
- // Print != constraints.
-
- ConstNotEqTy CNE = state->get<ConstNotEq>();
-
- if (!CNE.isEmpty()) {
- Out << nl << sep << "'!=' constraints:";
-
- for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
- Out << nl << " $" << I.getKey() << " : ";
- bool isFirst = true;
-
- ProgramState::IntSetTy::iterator J = I.getData().begin(),
- EJ = I.getData().end();
-
- for ( ; J != EJ; ++J) {
- if (isFirst) isFirst = false;
- else Out << ", ";
-
- Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream.
- }
- }
- }
-}
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 20c73612c481..a6c400f3704d 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -101,11 +101,7 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
- unsigned bits = Ctx.getTypeSize(T);
- llvm::APSInt V(bits,
- T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T));
- V = X;
- return getValue(V);
+ return getValue(getAPSIntType(T).getValue(X));
}
const CompoundValData*
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 571baecd729d..c898d65a5f95 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -118,10 +118,82 @@ GetCurrentOrNextStmt(const ExplodedNode *N) {
// Diagnostic cleanup.
//===----------------------------------------------------------------------===//
+static PathDiagnosticEventPiece *
+eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
+ PathDiagnosticEventPiece *Y) {
+ // Prefer diagnostics that come from ConditionBRVisitor over
+ // those that came from TrackConstraintBRVisitor.
+ const void *tagPreferred = ConditionBRVisitor::getTag();
+ const void *tagLesser = TrackConstraintBRVisitor::getTag();
+
+ if (X->getLocation() != Y->getLocation())
+ return 0;
+
+ if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
+ return X;
+
+ if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
+ return Y;
+
+ return 0;
+}
+
+/// An optimization pass over PathPieces that removes redundant diagnostics
+/// generated by both ConditionBRVisitor and TrackConstraintBRVisitor. Both
+/// BugReporterVisitors use different methods to generate diagnostics, with
+/// one capable of emitting diagnostics in some cases but not in others. This
+/// can lead to redundant diagnostic pieces at the same point in a path.
+static void removeRedundantMsgs(PathPieces &path) {
+ unsigned N = path.size();
+ if (N < 2)
+ return;
+ // NOTE: this loop intentionally is not using an iterator. Instead, we
+ // are streaming the path and modifying it in place. This is done by
+ // grabbing the front, processing it, and if we decide to keep it append
+ // it to the end of the path. The entire path is processed in this way.
+ for (unsigned i = 0; i < N; ++i) {
+ IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front());
+ path.pop_front();
+
+ switch (piece->getKind()) {
+ case clang::ento::PathDiagnosticPiece::Call:
+ removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path);
+ break;
+ case clang::ento::PathDiagnosticPiece::Macro:
+ removeRedundantMsgs(cast<PathDiagnosticMacroPiece>(piece)->subPieces);
+ break;
+ case clang::ento::PathDiagnosticPiece::ControlFlow:
+ break;
+ case clang::ento::PathDiagnosticPiece::Event: {
+ if (i == N-1)
+ break;
+
+ if (PathDiagnosticEventPiece *nextEvent =
+ dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) {
+ PathDiagnosticEventPiece *event =
+ cast<PathDiagnosticEventPiece>(piece);
+ // Check to see if we should keep one of the two pieces. If we
+ // come up with a preference, record which piece to keep, and consume
+ // another piece from the path.
+ if (PathDiagnosticEventPiece *pieceToKeep =
+ eventsDescribeSameCondition(event, nextEvent)) {
+ piece = pieceToKeep;
+ path.pop_front();
+ ++i;
+ }
+ }
+ break;
+ }
+ }
+ path.push_back(piece);
+ }
+}
+
/// Recursively scan through a path and prune out calls and macros pieces
/// that aren't needed. Return true if afterwards the path contains
/// "interesting stuff" which means it should be pruned from the parent path.
-static bool RemoveUneededCalls(PathPieces &pieces) {
+bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
+ PathDiagnosticCallPiece *CallWithLoc) {
bool containsSomethingInteresting = false;
const unsigned N = pieces.size();
@@ -131,30 +203,49 @@ static bool RemoveUneededCalls(PathPieces &pieces) {
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front();
+ // Throw away pieces with invalid locations.
+ if (piece->getKind() != PathDiagnosticPiece::Call &&
+ piece->getLocation().asLocation().isInvalid())
+ continue;
+
switch (piece->getKind()) {
case PathDiagnosticPiece::Call: {
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
+ // Check if the location context is interesting.
+ assert(LocationContextMap.count(call));
+ if (R->isInteresting(LocationContextMap[call])) {
+ containsSomethingInteresting = true;
+ break;
+ }
// Recursively clean out the subclass. Keep this call around if
// it contains any informative diagnostics.
- if (!RemoveUneededCalls(call->path))
+ PathDiagnosticCallPiece *NewCallWithLoc =
+ call->getLocation().asLocation().isValid()
+ ? call : CallWithLoc;
+
+ if (!RemoveUneededCalls(call->path, R, NewCallWithLoc))
continue;
+
+ if (NewCallWithLoc == CallWithLoc && CallWithLoc) {
+ call->callEnter = CallWithLoc->callEnter;
+ }
+
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Macro: {
PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
- if (!RemoveUneededCalls(macro->subPieces))
+ if (!RemoveUneededCalls(macro->subPieces, R))
continue;
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Event: {
PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
+
// We never throw away an event, but we do throw it away wholesale
// as part of a path if we throw the entire path away.
- if (event->isPrunable())
- continue;
- containsSomethingInteresting = true;
+ containsSomethingInteresting |= !event->isPrunable();
break;
}
case PathDiagnosticPiece::ControlFlow:
@@ -382,6 +473,35 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
}
//===----------------------------------------------------------------------===//
+// "Visitors only" path diagnostic generation algorithm.
+//===----------------------------------------------------------------------===//
+static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode *N,
+ ArrayRef<BugReporterVisitor *> visitors) {
+ // All path generation skips the very first node (the error node).
+ // This is because there is special handling for the end-of-path note.
+ N = N->getFirstPred();
+ if (!N)
+ return true;
+
+ BugReport *R = PDB.getBugReport();
+ while (const ExplodedNode *Pred = N->getFirstPred()) {
+ for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
+ E = visitors.end();
+ I != E; ++I) {
+ // Visit all the node pairs, but throw the path pieces away.
+ PathDiagnosticPiece *Piece = (*I)->VisitNode(N, Pred, PDB, *R);
+ delete Piece;
+ }
+
+ N = Pred;
+ }
+
+ return R->isValid();
+}
+
+//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*> StackDiagPair;
@@ -412,7 +532,7 @@ static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
-static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
+static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
ArrayRef<BugReporterVisitor *> visitors) {
@@ -430,55 +550,60 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
NextNode = GetPredecessorNode(N);
ProgramPoint P = N->getLocation();
-
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
- PathDiagnosticCallPiece *C =
- PathDiagnosticCallPiece::construct(N, *CE, SMgr);
- PD.getActivePath().push_front(C);
- PD.pushActivePath(&C->path);
- CallStack.push_back(StackDiagPair(C, N));
- continue;
- }
-
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
- // Flush all locations, and pop the active path.
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
-
- // Either we just added a bunch of stuff to the top-level path, or
- // we have a previous CallExitEnd. If the former, it means that the
- // path terminated within a function call. We must then take the
- // current contents of the active path and place it within
- // a new PathDiagnosticCallPiece.
- PathDiagnosticCallPiece *C;
- if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
- } else {
- const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+
+ do {
+ if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ PathDiagnosticCallPiece *C =
+ PathDiagnosticCallPiece::construct(N, *CE, SMgr);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ PD.getActivePath().push_front(C);
+ PD.pushActivePath(&C->path);
+ CallStack.push_back(StackDiagPair(C, N));
+ break;
}
- C->setCallee(*CE, SMgr);
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
+ if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ // Flush all locations, and pop the active path.
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ // Either we just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExitEnd. If the former, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ }
+
+ C->setCallee(*CE, SMgr);
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ break;
}
- continue;
- }
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const CFGBlock *Src = BE->getSrc();
- const CFGBlock *Dst = BE->getDst();
- const Stmt *T = Src->getTerminator();
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ const CFGBlock *Src = BE->getSrc();
+ const CFGBlock *Dst = BE->getDst();
+ const Stmt *T = Src->getTerminator();
- if (!T)
- continue;
+ if (!T)
+ break;
- PathDiagnosticLocation Start =
- PathDiagnosticLocation::createBegin(T, SMgr,
- N->getLocationContext());
+ PathDiagnosticLocation Start =
+ PathDiagnosticLocation::createBegin(T, SMgr,
+ N->getLocationContext());
- switch (T->getStmtClass()) {
+ switch (T->getStmtClass()) {
default:
break;
@@ -487,16 +612,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const Stmt *S = GetNextStmt(N);
if (!S)
- continue;
+ break;
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
os << "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ << End.asLocation().getExpansionLineNumber();
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
@@ -509,52 +634,52 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticLocation End(S, SMgr, LC);
switch (S->getStmtClass()) {
- default:
- os << "No cases match in the switch statement. "
- "Control jumps to line "
- << End.asLocation().getExpansionLineNumber();
- break;
- case Stmt::DefaultStmtClass:
- os << "Control jumps to the 'default' case at line "
- << End.asLocation().getExpansionLineNumber();
- break;
-
- case Stmt::CaseStmtClass: {
- os << "Control jumps to 'case ";
- const CaseStmt *Case = cast<CaseStmt>(S);
- const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
-
- // Determine if it is an enum.
- bool GetRawInt = true;
-
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
- // FIXME: Maybe this should be an assertion. Are there cases
- // were it is not an EnumConstantDecl?
- const EnumConstantDecl *D =
+ default:
+ os << "No cases match in the switch statement. "
+ "Control jumps to line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
+ case Stmt::DefaultStmtClass:
+ os << "Control jumps to the 'default' case at line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
+
+ case Stmt::CaseStmtClass: {
+ os << "Control jumps to 'case ";
+ const CaseStmt *Case = cast<CaseStmt>(S);
+ const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
+
+ // Determine if it is an enum.
+ bool GetRawInt = true;
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
+ // FIXME: Maybe this should be an assertion. Are there cases
+ // were it is not an EnumConstantDecl?
+ const EnumConstantDecl *D =
dyn_cast<EnumConstantDecl>(DR->getDecl());
- if (D) {
- GetRawInt = false;
- os << *D;
- }
+ if (D) {
+ GetRawInt = false;
+ os << *D;
}
+ }
- if (GetRawInt)
- os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
+ if (GetRawInt)
+ os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
- os << ":' at line "
- << End.asLocation().getExpansionLineNumber();
- break;
- }
+ os << ":' at line "
+ << End.asLocation().getExpansionLineNumber();
+ break;
}
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ }
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "'Default' branch taken. ";
const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
break;
@@ -565,12 +690,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
- // Determine control-flow for ternary '?'.
+ // Determine control-flow for ternary '?'.
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
std::string sbuf;
@@ -587,12 +712,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
break;
}
- // Determine control-flow for short-circuited '&&' and '||'.
+ // Determine control-flow for short-circuited '&&' and '||'.
case Stmt::BinaryOperatorClass: {
if (!PDB.supportsLogicalOpControlFlow())
break;
@@ -609,16 +734,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "false";
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "true";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
}
else {
@@ -629,16 +754,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "false";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
os << "true";
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
- PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PathDiagnosticLocation::createOperatorLoc(B, SMgr);
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
}
@@ -656,8 +781,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
@@ -665,8 +790,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is false. Exiting loop"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Loop condition is false. Exiting loop"));
}
break;
@@ -683,16 +808,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, os.str()));
}
else {
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is true. Entering loop body"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Loop condition is true. Entering loop body"));
}
break;
@@ -705,16 +830,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
End = PDB.getEnclosingStmtLocation(S);
if (*(Src->succ_begin()+1) == Dst)
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking false branch"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Taking false branch"));
else
- PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking true branch"));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(
+ Start, End, "Taking true branch"));
break;
}
+ }
}
- }
+ } while(0);
if (NextNode) {
// Add diagnostic pieces from custom visitors.
@@ -730,9 +856,13 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
}
+ if (!PDB.getBugReport()->isValid())
+ return false;
+
// After constructing the full PathDiagnostic, do a pass over it to compact
// PathDiagnosticPieces that occur within a macro.
CompactPathDiagnostic(PD.getMutablePieces(), PDB.getSourceManager());
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -944,6 +1074,11 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc);
const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc);
+ if (PrevLocClean.asLocation().isInvalid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
if (NewLocClean.asLocation() == PrevLocClean.asLocation())
return;
@@ -1133,7 +1268,7 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
-static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
ArrayRef<BugReporterVisitor *> visitors) {
@@ -1166,6 +1301,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SM);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
EB.addEdge(C->callReturn, true);
EB.flushLocations();
@@ -1202,6 +1339,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ GRBugReporter& BR = PDB.getBugReporter();
+ BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
}
C->setCallee(*CE, SM);
@@ -1234,20 +1373,15 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
}
- const CFGBlock &Blk = *BE->getSrc();
- const Stmt *Term = Blk.getTerminator();
-
// Are we jumping to the head of a loop? Add a special diagnostic.
- if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
+ if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC);
const CompoundStmt *CS = NULL;
- if (!Term) {
- if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(FS->getBody());
- else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
- CS = dyn_cast<CompoundStmt>(WS->getBody());
- }
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(FS->getBody());
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(WS->getBody());
PathDiagnosticEventPiece *p =
new PathDiagnosticEventPiece(L,
@@ -1263,15 +1397,16 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
- if (Term)
+
+ if (const Stmt *Term = BE->getSrc()->getTerminator())
EB.addContext(Term);
break;
}
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- if (const CFGStmt *S = BE->getFirstElement().getAs<CFGStmt>()) {
+ CFGElement First = BE->getFirstElement();
+ if (const CFGStmt *S = First.getAs<CFGStmt>()) {
const Stmt *stmt = S->getStmt();
if (IsControlFlowExpr(stmt)) {
// Add the proper context for '&&', '||', and '?'.
@@ -1306,6 +1441,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
}
}
+
+ return PDB.getBugReport()->isValid();
}
//===----------------------------------------------------------------------===//
@@ -1414,6 +1551,12 @@ void BugReport::markInteresting(SVal V) {
markInteresting(V.getAsSymbol());
}
+void BugReport::markInteresting(const LocationContext *LC) {
+ if (!LC)
+ return;
+ InterestingLocationContexts.insert(LC);
+}
+
bool BugReport::isInteresting(SVal V) {
return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
}
@@ -1438,6 +1581,12 @@ bool BugReport::isInteresting(const MemRegion *R) {
return false;
}
+bool BugReport::isInteresting(const LocationContext *LC) {
+ if (!LC)
+ return false;
+ return InterestingLocationContexts.count(LC);
+}
+
void BugReport::lazyInitializeInterestingSets() {
if (interestingSymbols.empty()) {
interestingSymbols.push_back(new Symbols());
@@ -1823,17 +1972,27 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
path.push_back(*I);
}
-void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticConsumer &PC,
ArrayRef<BugReport *> &bugReports) {
-
assert(!bugReports.empty());
+
+ bool HasValid = false;
SmallVector<const ExplodedNode *, 10> errorNodes;
for (ArrayRef<BugReport*>::iterator I = bugReports.begin(),
E = bugReports.end(); I != E; ++I) {
+ if ((*I)->isValid()) {
+ HasValid = true;
errorNodes.push_back((*I)->getErrorNode());
+ } else {
+ errorNodes.push_back(0);
+ }
}
+ // If all the reports have been marked invalid, we're done.
+ if (!HasValid)
+ return false;
+
// Construct a new graph that contains only a single path from the error
// node to a root.
const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
@@ -1844,6 +2003,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
assert(GPair.second.second < bugReports.size());
BugReport *R = bugReports[GPair.second.second];
assert(R && "No original report found for sliced graph.");
+ assert(R->isValid() && "Report selected from trimmed graph marked invalid.");
OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
OwningPtr<NodeBackMap> BackMap(GPair.first.second);
@@ -1870,36 +2030,53 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
visitors.push_back((*I)->clone());
// Clear out the active path from any previous work.
- PD.getActivePath().clear();
+ PD.resetPath();
originalReportConfigToken = R->getConfigurationChangeToken();
// Generate the very last diagnostic piece - the piece is visible before
// the trace is expanded.
- PathDiagnosticPiece *LastPiece = 0;
- for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
- I != E; ++I) {
- if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
- assert (!LastPiece &&
- "There can only be one final piece in a diagnostic.");
- LastPiece = Piece;
+ if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) {
+ PathDiagnosticPiece *LastPiece = 0;
+ for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
+ I != E; ++I) {
+ if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
+ assert (!LastPiece &&
+ "There can only be one final piece in a diagnostic.");
+ LastPiece = Piece;
+ }
}
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ if (LastPiece)
+ PD.setEndOfPath(LastPiece);
+ else
+ return false;
}
- if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
- if (LastPiece)
- PD.getActivePath().push_back(LastPiece);
- else
- return;
switch (PDB.getGenerationScheme()) {
case PathDiagnosticConsumer::Extensive:
- GenerateExtensivePathDiagnostic(PD, PDB, N, visitors);
+ if (!GenerateExtensivePathDiagnostic(PD, PDB, N, visitors)) {
+ assert(!R->isValid() && "Failed on valid report");
+ // Try again. We'll filter out the bad report when we trim the graph.
+ // FIXME: It would be more efficient to use the same intermediate
+ // trimmed graph, and just repeat the shortest-path search.
+ return generatePathDiagnostic(PD, PC, bugReports);
+ }
break;
case PathDiagnosticConsumer::Minimal:
- GenerateMinimalPathDiagnostic(PD, PDB, N, visitors);
+ if (!GenerateMinimalPathDiagnostic(PD, PDB, N, visitors)) {
+ assert(!R->isValid() && "Failed on valid report");
+ // Try again. We'll filter out the bad report when we trim the graph.
+ return generatePathDiagnostic(PD, PC, bugReports);
+ }
break;
case PathDiagnosticConsumer::None:
- llvm_unreachable("PathDiagnosticConsumer::None should never appear here");
+ if (!GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors)) {
+ assert(!R->isValid() && "Failed on valid report");
+ // Try again. We'll filter out the bad report when we trim the graph.
+ return generatePathDiagnostic(PD, PC, bugReports);
+ }
+ break;
}
// Clean up the visitors we used.
@@ -1910,18 +2087,26 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
} while(finalReportConfigToken != originalReportConfigToken);
// Finally, prune the diagnostic path of uninteresting stuff.
- if (R->shouldPrunePath()) {
- bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces());
- assert(hasSomethingInteresting);
- (void) hasSomethingInteresting;
+ if (!PD.path.empty()) {
+ // Remove messages that are basically the same.
+ removeRedundantMsgs(PD.getMutablePieces());
+
+ if (R->shouldPrunePath()) {
+ bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(),
+ R);
+ assert(hasSomethingInteresting);
+ (void) hasSomethingInteresting;
+ }
}
+
+ return true;
}
void BugReporter::Register(BugType *BT) {
BugTypes = F.add(BugTypes, BT);
}
-void BugReporter::EmitReport(BugReport* R) {
+void BugReporter::emitReport(BugReport* R) {
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
@@ -2078,17 +2263,17 @@ void BugReporter::FlushReport(BugReport *exampleReport,
OwningPtr<PathDiagnostic>
D(new PathDiagnostic(exampleReport->getDeclWithIssue(),
exampleReport->getBugType().getName(),
- PD.useVerboseDescription()
- ? exampleReport->getDescription()
- : exampleReport->getShortDescription(),
+ exampleReport->getDescription(),
+ exampleReport->getShortDescription(/*Fallback=*/false),
BT.getCategory()));
// Generate the full path diagnostic, using the generation scheme
- // specified by the PathDiagnosticConsumer.
- if (PD.getGenerationScheme() != PathDiagnosticConsumer::None) {
- if (!bugReports.empty())
- GeneratePathDiagnostic(*D.get(), PD, bugReports);
- }
+ // specified by the PathDiagnosticConsumer. Note that we have to generate
+ // path diagnostics even for consumers which do not support paths, because
+ // the BugReporterVisitors may mark this bug as a false positive.
+ if (!bugReports.empty())
+ if (!generatePathDiagnostic(*D.get(), PD, bugReports))
+ return;
// If the path is empty, generate a single step path with the location
// of the issue.
@@ -2100,7 +2285,7 @@ void BugReporter::FlushReport(BugReport *exampleReport,
llvm::tie(Beg, End) = exampleReport->getRanges();
for ( ; Beg != End; ++Beg)
piece->addRange(*Beg);
- D->getActivePath().push_back(piece);
+ D->setEndOfPath(piece);
}
// Get the meta data.
@@ -2124,7 +2309,7 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
BugReport *R = new BugReport(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
- EmitReport(R);
+ emitReport(R);
}
BugType *BugReporter::getBugTypeForName(StringRef name,
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e7295878fa6f..328e8a650df1 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -17,10 +17,13 @@
#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
@@ -29,10 +32,24 @@ using namespace ento;
// Utility functions.
//===----------------------------------------------------------------------===//
+bool bugreporter::isDeclRefExprToReference(const Expr *E) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ return DRE->getDecl()->getType()->isReferenceType();
+ }
+ return false;
+}
+
const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+ const PostStmt *Loc = N->getLocationAs<PostStmt>();
+ if (!Loc)
+ return 0;
+
+ const Expr *S = dyn_cast<Expr>(Loc->getStmt());
+ if (!S)
+ return 0;
+ S = S->IgnoreParenCasts();
while (true) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
@@ -45,7 +62,12 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
return U->getSubExpr()->IgnoreParenCasts();
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
- return ME->getBase()->IgnoreParenCasts();
+ if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
+ return ME->getBase()->IgnoreParenCasts();
+ }
+ }
+ else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) {
+ return IvarRef->getBase()->IgnoreParenCasts();
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
return AE->getBase();
@@ -103,6 +125,228 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
}
+namespace {
+/// Emits an extra note at the return statement of an interesting stack frame.
+///
+/// The returned value is marked as an interesting value, and if it's null,
+/// adds a visitor to track where it became null.
+///
+/// This visitor is intended to be used when another visitor discovers that an
+/// interesting value comes from an inlined function call.
+class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
+ const StackFrameContext *StackFrame;
+ enum {
+ Initial,
+ MaybeSuppress,
+ Satisfied
+ } Mode;
+
+public:
+ ReturnVisitor(const StackFrameContext *Frame)
+ : StackFrame(Frame), Mode(Initial) {}
+
+ static void *getTag() {
+ static int Tag = 0;
+ return static_cast<void *>(&Tag);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(ReturnVisitor::getTag());
+ ID.AddPointer(StackFrame);
+ }
+
+ /// Adds a ReturnVisitor if the given statement represents a call that was
+ /// inlined.
+ ///
+ /// This will search back through the ExplodedGraph, starting from the given
+ /// node, looking for when the given statement was processed. If it turns out
+ /// the statement is a call that was inlined, we add the visitor to the
+ /// bug report, so it can print a note later.
+ static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
+ BugReport &BR) {
+ if (!CallEvent::isCallStmt(S))
+ return;
+
+ // First, find when we processed the statement.
+ do {
+ if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>())
+ if (CEE->getCalleeContext()->getCallSite() == S)
+ break;
+ if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>())
+ if (SP->getStmt() == S)
+ break;
+
+ Node = Node->getFirstPred();
+ } while (Node);
+
+ // Next, step over any post-statement checks.
+ while (Node && isa<PostStmt>(Node->getLocation()))
+ Node = Node->getFirstPred();
+
+ // Finally, see if we inlined the call.
+ if (Node) {
+ if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) {
+ const StackFrameContext *CalleeContext = CEE->getCalleeContext();
+ if (CalleeContext->getCallSite() == S) {
+ BR.markInteresting(CalleeContext);
+ BR.addVisitor(new ReturnVisitor(CalleeContext));
+ }
+ }
+ }
+ }
+
+ /// Returns true if any counter-suppression heuristics are enabled for
+ /// ReturnVisitor.
+ static bool hasCounterSuppression(AnalyzerOptions &Options) {
+ return Options.shouldAvoidSuppressingNullArgumentPaths();
+ }
+
+ PathDiagnosticPiece *visitNodeInitial(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // Only print a message at the interesting return statement.
+ if (N->getLocationContext() != StackFrame)
+ return 0;
+
+ const StmtPoint *SP = N->getLocationAs<StmtPoint>();
+ if (!SP)
+ return 0;
+
+ const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt());
+ if (!Ret)
+ return 0;
+
+ // Okay, we're at the right return statement, but do we have the return
+ // value available?
+ ProgramStateRef State = N->getState();
+ SVal V = State->getSVal(Ret, StackFrame);
+ if (V.isUnknownOrUndef())
+ return 0;
+
+ // Don't print any more notes after this one.
+ Mode = Satisfied;
+
+ const Expr *RetE = Ret->getRetValue();
+ assert(RetE && "Tracking a return value for a void function");
+ RetE = RetE->IgnoreParenCasts();
+
+ // If we can't prove the return value is 0, just mark it interesting, and
+ // make sure to track it into any further inner functions.
+ if (State->assume(cast<DefinedSVal>(V), true)) {
+ BR.markInteresting(V);
+ ReturnVisitor::addVisitorIfNecessary(N, RetE, BR);
+ return 0;
+ }
+
+ // If we're returning 0, we should track where that 0 came from.
+ bugreporter::trackNullOrUndefValue(N, RetE, BR);
+
+ // Build an appropriate message based on the return value.
+ SmallString<64> Msg;
+ llvm::raw_svector_ostream Out(Msg);
+
+ if (isa<Loc>(V)) {
+ // If we are pruning null-return paths as unlikely error paths, mark the
+ // report invalid. We still want to emit a path note, however, in case
+ // the report is resurrected as valid later on.
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ if (Options.shouldPruneNullReturnPaths()) {
+ if (hasCounterSuppression(Options))
+ Mode = MaybeSuppress;
+ else
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ }
+
+ if (RetE->getType()->isObjCObjectPointerType())
+ Out << "Returning nil";
+ else
+ Out << "Returning null pointer";
+ } else {
+ Out << "Returning zero";
+ }
+
+ // FIXME: We should have a more generalized location printing mechanism.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
+ Out << " (loaded from '" << *DD << "')";
+
+ PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
+ return new PathDiagnosticEventPiece(L, Out.str());
+ }
+
+ PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // Are we at the entry node for this call?
+ const CallEnter *CE = N->getLocationAs<CallEnter>();
+ if (!CE)
+ return 0;
+
+ if (CE->getCalleeContext() != StackFrame)
+ return 0;
+
+ Mode = Satisfied;
+
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ if (Options.shouldAvoidSuppressingNullArgumentPaths()) {
+ // Don't automatically suppress a report if one of the arguments is
+ // known to be a null pointer. Instead, start tracking /that/ null
+ // value back to its origin.
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
+
+ ProgramStateRef State = N->getState();
+ CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
+ for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
+ SVal ArgV = Call->getArgSVal(I);
+ if (!isa<Loc>(ArgV))
+ continue;
+
+ const Expr *ArgE = Call->getArgExpr(I);
+ if (!ArgE)
+ continue;
+
+ // Is it possible for this argument to be non-null?
+ if (State->assume(cast<Loc>(ArgV), true))
+ continue;
+
+ if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
+ return 0;
+
+ // If we /can't/ track the null pointer, we should err on the side of
+ // false negatives, and continue towards marking this report invalid.
+ // (We will still look at the other arguments, though.)
+ }
+ }
+
+ // There is no reason not to suppress this report; go ahead and do it.
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ return 0;
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ switch (Mode) {
+ case Initial:
+ return visitNodeInitial(N, PrevN, BRC, BR);
+ case MaybeSuppress:
+ return visitNodeMaybeSuppress(N, PrevN, BRC, BR);
+ case Satisfied:
+ return 0;
+ }
+
+ llvm_unreachable("Invalid visit mode!");
+ }
+};
+} // end anonymous namespace
+
+
void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
ID.AddPointer(&tag);
@@ -110,59 +354,90 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
ID.Add(V);
}
-PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
if (satisfied)
return NULL;
- if (!StoreSite) {
- // Make sure the region is actually bound to value V here.
- // This is necessary because the region may not actually be live at the
- // report's error node.
- if (N->getState()->getSVal(R) != V)
- return NULL;
-
- const ExplodedNode *Node = N, *Last = N;
-
- // Now look for the store of V.
- for ( ; Node ; Node = Node->getFirstPred()) {
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- if (const PostStmt *P = Node->getLocationAs<PostStmt>())
- if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
- if (DS->getSingleDecl() == VR->getDecl()) {
- // Record the last seen initialization point.
- Last = Node;
- break;
- }
+ const ExplodedNode *StoreSite = 0;
+ const Expr *InitE = 0;
+ bool IsParam = false;
+
+ // First see if we reached the declaration of the region.
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) {
+ if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) {
+ if (DS->getSingleDecl() == VR->getDecl()) {
+ StoreSite = Pred;
+ InitE = VR->getDecl()->getInit();
+ }
}
-
- // Does the region still bind to value V? If not, we are done
- // looking for store sites.
- if (Node->getState()->getSVal(R) != V)
- break;
-
- Last = Node;
}
+ }
- if (!Node) {
- satisfied = true;
+ // Otherwise, check that Succ has this binding and Pred does not, i.e. this is
+ // where the binding first occurred.
+ if (!StoreSite) {
+ if (Succ->getState()->getSVal(R) != V)
+ return NULL;
+ if (Pred->getState()->getSVal(R) == V)
return NULL;
- }
- StoreSite = Last;
+ StoreSite = Succ;
+
+ // If this is an assignment expression, we can track the value
+ // being assigned.
+ if (const PostStmt *P = Succ->getLocationAs<PostStmt>())
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
+ if (BO->isAssignmentOp())
+ InitE = BO->getRHS();
+
+ // If this is a call entry, the variable should be a parameter.
+ // FIXME: Handle CXXThisRegion as well. (This is not a priority because
+ // 'this' should never be NULL, but this visitor isn't just for NULL and
+ // UndefinedVal.)
+ if (const CallEnter *CE = Succ->getLocationAs<CallEnter>()) {
+ const VarRegion *VR = cast<VarRegion>(R);
+ const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
+
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
+
+ CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
+ Succ->getState());
+ InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
+ IsParam = true;
+ }
}
- if (StoreSite != N)
+ if (!StoreSite)
return NULL;
-
satisfied = true;
+
+ // If we have an expression that provided the value, try to track where it
+ // came from.
+ if (InitE) {
+ if (V.isUndef() || isa<loc::ConcreteInt>(V)) {
+ if (!IsParam)
+ InitE = InitE->IgnoreParenCasts();
+ bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam);
+ } else {
+ ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(),
+ BR);
+ }
+ }
+
+ if (!R->canPrintPretty())
+ return 0;
+
+ // Okay, we've found the binding. Emit an appropriate message.
SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
- if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
+ if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -201,6 +476,30 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
os << "initialized here";
}
}
+ } else if (isa<CallEnter>(StoreSite->getLocation())) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl());
+
+ os << "Passing ";
+
+ if (isa<loc::ConcreteInt>(V)) {
+ if (Param->getType()->isObjCObjectPointerType())
+ os << "nil object reference";
+ else
+ os << "null pointer value";
+ } else if (V.isUndef()) {
+ os << "uninitialized value";
+ } else if (isa<nonloc::ConcreteInt>(V)) {
+ os << "the value " << cast<nonloc::ConcreteInt>(V).getValue();
+ } else {
+ os << "value";
+ }
+
+ // Printed parameter indexes are 1-based, not 0-based.
+ unsigned Idx = Param->getFunctionScopeIndex() + 1;
+ os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '";
+
+ R->printPretty(os);
+ os << '\'';
}
if (os.str().empty()) {
@@ -228,17 +527,19 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
else
os << "Value assigned to ";
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << *VR->getDecl() << '\'';
- }
- else
- return NULL;
+ os << '\'';
+ R->printPretty(os);
+ os << '\'';
}
// Construct a new PathDiagnosticPiece.
- ProgramPoint P = N->getLocation();
- PathDiagnosticLocation L =
- PathDiagnosticLocation::create(P, BRC.getSourceManager());
+ ProgramPoint P = StoreSite->getLocation();
+ PathDiagnosticLocation L;
+ if (isa<CallEnter>(P))
+ L = PathDiagnosticLocation(InitE, BRC.getSourceManager(),
+ P.getLocationContext());
+ else
+ L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid())
return NULL;
return new PathDiagnosticEventPiece(L, os.str());
@@ -251,6 +552,12 @@ void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
ID.Add(Constraint);
}
+/// Return the tag associated with this visitor. This tag will be used
+/// to make all PathDiagnosticPieces created by this visitor.
+const char *TrackConstraintBRVisitor::getTag() {
+ return "TrackConstraintBRVisitor";
+}
+
PathDiagnosticPiece *
TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
@@ -290,62 +597,97 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid())
return NULL;
- return new PathDiagnosticEventPiece(L, os.str());
+
+ PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str());
+ X->setTag(getTag());
+ return X;
}
return NULL;
}
-void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S,
- BugReport *report) {
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
+ BugReport &report, bool IsArg) {
if (!S || !N)
- return;
+ return false;
- ProgramStateManager &StateMgr = N->getState()->getStateManager();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
+ S = OVE->getSourceExpr();
+
+ if (IsArg) {
+ assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
+ } else {
+ // Walk through nodes until we get one that matches the statement exactly.
+ do {
+ const ProgramPoint &pp = N->getLocation();
+ if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
+ if (ps->getStmt() == S)
+ break;
+ } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
+ if (CEE->getCalleeContext()->getCallSite() == S)
+ break;
+ }
+ N = N->getFirstPred();
+ } while (N);
- // Walk through nodes until we get one that matches the statement
- // exactly.
- while (N) {
- const ProgramPoint &pp = N->getLocation();
- if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
- if (ps->getStmt() == S)
- break;
- }
- N = N->getFirstPred();
+ if (!N)
+ return false;
}
-
- if (!N)
- return;
ProgramStateRef state = N->getState();
- // Walk through lvalue-to-rvalue conversions.
- const Expr *Ex = dyn_cast<Expr>(S);
- if (Ex) {
+ // See if the expression we're interested refers to a variable.
+ // If so, we can track both its contents and constraints on its value.
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ // Strip off parens and casts. Note that this will never have issues with
+ // C++ user-defined implicit conversions, because those have a constructor
+ // or function call inside.
Ex = Ex->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
+ // FIXME: Right now we only track VarDecls because it's non-trivial to
+ // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const VarRegion *R =
- StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
+ ProgramStateManager &StateMgr = state->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());
- // What did we load?
+ // Mark both the variable region and its contents as interesting.
SVal V = state->getRawSVal(loc::MemRegionVal(R));
- report->markInteresting(R);
- report->markInteresting(V);
+ // If the value matches the default for the variable region, that
+ // might mean that it's been cleared out of the state. Fall back to
+ // the full argument expression (with casts and such intact).
+ if (IsArg) {
+ bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
+ if (!UseArgValue) {
+ const SymbolRegionValue *SRV =
+ dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
+ if (SRV)
+ UseArgValue = (SRV->getRegion() == R);
+ }
+ if (UseArgValue)
+ V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ }
+
+ report.markInteresting(R);
+ report.markInteresting(V);
+ report.addVisitor(new UndefOrNullArgVisitor(R));
+
+ // If the contents are symbolic, find out when they became null.
if (V.getAsLocSymbol()) {
BugReporterVisitor *ConstraintTracker
- = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false);
- report->addVisitor(ConstraintTracker);
+ = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false);
+ report.addVisitor(ConstraintTracker);
}
- report->addVisitor(new FindLastStoreBRVisitor(V, R));
- return;
+ report.addVisitor(new FindLastStoreBRVisitor(V, R));
+ return true;
}
}
}
+ // If the expression does NOT refer to a variable, we can still track
+ // constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
// Uncomment this to find cases where we aren't properly getting the
@@ -354,17 +696,27 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N,
// Is it a symbolic value?
if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
- const SubRegion *R = cast<SubRegion>(L->getRegion());
- while (R && !isa<SymbolicRegion>(R)) {
- R = dyn_cast<SubRegion>(R->getSuperRegion());
- }
+ // At this point we are dealing with the region's LValue.
+ // However, if the rvalue is a symbolic region, we should track it as well.
+ SVal RVal = state->getSVal(L->getRegion());
+ const MemRegion *RegionRVal = RVal.getAsRegion();
+ report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));
+
- if (R) {
- report->markInteresting(R);
- report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(R),
- false));
+ if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
+ report.markInteresting(RegionRVal);
+ report.addVisitor(new TrackConstraintBRVisitor(
+ loc::MemRegionVal(RegionRVal), false));
}
+ } else {
+ // Otherwise, if the value came from an inlined function call,
+ // we should at least make sure that function isn't pruned in our output.
+ if (const Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParenCasts();
+ ReturnVisitor::addVisitorIfNecessary(N, S, report);
}
+
+ return true;
}
BugReporterVisitor *
@@ -406,7 +758,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// The receiver was nil, and hence the method was skipped.
// Register a BugReporterVisitor to issue a message telling us how
// the receiver was null.
- bugreporter::addTrackNullOrUndefValueVisitor(N, Receiver, &BR);
+ bugreporter::trackNullOrUndefValue(N, Receiver, BR);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -452,14 +804,23 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
//===----------------------------------------------------------------------===//
// Visitor that tries to report interesting diagnostics from conditions.
//===----------------------------------------------------------------------===//
+
+/// Return the tag associated with this visitor. This tag will be used
+/// to make all PathDiagnosticPieces created by this visitor.
+const char *ConditionBRVisitor::getTag() {
+ return "ConditionBRVisitor";
+}
+
PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
BugReporterContext &BRC,
BugReport &BR) {
PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR);
- if (PathDiagnosticEventPiece *ev =
- dyn_cast_or_null<PathDiagnosticEventPiece>(piece))
- ev->setPrunable(true, /* override */ false);
+ if (piece) {
+ piece->setTag(getTag());
+ if (PathDiagnosticEventPiece *ev=dyn_cast<PathDiagnosticEventPiece>(piece))
+ ev->setPrunable(true, /* override */ false);
+ }
return piece;
}
@@ -468,8 +829,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) {
- const ProgramPoint &progPoint = N->getLocation();
-
+ ProgramPoint progPoint = N->getLocation();
ProgramStateRef CurrentState = N->getState();
ProgramStateRef PrevState = Prev->getState();
@@ -494,7 +854,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// violation.
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
cast<GRBugReporter>(BRC.getBugReporter()).
- getEngine().getEagerlyAssumeTags();
+ getEngine().geteagerlyAssumeBinOpBifurcationTags();
const ProgramPointTag *tag = PS->getTag();
if (tag == tags.first)
@@ -533,8 +893,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
assert(Cond);
assert(srcBlk->succ_size() == 2);
const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
- return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
- tookTrue, BRC, R, N);
+ return VisitTrueTest(Cond, tookTrue, BRC, R, N);
}
PathDiagnosticPiece *
@@ -547,7 +906,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const Expr *Ex = Cond;
while (true) {
- Ex = Ex->IgnoreParens();
+ Ex = Ex->IgnoreParenCasts();
switch (Ex->getStmtClass()) {
default:
return 0;
@@ -561,7 +920,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const UnaryOperator *UO = cast<UnaryOperator>(Ex);
if (UO->getOpcode() == UO_LNot) {
tookTrue = !tookTrue;
- Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext());
+ Ex = UO->getSubExpr();
continue;
}
return 0;
@@ -802,3 +1161,54 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
return event;
}
+PathDiagnosticPiece *
+UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+
+ ProgramStateRef State = N->getState();
+ ProgramPoint ProgLoc = N->getLocation();
+
+ // We are only interested in visiting CallEnter nodes.
+ CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc);
+ if (!CEnter)
+ return 0;
+
+ // Check if one of the arguments is the region the visitor is tracking.
+ CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
+ unsigned Idx = 0;
+ for (CallEvent::param_iterator I = Call->param_begin(),
+ E = Call->param_end(); I != E; ++I, ++Idx) {
+ const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
+
+ // Are we tracking the argument or its subregion?
+ if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts())))
+ continue;
+
+ // Check the function parameter type.
+ const ParmVarDecl *ParamDecl = *I;
+ assert(ParamDecl && "Formal parameter has no decl?");
+ QualType T = ParamDecl->getType();
+
+ if (!(T->isAnyPointerType() || T->isReferenceType())) {
+ // Function can only change the value passed in by address.
+ continue;
+ }
+
+ // If it is a const pointer value, the function does not intend to
+ // change the value.
+ if (T->getPointeeType().isConstQualified())
+ continue;
+
+ // Mark the call site (LocationContext) as interesting if the value of the
+ // argument is undefined or '0'/'NULL'.
+ SVal BoundVal = State->getSVal(R);
+ if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
+ BR.markInteresting(CEnter->getCalleeContext());
+ return 0;
+ }
+ }
+ return 0;
+}
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index b16b233d6346..91f15b31da63 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -1,9 +1,9 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangStaticAnalyzerCore
- AnalysisManager.cpp
APSIntType.cpp
- BasicConstraintManager.cpp
+ AnalysisManager.cpp
+ AnalyzerOptions.cpp
BasicValueFactory.cpp
BlockCounter.cpp
BugReporter.cpp
@@ -14,6 +14,7 @@ add_clang_library(clangStaticAnalyzerCore
CheckerHelpers.cpp
CheckerManager.cpp
CheckerRegistry.cpp
+ ConstraintManager.cpp
CoreEngine.cpp
Environment.cpp
ExplodedGraph.cpp
@@ -54,5 +55,5 @@ target_link_libraries(clangStaticAnalyzerCore
clangLex
clangAST
clangFrontend
- clangRewrite
+ clangRewriteCore
)
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 5345bd517045..c5cb317bd18d 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallSet.h"
@@ -23,10 +24,26 @@ using namespace clang;
using namespace ento;
QualType CallEvent::getResultType() const {
- QualType ResultTy = getDeclaredResultType();
+ const Expr *E = getOriginExpr();
+ assert(E && "Calls without origin expressions do not have results");
+ QualType ResultTy = E->getType();
- if (ResultTy.isNull())
- ResultTy = getOriginExpr()->getType();
+ ASTContext &Ctx = getState()->getStateManager().getContext();
+
+ // A function that returns a reference to 'int' will have a result type
+ // of simply 'int'. Check the origin expr's value kind to recover the
+ // proper type.
+ switch (E->getValueKind()) {
+ case VK_LValue:
+ ResultTy = Ctx.getLValueReferenceType(ResultTy);
+ break;
+ case VK_XValue:
+ ResultTy = Ctx.getRValueReferenceType(ResultTy);
+ break;
+ case VK_RValue:
+ // No adjustment is necessary.
+ break;
+ }
return ResultTy;
}
@@ -45,7 +62,7 @@ static bool isCallbackArg(SVal V, QualType T) {
// Check if a callback is passed inside a struct (for both, struct passed by
// reference and by value). Dig just one level into the struct for now.
- if (isa<PointerType>(T) || isa<ReferenceType>(T))
+ if (T->isAnyPointerType() || T->isReferenceType())
T = T->getPointeeType();
if (const RecordType *RT = T->getAsStructureType()) {
@@ -83,6 +100,14 @@ bool CallEvent::hasNonZeroCallbackArg() const {
return false;
}
+bool CallEvent::isGlobalCFunction(StringRef FunctionName) const {
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
+ if (!FD)
+ return false;
+
+ return CheckerContext::isCLibraryFunction(FD, FunctionName);
+}
+
/// \brief Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {
@@ -207,6 +232,13 @@ SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
return ArgE->getSourceRange();
}
+SVal CallEvent::getReturnValue() const {
+ const Expr *E = getOriginExpr();
+ if (!E)
+ return UndefinedVal();
+ return getSVal(E);
+}
+
void CallEvent::dump() const {
dump(llvm::errs());
}
@@ -230,10 +262,20 @@ void CallEvent::dump(raw_ostream &Out) const {
}
-bool CallEvent::mayBeInlined(const Stmt *S) {
- // FIXME: Kill this.
+bool CallEvent::isCallStmt(const Stmt *S) {
return isa<CallExpr>(S) || isa<ObjCMessageExpr>(S)
- || isa<CXXConstructExpr>(S);
+ || isa<CXXConstructExpr>(S)
+ || isa<CXXNewExpr>(S);
+}
+
+/// \brief Returns the result type, adjusted for references.
+QualType CallEvent::getDeclaredResultType(const Decl *D) {
+ assert(D);
+ if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
+ return FD->getResultType();
+ else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->getResultType();
+ return QualType();
}
static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
@@ -285,14 +327,6 @@ void AnyFunctionCall::getInitialStackFrameContents(
D->param_begin(), D->param_end());
}
-QualType AnyFunctionCall::getDeclaredResultType() const {
- const FunctionDecl *D = getDecl();
- if (!D)
- return QualType();
-
- return D->getResultType();
-}
-
bool AnyFunctionCall::argumentsMayEscape() const {
if (hasNonZeroCallbackArg())
return true;
@@ -303,7 +337,7 @@ bool AnyFunctionCall::argumentsMayEscape() const {
const IdentifierInfo *II = D->getIdentifier();
if (!II)
- return true;
+ return false;
// This set of "escaping" APIs is
@@ -376,6 +410,17 @@ void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const {
Regions.push_back(R);
}
+SVal CXXInstanceCall::getCXXThisVal() const {
+ const Expr *Base = getCXXThisExpr();
+ // FIXME: This doesn't handle an overloaded ->* operator.
+ if (!Base)
+ return UnknownVal();
+
+ SVal ThisVal = getSVal(Base);
+ assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
+ return ThisVal;
+}
+
RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// Do we have a decl at all?
@@ -400,13 +445,30 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// Is the type a C++ class? (This is mostly a defensive check.)
QualType RegionType = DynType.getType()->getPointeeType();
+ assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer.");
+
const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl();
if (!RD || !RD->hasDefinition())
return RuntimeDefinition();
// Find the decl for this method in that class.
const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true);
- assert(Result && "At the very least the static decl should show up.");
+ if (!Result) {
+ // We might not even get the original statically-resolved method due to
+ // some particularly nasty casting (e.g. casts to sister classes).
+ // However, we should at least be able to search up and down our own class
+ // hierarchy, and some real bugs have been caught by checking this.
+ assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
+
+ // FIXME: This is checking that our DynamicTypeInfo is at least as good as
+ // the static type. However, because we currently don't update
+ // DynamicTypeInfo when an object is cast, we can't actually be sure the
+ // DynamicTypeInfo is up to date. This assert should be re-enabled once
+ // this is fixed. <rdar://problem/12287087>
+ //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
+
+ return RuntimeDefinition();
+ }
// Does the decl that we found have an implementation?
const FunctionDecl *Definition;
@@ -459,6 +521,18 @@ const Expr *CXXMemberCall::getCXXThisExpr() const {
return getOriginExpr()->getImplicitObjectArgument();
}
+RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const {
+ // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the
+ // id-expression in the class member access expression is a qualified-id,
+ // that function is called. Otherwise, its final overrider in the dynamic type
+ // of the object expression is called.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee()))
+ if (ME->hasQualifier())
+ return AnyFunctionCall::getRuntimeDefinition();
+
+ return CXXInstanceCall::getRuntimeDefinition();
+}
+
const Expr *CXXMemberOperatorCall::getCXXThisExpr() const {
return getOriginExpr()->getArg(0);
@@ -501,15 +575,6 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
}
-QualType BlockCall::getDeclaredResultType() const {
- const BlockDataRegion *BR = getBlockRegion();
- if (!BR)
- return QualType();
- QualType BlockTy = BR->getCodeRegion()->getLocationType();
- return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
-}
-
-
SVal CXXConstructorCall::getCXXThisVal() const {
if (Data)
return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
@@ -539,10 +604,19 @@ void CXXConstructorCall::getInitialStackFrameContents(
SVal CXXDestructorCall::getCXXThisVal() const {
if (Data)
- return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
+ return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer());
return UnknownVal();
}
+RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
+ // Base destructors are always called non-virtually.
+ // Skip CXXInstanceCall's devirtualization logic in this case.
+ if (isBaseDestructor())
+ return AnyFunctionCall::getRuntimeDefinition();
+
+ return CXXInstanceCall::getRuntimeDefinition();
+}
+
CallEvent::param_iterator ObjCMethodCall::param_begin() const {
const ObjCMethodDecl *D = getDecl();
@@ -566,12 +640,12 @@ ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const {
Regions.push_back(R);
}
-QualType ObjCMethodCall::getDeclaredResultType() const {
- const ObjCMethodDecl *D = getDecl();
- if (!D)
- return QualType();
-
- return D->getResultType();
+SVal ObjCMethodCall::getSelfSVal() const {
+ const LocationContext *LCtx = getLocationContext();
+ const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
+ if (!SelfDecl)
+ return SVal();
+ return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
}
SVal ObjCMethodCall::getReceiverSVal() const {
@@ -584,10 +658,23 @@ SVal ObjCMethodCall::getReceiverSVal() const {
// An instance message with no expression means we are sending to super.
// In this case the object reference is the same as 'self'.
- const LocationContext *LCtx = getLocationContext();
- const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
- assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
- return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
+ assert(getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+ SVal SelfVal = getSelfSVal();
+ assert(SelfVal.isValid() && "Calling super but not in ObjC method");
+ return SelfVal;
+}
+
+bool ObjCMethodCall::isReceiverSelfOrSuper() const {
+ if (getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance ||
+ getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperClass)
+ return true;
+
+ if (!isInstanceMessage())
+ return false;
+
+ SVal RecVal = getSVal(getOriginExpr()->getInstanceReceiver());
+
+ return (RecVal == getSelfSVal());
}
SourceRange ObjCMethodCall::getSourceRange() const {
@@ -820,7 +907,8 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
return getSimpleCall(CE, State, CallerCtx);
switch (CallSite->getStmtClass()) {
- case Stmt::CXXConstructExprClass: {
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXTemporaryObjectExprClass: {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
@@ -858,5 +946,5 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
Trigger = Dtor->getBody();
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
- State, CallerCtx);
+ isa<CFGBaseDtor>(E), State, CallerCtx);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 0a047d922aa9..74eeef1c67a8 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -38,17 +38,14 @@ StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
StringRef Name) {
- return isCLibraryFunction(FD, Name, getASTContext());
-}
-
-bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
- StringRef Name, ASTContext &Context) {
// To avoid false positives (Ex: finding user defined functions with
// similar names), only perform fuzzy name matching when it's a builtin.
// Using a string compare is slow, we might want to switch on BuiltinID here.
unsigned BId = FD->getBuiltinID();
if (BId != 0) {
- StringRef BName = Context.BuiltinInfo.GetName(BId);
+ if (Name.empty())
+ return true;
+ StringRef BName = FD->getASTContext().BuiltinInfo.GetName(BId);
if (BName.find(Name) != StringRef::npos)
return true;
}
@@ -59,6 +56,24 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
if (!II)
return false;
+ // Look through 'extern "C"' and anything similar invented in the future.
+ const DeclContext *DC = FD->getDeclContext();
+ while (DC->isTransparentContext())
+ DC = DC->getParent();
+
+ // If this function is in a namespace, it is not a C library function.
+ if (!DC->isTranslationUnit())
+ return false;
+
+ // 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)
+ return false;
+
+ if (Name.empty())
+ return true;
+
StringRef FName = II->getName();
if (FName.equals(Name))
return true;
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index c7866559c6d7..3672952b8f6e 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -36,8 +36,7 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
!DeadSymbolsCheckers.empty() ||
!RegionChangesCheckers.empty() ||
!EvalAssumeCheckers.empty() ||
- !EvalCallCheckers.empty() ||
- !InlineCallCheckers.empty();
+ !EvalCallCheckers.empty();
}
void CheckerManager::finishedCheckerRegistration() {
@@ -314,20 +313,19 @@ namespace {
SVal Val;
const Stmt *S;
ExprEngine &Eng;
- ProgramPoint::Kind PointKind;
+ const ProgramPoint &PP;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
- ProgramPoint::Kind PK)
- : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
+ const ProgramPoint &pp)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {}
void runChecker(CheckerManager::CheckBindFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
- Pred->getLocationContext(), checkFn.Checker);
+ const ProgramPoint &L = PP.withTag(checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
checkFn(Loc, Val, S, C);
@@ -340,8 +338,8 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng,
- ProgramPoint::Kind PointKind) {
- CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
+ const ProgramPoint &PP) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng, PP);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -357,8 +355,8 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
// for this callback since end of path nodes are expected to be final.
void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
ExprEngine &Eng) {
- ExplodedNode *Pred = BC.Pred;
// We define the builder outside of the loop bacause if at least one checkers
// creates a sucsessor for Pred, we do not need to generate an
@@ -509,41 +507,13 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
for (ExplodedNodeSet::iterator
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
-
ExplodedNode *Pred = *NI;
bool anyEvaluated = false;
- // First, check if any of the InlineCall callbacks can evaluate the call.
- assert(InlineCallCheckers.size() <= 1 &&
- "InlineCall is a special hacky callback to allow intrusive"
- "evaluation of the call (which simulates inlining). It is "
- "currently only used by OSAtomicChecker and should go away "
- "at some point.");
- for (std::vector<InlineCallFunc>::iterator
- EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
- EI != EE; ++EI) {
- ExplodedNodeSet checkDst;
- bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
- assert(!(evaluated && anyEvaluated)
- && "There are more than one checkers evaluating the call");
- if (evaluated) {
- anyEvaluated = true;
- Dst.insert(checkDst);
-#ifdef NDEBUG
- break; // on release don't check that no other checker also evals.
-#endif
- }
- }
-
-#ifdef NDEBUG // on release don't check that no other checker also evals.
- if (anyEvaluated) {
- break;
- }
-#endif
-
ExplodedNodeSet checkDst;
NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
- // Next, check if any of the EvalCall callbacks can evaluate the call.
+
+ // Check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
@@ -679,10 +649,6 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
-void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
- InlineCallCheckers.push_back(checkfn);
-}
-
void CheckerManager::_registerForEndOfTranslationUnit(
CheckEndOfTranslationUnit checkfn) {
EndOfTranslationUnitCheckers.push_back(checkfn);
diff --git a/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/lib/StaticAnalyzer/Core/ConstraintManager.cpp
new file mode 100644
index 000000000000..4dec52600518
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -0,0 +1,39 @@
+//== ConstraintManager.cpp - Constraints on symbolic values -----*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+using namespace clang;
+using namespace ento;
+
+ConstraintManager::~ConstraintManager() {}
+
+static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
+ SymbolRef Sym) {
+ const MemRegion *R = State->getStateManager().getRegionManager()
+ .getSymbolicRegion(Sym);
+ return loc::MemRegionVal(R);
+}
+
+ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
+ SymbolRef Sym) {
+ QualType Ty = Sym->getType();
+ DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
+ : nonloc::SymbolVal(Sym);
+ const ProgramStatePair &P = assumeDual(State, V);
+ if (P.first && !P.second)
+ return ConditionTruthVal(false);
+ if (!P.first && P.second)
+ return ConditionTruthVal(true);
+ return ConditionTruthVal();
+}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 1f137424d450..ec2379212dc6 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -243,11 +243,6 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
case ProgramPoint::CallEnterKind: {
CallEnter CEnter = cast<CallEnter>(Loc);
- if (AnalyzedCallees)
- if (const CallExpr* CE =
- dyn_cast_or_null<CallExpr>(CEnter.getCallExpr()))
- if (const Decl *CD = CE->getCalleeDecl())
- AnalyzedCallees->insert(CD);
SubEng.processCallEnter(CEnter, Pred);
break;
}
@@ -303,7 +298,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
&& "EXIT block cannot contain Stmts.");
// Process the final state transition.
- SubEng.processEndOfFunction(BuilderCtx);
+ SubEng.processEndOfFunction(BuilderCtx, Pred);
// This path is done. Don't enqueue any more nodes.
return;
@@ -313,7 +308,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
ExplodedNodeSet dstNodes;
BlockEntrance BE(Blk, Pred->getLocationContext());
NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
- SubEng.processCFGBlockEntrance(L, nodeBuilder);
+ SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
// Auto-generate a node.
if (!nodeBuilder.hasGeneratedNodes()) {
@@ -519,9 +514,9 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
return;
}
- const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>();
- const Stmt *St = CS ? CS->getStmt() : 0;
- PostStmt Loc(St, N->getLocationContext());
+ // At this point, we know we're processing a normal statement.
+ CFGStmt CS = cast<CFGStmt>((*Block)[Idx]);
+ PostStmt Loc(CS.getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
// Note: 'N' should be a fresh node because otherwise it shouldn't be
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 52644f7702fc..bab89c545c34 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -20,6 +20,44 @@
using namespace clang;
using namespace ento;
+static const Expr *ignoreTransparentExprs(const Expr *E) {
+ E = E->IgnoreParens();
+
+ switch (E->getStmtClass()) {
+ case Stmt::OpaqueValueExprClass:
+ E = cast<OpaqueValueExpr>(E)->getSourceExpr();
+ break;
+ case Stmt::ExprWithCleanupsClass:
+ E = cast<ExprWithCleanups>(E)->getSubExpr();
+ break;
+ case Stmt::CXXBindTemporaryExprClass:
+ E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
+ break;
+ case Stmt::SubstNonTypeTemplateParmExprClass:
+ E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
+ break;
+ case Stmt::CXXDefaultArgExprClass:
+ E = cast<CXXDefaultArgExpr>(E)->getExpr();
+ break;
+ default:
+ // This is the base case: we can't look through more than we already have.
+ return E;
+ }
+
+ return ignoreTransparentExprs(E);
+}
+
+static const Stmt *ignoreTransparentExprs(const Stmt *S) {
+ if (const Expr *E = dyn_cast<Expr>(S))
+ return ignoreTransparentExprs(E);
+ return S;
+}
+
+EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
+ : std::pair<const Stmt *,
+ const StackFrameContext *>(ignoreTransparentExprs(S),
+ L ? L->getCurrentStackFrame() : 0) {}
+
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
const SVal* X = ExprBindings.lookup(E);
if (X) {
@@ -30,101 +68,72 @@ SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
}
SVal Environment::getSVal(const EnvironmentEntry &Entry,
- SValBuilder& svalBuilder,
- bool useOnlyDirectBindings) const {
-
- if (useOnlyDirectBindings) {
- // This branch is rarely taken, but can be exercised by
- // checkers that explicitly bind values to arbitrary
- // expressions. It is crucial that we do not ignore any
- // expression here, and do a direct lookup.
- return lookupExpr(Entry);
+ SValBuilder& svalBuilder) const {
+ const Stmt *S = Entry.getStmt();
+ const LocationContext *LCtx = Entry.getLocationContext();
+
+ switch (S->getStmtClass()) {
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::ExprWithCleanupsClass:
+ case Stmt::GenericSelectionExprClass:
+ case Stmt::OpaqueValueExprClass:
+ case Stmt::ParenExprClass:
+ case Stmt::SubstNonTypeTemplateParmExprClass:
+ llvm_unreachable("Should have been handled by ignoreTransparentExprs");
+
+ case Stmt::AddrLabelExprClass:
+ return svalBuilder.makeLoc(cast<AddrLabelExpr>(S));
+
+ case Stmt::CharacterLiteralClass: {
+ const CharacterLiteral *C = cast<CharacterLiteral>(S);
+ return svalBuilder.makeIntVal(C->getValue(), C->getType());
}
- const Stmt *E = Entry.getStmt();
- const LocationContext *LCtx = Entry.getLocationContext();
-
- for (;;) {
- if (const Expr *Ex = dyn_cast<Expr>(E))
- E = Ex->IgnoreParens();
-
- switch (E->getStmtClass()) {
- case Stmt::AddrLabelExprClass:
- return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
- case Stmt::OpaqueValueExprClass: {
- const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E);
- E = ope->getSourceExpr();
- continue;
- }
- case Stmt::ParenExprClass:
- case Stmt::GenericSelectionExprClass:
- llvm_unreachable("ParenExprs and GenericSelectionExprs should "
- "have been handled by IgnoreParens()");
- case Stmt::CharacterLiteralClass: {
- const CharacterLiteral* C = cast<CharacterLiteral>(E);
- return svalBuilder.makeIntVal(C->getValue(), C->getType());
- }
- case Stmt::CXXBoolLiteralExprClass: {
- const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
- if (X)
- return *X;
- else
- return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(E));
- }
- case Stmt::CXXScalarValueInitExprClass:
- case Stmt::ImplicitValueInitExprClass: {
- QualType Ty = cast<Expr>(E)->getType();
- return svalBuilder.makeZeroVal(Ty);
- }
- case Stmt::IntegerLiteralClass: {
- // In C++, this expression may have been bound to a temporary object.
- SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
- if (X)
- return *X;
- else
- return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
- }
- case Stmt::ObjCBoolLiteralExprClass:
- return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
-
- // For special C0xx nullptr case, make a null pointer SVal.
- case Stmt::CXXNullPtrLiteralExprClass:
- return svalBuilder.makeNull();
- case Stmt::ExprWithCleanupsClass:
- E = cast<ExprWithCleanups>(E)->getSubExpr();
- continue;
- case Stmt::CXXBindTemporaryExprClass:
- E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
- continue;
- case Stmt::SubstNonTypeTemplateParmExprClass:
- E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
- continue;
- case Stmt::ObjCStringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E);
- return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
- }
- case Stmt::StringLiteralClass: {
- MemRegionManager &MRMgr = svalBuilder.getRegionManager();
- const StringLiteral *SL = cast<StringLiteral>(E);
- return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
- }
- case Stmt::ReturnStmtClass: {
- const ReturnStmt *RS = cast<ReturnStmt>(E);
- if (const Expr *RE = RS->getRetValue()) {
- E = RE;
- continue;
- }
- return UndefinedVal();
- }
-
- // Handle all other Stmt* using a lookup.
- default:
- break;
- };
+ case Stmt::CXXBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S));
+
+ case Stmt::CXXScalarValueInitExprClass:
+ case Stmt::ImplicitValueInitExprClass: {
+ QualType Ty = cast<Expr>(S)->getType();
+ return svalBuilder.makeZeroVal(Ty);
+ }
+
+ case Stmt::IntegerLiteralClass:
+ return svalBuilder.makeIntVal(cast<IntegerLiteral>(S));
+
+ case Stmt::ObjCBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S));
+
+ // For special C0xx nullptr case, make a null pointer SVal.
+ case Stmt::CXXNullPtrLiteralExprClass:
+ return svalBuilder.makeNull();
+
+ case Stmt::ObjCStringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S);
+ return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
+ }
+
+ case Stmt::StringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const StringLiteral *SL = cast<StringLiteral>(S);
+ return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
+ }
+
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *RS = cast<ReturnStmt>(S);
+ if (const Expr *RE = RS->getRetValue())
+ return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
+ return UndefinedVal();
+ }
+
+ // Handle all other Stmt* using a lookup.
+ default:
break;
}
- return lookupExpr(EnvironmentEntry(E, LCtx));
+
+ return lookupExpr(EnvironmentEntry(S, LCtx));
}
Environment EnvironmentManager::bindExpr(Environment Env,
@@ -140,16 +149,16 @@ Environment EnvironmentManager::bindExpr(Environment Env,
return Environment(F.add(Env.ExprBindings, E, V));
}
-static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) {
- const Stmt *S = E.getStmt();
- S = (const Stmt*) (((uintptr_t) S) | 0x1);
- return EnvironmentEntry(S, E.getLocationContext());
+EnvironmentEntry EnvironmentEntry::makeLocation() const {
+ EnvironmentEntry Result = *this;
+ reinterpret_cast<uintptr_t &>(Result.first) |= 0x1;
+ return Result;
}
Environment EnvironmentManager::bindExprAndLocation(Environment Env,
const EnvironmentEntry &E,
SVal location, SVal V) {
- return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location),
+ return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location),
E, V));
}
@@ -286,7 +295,8 @@ void Environment::printAux(raw_ostream &Out, bool printLocations,
S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
}
- Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") ";
+ Out << " (" << (const void*) En.getLocationContext() << ','
+ << (const void*) S << ") ";
LangOptions LO; // FIXME.
S->printPretty(Out, 0, PrintingPolicy(LO));
Out << " : " << I.getData();
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index b79f3f5d1eaa..c284bd7dfad4 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -47,10 +47,8 @@ void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
// Cleanup.
//===----------------------------------------------------------------------===//
-static const unsigned CounterTop = 1000;
-
ExplodedGraph::ExplodedGraph()
- : NumNodes(0), reclaimNodes(false), reclaimCounter(CounterTop) {}
+ : NumNodes(0), ReclaimNodeInterval(0) {}
ExplodedGraph::~ExplodedGraph() {}
@@ -63,12 +61,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
//
// (1) 1 predecessor (that has one successor)
// (2) 1 successor (that has one predecessor)
- // (3) The ProgramPoint is for a PostStmt.
+ // (3) The ProgramPoint is for a PostStmt, but not a PostStore.
// (4) There is no 'tag' for the ProgramPoint.
// (5) The 'store' is the same as the predecessor.
// (6) The 'GDM' is the same as the predecessor.
// (7) The LocationContext is the same as the predecessor.
- // (8) The PostStmt is for a non-consumed Stmt or Expr.
+ // (8) The PostStmt isn't for a non-consumed Stmt or Expr.
// (9) The successor is not a CallExpr StmtPoint (so that we would be able to
// find it when retrying a call with no inlining).
// FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
@@ -87,16 +85,13 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Condition 3.
ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint))
+ if (!isa<PostStmt>(progPoint) || isa<PostStore>(progPoint))
return false;
// Condition 4.
PostStmt ps = cast<PostStmt>(progPoint);
if (ps.getTag())
return false;
-
- if (isa<BinaryOperator>(ps.getStmt()))
- return false;
// Conditions 5, 6, and 7.
ProgramStateRef state = node->getState();
@@ -106,6 +101,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
return false;
// Condition 8.
+ // Do not collect nodes for non-consumed Stmt or Expr to ensure precise
+ // diagnostic generation; specifically, so that we could anchor arrows
+ // pointing to the beginning of statements (as written in code).
+ if (!isa<Expr>(ps.getStmt()))
+ return false;
+
if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) {
ParentMap &PM = progPoint.getLocationContext()->getParentMap();
if (!PM.isConsumedExpr(Ex))
@@ -115,7 +116,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Condition 9.
const ProgramPoint SuccLoc = succ->getLocation();
if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc))
- if (CallEvent::mayBeInlined(SP->getStmt()))
+ if (CallEvent::isCallStmt(SP->getStmt()))
return false;
return true;
@@ -141,13 +142,13 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
if (ChangedNodes.empty())
return;
- // Only periodically relcaim nodes so that we can build up a set of
+ // Only periodically reclaim nodes so that we can build up a set of
// nodes that meet the reclamation criteria. Freshly created nodes
// by definition have no successor, and thus cannot be reclaimed (see below).
- assert(reclaimCounter > 0);
- if (--reclaimCounter != 0)
+ assert(ReclaimCounter > 0);
+ if (--ReclaimCounter != 0)
return;
- reclaimCounter = CounterTop;
+ ReclaimCounter = ReclaimNodeInterval;
for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end();
it != et; ++it) {
@@ -162,9 +163,18 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
// ExplodedNode.
//===----------------------------------------------------------------------===//
-static inline BumpVector<ExplodedNode*>& getVector(void *P) {
- return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
-}
+// An NodeGroup's storage type is actually very much like a TinyPtrVector:
+// it can be either a pointer to a single ExplodedNode, or a pointer to a
+// BumpVector allocated with the ExplodedGraph's allocator. This allows the
+// common case of single-node NodeGroups to be implemented with no extra memory.
+//
+// Consequently, each of the NodeGroup methods have up to four cases to handle:
+// 1. The flag is set and this group does not actually contain any nodes.
+// 2. The group is empty, in which case the storage value is null.
+// 3. The group contains a single node.
+// 4. The group contains more than one node.
+typedef BumpVector<ExplodedNode *> ExplodedNodeVector;
+typedef llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *> GroupStorage;
void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
assert (!V->isSink());
@@ -176,71 +186,77 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
}
void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
- assert(getKind() == Size1);
- P = reinterpret_cast<uintptr_t>(node);
- assert(getKind() == Size1);
+ assert(!getFlag());
+
+ GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
+ assert(Storage.is<ExplodedNode *>());
+ Storage = node;
+ assert(Storage.is<ExplodedNode *>());
}
void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
- assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
assert(!getFlag());
- if (getKind() == Size1) {
- if (ExplodedNode *NOld = getNode()) {
- BumpVectorContext &Ctx = G.getNodeAllocator();
- BumpVector<ExplodedNode*> *V =
- G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
- new (V) BumpVector<ExplodedNode*>(Ctx, 4);
-
- assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
- V->push_back(NOld, Ctx);
- V->push_back(N, Ctx);
- P = reinterpret_cast<uintptr_t>(V) | SizeOther;
- assert(getPtr() == (void*) V);
- assert(getKind() == SizeOther);
- }
- else {
- P = reinterpret_cast<uintptr_t>(N);
- assert(getKind() == Size1);
- }
+ GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
+ if (Storage.isNull()) {
+ Storage = N;
+ assert(Storage.is<ExplodedNode *>());
+ return;
}
- else {
- assert(getKind() == SizeOther);
- getVector(getPtr()).push_back(N, G.getNodeAllocator());
+
+ ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>();
+
+ if (!V) {
+ // Switch from single-node to multi-node representation.
+ ExplodedNode *Old = Storage.get<ExplodedNode *>();
+
+ BumpVectorContext &Ctx = G.getNodeAllocator();
+ V = G.getAllocator().Allocate<ExplodedNodeVector>();
+ new (V) ExplodedNodeVector(Ctx, 4);
+ V->push_back(Old, Ctx);
+
+ Storage = V;
+ assert(!getFlag());
+ assert(Storage.is<ExplodedNodeVector *>());
}
+
+ V->push_back(N, G.getNodeAllocator());
}
unsigned ExplodedNode::NodeGroup::size() const {
if (getFlag())
return 0;
- if (getKind() == Size1)
- return getNode() ? 1 : 0;
- else
- return getVector(getPtr()).size();
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->size();
+ return 1;
}
-ExplodedNode **ExplodedNode::NodeGroup::begin() const {
+ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
if (getFlag())
- return NULL;
+ return 0;
- if (getKind() == Size1)
- return (ExplodedNode**) (getPtr() ? &P : NULL);
- else
- return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin()));
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->begin();
+ return Storage.getAddrOfPtr1();
}
-ExplodedNode** ExplodedNode::NodeGroup::end() const {
+ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
if (getFlag())
- return NULL;
-
- if (getKind() == Size1)
- return (ExplodedNode**) (getPtr() ? &P+1 : NULL);
- else {
- // Dereferencing end() is undefined behaviour. The vector is not empty, so
- // we can dereference the last elem and then add 1 to the result.
- return const_cast<ExplodedNode**>(getVector(getPtr()).end());
- }
+ return 0;
+
+ const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
+ if (Storage.isNull())
+ return 0;
+ if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
+ return V->end();
+ return Storage.getAddrOfPtr1() + 1;
}
ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
@@ -266,7 +282,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
new (V) NodeTy(L, State, IsSink);
- if (reclaimNodes)
+ if (ReclaimNodeInterval)
ChangedNodes.push_back(V);
// Insert the node into the node set and return it.
@@ -314,8 +330,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// ===- Pass 1 (reverse DFS) -===
for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
- assert(*I);
- WL1.push_back(*I);
+ if (*I)
+ WL1.push_back(*I);
}
// Process the first worklist until it is empty. Because it is a std::list
@@ -338,7 +354,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
}
// Visit our predecessors and enqueue them.
- for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
+ for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
+ I != E; ++I)
WL1.push_back(*I);
}
@@ -375,7 +392,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// Walk through the predecessors of 'N' and hook up their corresponding
// nodes in the new graph (if any) to the freshly created node.
- for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
+ for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
+ I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI == Pass2.end())
continue;
@@ -387,7 +405,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// been created, we should hook them up as successors. Otherwise, enqueue
// the new nodes from the original graph that should have nodes created
// in the new graph.
- for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
+ for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
+ I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
PI->second->addPredecessor(NewN, *G);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index b0435fb562e3..045591c9074b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -55,32 +55,32 @@ STATISTIC(NumTimesRetriedWithoutInlining,
//===----------------------------------------------------------------------===//
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCallees,
+ SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
- Engine(*this, VisitedCallees, FS),
+ Engine(*this, FS),
G(Engine.getGraph()),
StateMgr(getContext(), mgr.getStoreManagerCreator(),
mgr.getConstraintManagerCreator(), G.getAllocator(),
- *this),
+ this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
EntryNode(NULL),
- currentStmt(NULL), currentStmtIdx(0), currentBuilderContext(0),
- NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
- RaiseSel(GetNullarySelector("raise", getContext())),
- ObjCGCEnabled(gcEnabled), BR(mgr, *this) {
-
- if (mgr.shouldEagerlyTrimExplodedGraph()) {
- // Enable eager node reclaimation when constructing the ExplodedGraph.
- G.enableNodeReclamation();
+ currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
+ ObjCNoRet(mgr.getASTContext()),
+ ObjCGCEnabled(gcEnabled), BR(mgr, *this),
+ VisitedCallees(VisitedCalleesIn)
+{
+ unsigned TrimInterval = mgr.options.getGraphTrimInterval();
+ if (TrimInterval != 0) {
+ // Enable eager node reclaimation when constructing the ExplodedGraph.
+ G.enableNodeReclamation(TrimInterval);
}
}
ExprEngine::~ExprEngine() {
BR.FlushReports();
- delete [] NSExceptionInstanceRaiseSelectors;
}
//===----------------------------------------------------------------------===//
@@ -164,6 +164,23 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
+/// If the value of the given expression is a NonLoc, copy it into a new
+/// temporary region, and replace the value of the expression with that.
+static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
+ const LocationContext *LC,
+ const Expr *E) {
+ SVal V = State->getSVal(E, LC);
+
+ if (isa<NonLoc>(V)) {
+ MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
+ const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC);
+ State = State->bindLoc(loc::MemRegionVal(R), V);
+ State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+ }
+
+ return State;
+}
+
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
@@ -200,8 +217,8 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) {
- currentStmtIdx = StmtIdx;
- currentBuilderContext = Ctx;
+ currStmtIdx = StmtIdx;
+ currBldrCtx = Ctx;
switch (E.getKind()) {
case CFGElement::Invalid:
@@ -219,7 +236,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
- currentBuilderContext = 0;
+ currBldrCtx = 0;
}
static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
@@ -228,7 +245,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
const LocationContext *LC) {
// Are we never purging state values?
- if (AMgr.getPurgeMode() == PurgeNone)
+ if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
return false;
// Is this the beginning of a basic block?
@@ -240,7 +257,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
return true;
// Run before processing a call.
- if (CallEvent::mayBeInlined(S.getStmt()))
+ if (CallEvent::isCallStmt(S.getStmt()))
return true;
// Is this an expression that is consumed by another expression? If so,
@@ -251,12 +268,12 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *ReferenceStmt,
- const LocationContext *LC,
+ const StackFrameContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
- ReferenceStmt == 0) && "PreStmt is not generally supported by "
- "the SymbolReaper yet");
+ ReferenceStmt == 0)
+ && "PostStmt is not generally supported by the SymbolReaper yet");
NumRemoveDeadBindings++;
CleanedState = Pred->getState();
SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
@@ -276,8 +293,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// Generate a CleanedNode that has the environment and store cleaned
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
- StmtNodeBuilder Bldr(Pred, Out, *currentBuilderContext);
- Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, false, &cleanupTag,K);
+ StmtNodeBuilder Bldr(Pred, Out, *currBldrCtx);
+ Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, &cleanupTag, K);
} else {
// Call checkers with the non-cleaned state so that they could query the
@@ -289,7 +306,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// For each node in CheckedSet, generate CleanedNodes that have the
// environment, the store, and the constraints cleaned up but have the
// user-supplied states as the predecessors.
- StmtNodeBuilder Bldr(CheckedSet, Out, *currentBuilderContext);
+ StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx);
for (ExplodedNodeSet::const_iterator
I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) {
ProgramStateRef CheckerState = (*I)->getState();
@@ -309,8 +326,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// generate a transition to that state.
ProgramStateRef CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
- Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, false,
- &cleanupTag, K);
+ Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, &cleanupTag, K);
}
}
}
@@ -320,17 +336,17 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- currentStmt = S.getStmt();
+ currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- currentStmt->getLocStart(),
+ currStmt->getLocStart(),
"Error evaluating statement");
// Remove dead bindings and symbols.
EntryNode = Pred;
ExplodedNodeSet CleanedStates;
if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
- removeDead(EntryNode, CleanedStates, currentStmt,
- Pred->getLocationContext(), currentStmt);
+ removeDead(EntryNode, CleanedStates, currStmt,
+ Pred->getStackFrame(), currStmt);
} else
CleanedStates.Add(EntryNode);
@@ -340,44 +356,45 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
E = CleanedStates.end(); I != E; ++I) {
ExplodedNodeSet DstI;
// Visit the statement.
- Visit(currentStmt, *I, DstI);
+ Visit(currStmt, *I, DstI);
Dst.insert(DstI);
}
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
// NULL out these variables to cleanup.
CleanedState = NULL;
EntryNode = NULL;
- currentStmt = 0;
+ currStmt = 0;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ExplodedNode *Pred) {
- ExplodedNodeSet Dst;
- NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
-
- ProgramStateRef State = Pred->getState();
-
const CXXCtorInitializer *BMI = Init.getInitializer();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
BMI->getSourceLocation(),
"Error evaluating initializer");
- // We don't set EntryNode and currentStmt. And we don't clean up state.
+ // We don't set EntryNode and currStmt. And we don't clean up state.
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
cast<CXXConstructorDecl>(stackFrame->getDecl());
+
+ ProgramStateRef State = Pred->getState();
SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
+ PostInitializer PP(BMI, stackFrame);
+ ExplodedNodeSet Tmp(Pred);
+
// Evaluate the initializer, if necessary
if (BMI->isAnyMemberInitializer()) {
// Constructors build the object directly in the field,
// but non-objects must be copied in from the initializer.
- if (!isa<CXXConstructExpr>(BMI->getInit())) {
+ const Expr *Init = BMI->getInit();
+ if (!isa<CXXConstructExpr>(Init)) {
SVal FieldLoc;
if (BMI->isIndirectMemberInitializer())
FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
@@ -385,22 +402,26 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
FieldLoc = State->getLValue(BMI->getMember(), thisVal);
SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
- State = State->bindLoc(FieldLoc, InitVal);
+
+ Tmp.clear();
+ evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
}
} else {
assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
// We already did all the work when visiting the CXXConstructExpr.
}
- // Construct a PostInitializer node whether the state changed or not,
+ // Construct PostInitializer nodes whether the state changed or not,
// so that the diagnostics don't get confused.
- PostInitializer PP(BMI, stackFrame);
- // Builder automatically add the generated node to the deferred set,
- // which are processed in the builder's dtor.
- Bldr.generateNode(PP, State, Pred);
+ ExplodedNodeSet Dst;
+ NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ ExplodedNode *N = *I;
+ Bldr.generateNode(PP, N->getState(), N);
+ }
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
@@ -424,7 +445,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
}
// Enqueue the new nodes onto the work list.
- Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
@@ -441,7 +462,7 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
- Dtor.getTriggerStmt(), Pred, Dst);
+ Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
@@ -459,7 +480,7 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
- CurDtor->getBody(), Pred, Dst);
+ CurDtor->getBody(), /*IsBase=*/true, Pred, Dst);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
@@ -475,7 +496,7 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
VisitCXXDestructor(Member->getType(),
cast<loc::MemRegionVal>(FieldVal).getRegion(),
- CurDtor->getBody(), Pred, Dst);
+ CurDtor->getBody(), /*IsBase=*/false, Pred, Dst);
}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
@@ -488,7 +509,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
S->getLocStart(),
"Error evaluating statement");
ExplodedNodeSet Dst;
- StmtNodeBuilder Bldr(Pred, DstTop, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
// Expressions to ignore.
if (const Expr *Ex = dyn_cast<Expr>(S))
@@ -498,7 +519,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
+ if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
switch (S->getStmtClass()) {
@@ -521,21 +542,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ case Stmt::FunctionParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
- const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState(),
- /* sink */ true);
- Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
+ const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currBldrCtx->getBlock());
break;
}
- // We don't handle default arguments either yet, but we can fake it
- // for now by just skipping them.
- case Stmt::CXXDefaultArgExprClass:
- break;
-
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
case Stmt::GenericSelectionExprClass:
@@ -607,11 +623,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::AtomicExprClass:
// Fall through.
- // Currently all handling of 'throw' just falls to the CFG. We
- // can consider doing more if necessary.
- case Stmt::CXXThrowExprClass:
- // Fall through.
-
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
case Stmt::AddrLabelExprClass:
@@ -626,6 +637,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXDefaultArgExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::CXXNullPtrLiteralExprClass: {
Bldr.takeNodes(Pred);
@@ -647,7 +659,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
const Expr *Ex = cast<Expr>(S);
QualType resultType = Ex->getType();
@@ -656,9 +668,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
it != et; ++it) {
ExplodedNode *N = *it;
const LocationContext *LCtx = N->getLocationContext();
- SVal result =
- svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType,
- currentBuilderContext->getCurrentBlockCount());
+ SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType,
+ currBldrCtx->blockCount());
ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
Bldr2.generateNode(S, N, state);
}
@@ -674,9 +685,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
- case Stmt::AsmStmtClass:
+ case Stmt::GCCAsmStmtClass:
Bldr.takeNodes(Pred);
- VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
@@ -711,11 +722,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.takeNodes(Pred);
- if (AMgr.shouldEagerlyAssume() &&
+ if (AMgr.options.eagerlyAssumeBinOpBifurcation &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
+ evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
@@ -724,8 +735,26 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
+ case Stmt::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *OCE = cast<CXXOperatorCallExpr>(S);
+
+ // For instance method operators, make sure the 'this' argument has a
+ // valid region.
+ const Decl *Callee = OCE->getCalleeDecl();
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
+ if (MD->isInstance()) {
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef NewState =
+ createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
+ if (NewState != State)
+ Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0,
+ ProgramPoint::PreStmtKind);
+ }
+ }
+ // FALLTHROUGH
+ }
case Stmt::CallExprClass:
- case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass:
case Stmt::UserDefinedLiteralClass: {
Bldr.takeNodes(Pred);
@@ -846,12 +875,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Expr::MaterializeTemporaryExprClass: {
Bldr.takeNodes(Pred);
- const MaterializeTemporaryExpr *Materialize
- = cast<MaterializeTemporaryExpr>(S);
- if (Materialize->getType()->isRecordType())
- Dst.Add(Pred);
- else
- CreateCXXTemporaryObject(Materialize, Pred, Dst);
+ const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
+ CreateCXXTemporaryObject(MTE, Pred, Dst);
Bldr.addNodes(Dst);
break;
}
@@ -886,12 +911,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
- case Stmt::ObjCAtThrowStmtClass: {
+ case Stmt::ObjCAtThrowStmtClass:
+ case Stmt::CXXThrowExprClass:
// FIXME: This is not complete. We basically treat @throw as
// an abort.
- Bldr.generateNode(S, Pred, Pred->getState());
+ Bldr.generateSink(S, Pred, Pred->getState());
break;
- }
case Stmt::ReturnStmtClass:
Bldr.takeNodes(Pred);
@@ -935,10 +960,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::UnaryOperatorClass: {
Bldr.takeNodes(Pred);
const UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) {
+ if (AMgr.options.eagerlyAssumeBinOpBifurcation && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, U);
+ evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
@@ -1030,19 +1055,18 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
/// Block entrance. (Update counters).
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
- NodeBuilderWithSinks &nodeBuilder) {
+ NodeBuilderWithSinks &nodeBuilder,
+ ExplodedNode *Pred) {
// FIXME: Refactor this into a checker.
- ExplodedNode *pred = nodeBuilder.getContext().getPred();
-
- if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) {
+ if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
const ExplodedNode *Sink =
- nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
+ nodeBuilder.generateSink(Pred->getState(), Pred, &tag);
// Check if we stopped at the top level function or not.
// Root node should have the location context of the top most function.
- const LocationContext *CalleeLC = pred->getLocation().getLocationContext();
+ const LocationContext *CalleeLC = Pred->getLocation().getLocationContext();
const LocationContext *CalleeSF = CalleeLC->getCurrentStackFrame();
const LocationContext *RootLC =
(*G.roots_begin())->getLocation().getLocationContext();
@@ -1053,7 +1077,8 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
// no-inlining policy in the state and enqueuing the new work item on
// the list. Replay should almost never fail. Use the stats to catch it
// if it does.
- if ((!AMgr.NoRetryExhausted && replayWithoutInlining(pred, CalleeLC)))
+ if ((!AMgr.options.NoRetryExhausted &&
+ replayWithoutInlining(Pred, CalleeLC)))
return;
NumMaxBlockCountReachedInInlined++;
} else
@@ -1155,7 +1180,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
ExplodedNodeSet &Dst,
const CFGBlock *DstT,
const CFGBlock *DstF) {
- currentBuilderContext = &BldCtx;
+ currBldrCtx = &BldCtx;
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
@@ -1238,7 +1263,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
builder.markInfeasible(false);
}
}
- currentBuilderContext = 0;
+ currBldrCtx = 0;
}
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
@@ -1287,10 +1312,25 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
-void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
- StateMgr.EndPath(BC.Pred->getState());
+void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred) {
+ StateMgr.EndPath(Pred->getState());
+
ExplodedNodeSet Dst;
- getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
+ if (Pred->getLocationContext()->inTopFrame()) {
+ // Remove dead symbols.
+ ExplodedNodeSet AfterRemovedDead;
+ removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead);
+
+ // Notify checkers.
+ for (ExplodedNodeSet::iterator I = AfterRemovedDead.begin(),
+ E = AfterRemovedDead.end(); I != E; ++I) {
+ getCheckerManager().runCheckersForEndPath(BC, Dst, *I, *this);
+ }
+ } else {
+ getCheckerManager().runCheckersForEndPath(BC, Dst, Pred, *this);
+ }
+
Engine.enqueueEndOfFunction(Dst);
}
@@ -1404,7 +1444,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -1422,7 +1462,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = UnknownVal();
}
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
@@ -1434,19 +1474,23 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
}
if (isa<FieldDecl>(D)) {
- // FIXME: Compute lvalue of fields.
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()),
- false, 0, ProgramPoint::PostLValueKind);
+ // FIXME: Compute lvalue of field pointers-to-member.
+ // Right now we just use a non-null void pointer, so that it gives proper
+ // results in boolean contexts.
+ SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
+ currBldrCtx->blockCount());
+ state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
+ ProgramPoint::PostLValueKind);
return;
}
- assert (false &&
- "ValueDecl support for this ValueDecl not implemented.");
+ llvm_unreachable("Support for this Decl not implemented.");
}
/// VisitArraySubscriptExpr - Transfer function for array accesses
@@ -1461,7 +1505,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
- StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
@@ -1471,8 +1515,8 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
state->getSVal(Idx, LCtx),
state->getSVal(Base, LCtx));
assert(A->isGLValue());
- Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V),
- false, 0, ProgramPoint::PostLValueKind);
+ Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0,
+ ProgramPoint::PostLValueKind);
}
}
@@ -1480,52 +1524,40 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet &TopDst) {
- StmtNodeBuilder Bldr(Pred, TopDst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx);
ExplodedNodeSet Dst;
- Decl *member = M->getMemberDecl();
+ ValueDecl *Member = M->getMemberDecl();
- if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
- assert(M->isGLValue());
+ // Handle static member variables and enum constants accessed via
+ // member syntax.
+ if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
Bldr.takeNodes(Pred);
- VisitCommonDeclRefExpr(M, VD, Pred, Dst);
+ VisitCommonDeclRefExpr(M, Member, Pred, Dst);
Bldr.addNodes(Dst);
return;
}
- // Handle C++ method calls.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(member)) {
- Bldr.takeNodes(Pred);
- SVal MDVal = svalBuilder.getFunctionPointer(MD);
- ProgramStateRef state =
- Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal);
- Bldr.generateNode(M, Pred, state);
- return;
- }
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ Expr *BaseExpr = M->getBase();
+ // Handle C++ method calls.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
+ if (MD->isInstance())
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
- FieldDecl *field = dyn_cast<FieldDecl>(member);
- if (!field) // FIXME: skipping member expressions for non-fields
- return;
+ SVal MDVal = svalBuilder.getFunctionPointer(MD);
+ state = state->BindExpr(M, LCtx, MDVal);
- Expr *baseExpr = M->getBase()->IgnoreParens();
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
- if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
- isa<nonloc::CompoundVal>(baseExprVal) ||
- // FIXME: This can originate by conjuring a symbol for an unknown
- // temporary struct object, see test/Analysis/fields.c:
- // (p = getit()).x
- isa<nonloc::SymbolVal>(baseExprVal)) {
- Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
+ Bldr.generateNode(M, Pred, state);
return;
}
- // FIXME: Should we insert some assumption logic in here to determine
- // if "Base" is a valid piece of memory? Before we put this assumption
- // later when using FieldOffset lvals (which we no longer have).
+ // Handle regular struct fields / member variables.
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+ SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
- // For all other cases, compute an lvalue.
+ FieldDecl *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
if (M->isGLValue()) {
if (field->getType()->isReferenceType()) {
@@ -1535,7 +1567,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
L = UnknownVal();
}
- Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0,
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0,
ProgramPoint::PostLValueKind);
} else {
Bldr.takeNodes(Pred);
@@ -1548,40 +1580,48 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit) {
+ SVal location, SVal Val,
+ bool atDeclInit, const ProgramPoint *PP) {
+
+ const LocationContext *LC = Pred->getLocationContext();
+ PostStmt PS(StoreE, LC);
+ if (!PP)
+ PP = &PS;
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
- StoreE, *this,
- ProgramPoint::PostStmtKind);
+ StoreE, *this, *PP);
+ // If the location is not a 'Loc', it will already be handled by
+ // the checkers. There is nothing left to do.
+ if (!isa<Loc>(location)) {
+ Dst = CheckedSet;
+ return;
+ }
+
ExplodedNodeSet TmpDst;
- StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx);
- const LocationContext *LC = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
-
- if (atDeclInit) {
- const VarRegion *VR =
- cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
-
- state = state->bindDecl(VR, Val);
- } else {
- state = state->bindLoc(location, Val);
- }
-
+
+ // When binding the value, pass on the hint that this is a initialization.
+ // For initializations, we do not need to inform clients of region
+ // changes.
+ state = state->bindLoc(cast<Loc>(location),
+ Val, /* notifyChanges = */ !atDeclInit);
+
const MemRegion *LocReg = 0;
- if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location))
+ if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) {
LocReg = LocRegVal->getRegion();
-
+ }
+
const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
- Bldr.generateNode(L, PredI, state, false);
+ Bldr.generateNode(L, state, PredI);
}
-
Dst.insert(TmpDst);
}
@@ -1671,7 +1711,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
if (Tmp.empty())
return;
- StmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
if (location.isUndef())
return;
@@ -1684,8 +1724,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
// This is important. We must nuke the old binding.
Bldr.generateNode(NodeEx, *NI,
state->BindExpr(BoundEx, LCtx, UnknownVal()),
- false, tag,
- ProgramPoint::PostLoadKind);
+ tag, ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
@@ -1693,7 +1732,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
Bldr.generateNode(NodeEx, *NI,
state->bindExprAndLocation(BoundEx, LCtx, location, V),
- false, tag, ProgramPoint::PostLoadKind);
+ tag, ProgramPoint::PostLoadKind);
}
}
}
@@ -1706,7 +1745,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
SVal location,
const ProgramPointTag *tag,
bool isLoad) {
- StmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
// Early checks for performance reason.
if (location.isUnknown()) {
return;
@@ -1714,7 +1753,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
ExplodedNodeSet Src;
BldrTop.takeNodes(Pred);
- StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx);
if (Pred->getState() != state) {
// Associate this new state with an ExplodedNode.
// FIXME: If I pass null tag, the graph is incorrect, e.g for
@@ -1725,9 +1764,8 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
// instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value"
- // FIXME: why is 'tag' not used instead of etag?
- static SimpleProgramPointTag etag("ExprEngine: Location");
- Bldr.generateNode(NodeEx, Pred, state, false, &etag);
+ static SimpleProgramPointTag tag("ExprEngine: Location");
+ Bldr.generateNode(NodeEx, Pred, state, &tag);
}
ExplodedNodeSet Tmp;
getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
@@ -1736,16 +1774,18 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
}
std::pair<const ProgramPointTag *, const ProgramPointTag*>
-ExprEngine::getEagerlyAssumeTags() {
+ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
- EagerlyAssumeTrue("ExprEngine : Eagerly Assume True"),
- EagerlyAssumeFalse("ExprEngine : Eagerly Assume False");
- return std::make_pair(&EagerlyAssumeTrue, &EagerlyAssumeFalse);
+ eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"),
+ eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False");
+ return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
+ &eagerlyAssumeBinOpBifurcationFalse);
}
-void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
- const Expr *Ex) {
- StmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext);
+void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ const Expr *Ex) {
+ StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
@@ -1762,28 +1802,28 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
- getEagerlyAssumeTags();
+ geteagerlyAssumeBinOpBifurcationTags();
// First assume that the condition is true.
if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
- Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first);
+ Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
}
// Next, assume that the condition is false.
if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
- Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second);
+ Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
}
}
}
}
-void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
// We have processed both the inputs and the outputs. All of the outputs
// should evaluate to Locs. Nuke all of their values.
@@ -1793,7 +1833,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
- for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
+ for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
SVal X = state->getSVal(*OI, Pred->getLocationContext());
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
@@ -1807,7 +1847,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(A, Pred, Pred->getState());
}
@@ -1932,7 +1972,7 @@ struct DOTGraphTraits<ExplodedNode*> :
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt *S = L->getStmt();
- Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
+ Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
LangOptions LO; // FIXME.
S->printPretty(Out, 0, PrintingPolicy(LO));
printLocation(Out, S->getLocStart());
@@ -2038,8 +2078,8 @@ struct DOTGraphTraits<ExplodedNode*> :
}
ProgramStateRef state = N->getState();
- Out << "\\|StateID: " << (void*) state.getPtr()
- << " NodeID: " << (void*) N << "\\|";
+ Out << "\\|StateID: " << (const void*) state.getPtr()
+ << " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out);
Out << "\\l";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 46cba81b14f7..00b2f4a6bee9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -45,8 +45,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
if (RightV.isUnknown()) {
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx, Count);
+ unsigned Count = currBldrCtx->blockCount();
+ RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
@@ -57,7 +57,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
}
if (!B->isAssignmentOp()) {
- StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext);
+ StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
if (B->isAdditiveOp()) {
// If one of the operands is a location, conjure a symbol for the other
@@ -65,16 +65,16 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// results in an ElementRegion.
// TODO: This can be removed after we enable history tracking with
// SymSymExpr.
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ unsigned Count = currBldrCtx->blockCount();
if (isa<Loc>(LeftV) &&
RHS->getType()->isIntegerType() && RightV.isUnknown()) {
- RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx,
- RHS->getType(), Count);
+ RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(),
+ Count);
}
if (isa<Loc>(RightV) &&
LHS->getType()->isIntegerType() && LeftV.isUnknown()) {
- LeftV = svalBuilder.getConjuredSymbolVal(LHS, LCtx,
- LHS->getType(), Count);
+ LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(),
+ Count);
}
}
@@ -145,15 +145,11 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
SVal LHSVal;
if (Result.isUnknown()) {
-
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
-
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
- LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx,
- LTy, Count);
-
+ LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy,
+ currBldrCtx->blockCount());
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
}
@@ -208,11 +204,10 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
}
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
Bldr.generateNode(BE, Pred,
State->BindExpr(BE, Pred->getLocationContext(), V),
- false, 0,
- ProgramPoint::PostLValueKind);
+ 0, ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
@@ -242,12 +237,14 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
- StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) {
Pred = *I;
-
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+
switch (CastE->getCastKind()) {
case CK_LValueToRValue:
llvm_unreachable("LValueToRValue casts handled earlier.");
@@ -267,7 +264,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
- case CK_FunctionToPointerDecay: {
+ case CK_ConstructorConversion:
+ case CK_UserDefinedConversion:
+ case CK_FunctionToPointerDecay:
+ case CK_BuiltinFnToFnPtr: {
// Copy the SVal of Ex to CastE.
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -276,6 +276,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_MemberPointerToBoolean:
+ // FIXME: For now, member pointers are represented by void *.
+ // FALLTHROUGH
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
@@ -304,8 +307,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast: {
// Delegate to SValBuilder to process.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
@@ -315,8 +316,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
val = getStoreManager().evalDerivedToBase(val, CastE);
state = state->BindExpr(CastE, LCtx, val);
@@ -325,8 +324,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
}
// Handle C++ dyn_cast.
case CK_Dynamic: {
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
SVal val = state->getSVal(Ex, LCtx);
// Compute the type of the result.
@@ -347,7 +344,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (T->isReferenceType()) {
// A bad_cast exception is thrown if input value is a reference.
// Currently, we model this, by generating a sink.
- Bldr.generateNode(CastE, Pred, state, true);
+ Bldr.generateSink(CastE, Pred, state);
continue;
} else {
// If the cast fails on a pointer, bind to 0.
@@ -356,9 +353,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
} else {
// If we don't know if the cast succeeded, conjure a new symbol.
if (val.isUnknown()) {
- DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL,
- CastE, LCtx, resultType,
- currentBuilderContext->getCurrentBlockCount());
+ DefinedOrUnknownSVal NewSym =
+ svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType,
+ currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, NewSym);
} else
// Else, bind to the derived region value.
@@ -367,27 +364,29 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_NullToMemberPointer: {
+ // FIXME: For now, member pointers are represented by void *.
+ SVal V = svalBuilder.makeIntValWithPtrWidth(0, true);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
// Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_BaseToDerived:
- case CK_NullToMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_ReinterpretMemberPointer:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
case CK_VectorSplat:
- case CK_MemberPointerToBoolean:
case CK_LValueBitCast: {
// Recover some path-sensitivty by conjuring a new value.
QualType resultType = CastE->getType();
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, LCtx,
- resultType, currentBuilderContext->getCurrentBlockCount());
- ProgramStateRef state = Pred->getState()->BindExpr(CastE, LCtx,
- result);
+ SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx,
+ resultType,
+ currBldrCtx->blockCount());
+ state = state->BindExpr(CastE, LCtx, result);
Bldr.generateNode(CastE, Pred, state);
continue;
}
@@ -398,7 +397,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
const InitListExpr *ILE
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
@@ -442,7 +441,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
- StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
@@ -478,8 +477,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Ty = getContext().getPointerType(Ty);
}
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
- currentBuilderContext->getCurrentBlockCount());
+ InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
+ currBldrCtx->blockCount());
}
B.takeNodes(N);
ExplodedNodeSet Dst2;
@@ -488,7 +487,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
}
}
else {
- B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
+ B.generateNode(DS, N, state);
}
}
}
@@ -498,7 +497,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
assert(B->getOpcode() == BO_LAnd ||
B->getOpcode() == BO_LOr);
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
ExplodedNode *N = Pred;
@@ -531,10 +530,28 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
else {
// If there is no terminator, by construction the last statement
// in SrcBlock is the value of the enclosing expression.
+ // However, we still need to constrain that value to be 0 or 1.
assert(!SrcBlock->empty());
CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin());
- const Stmt *S = Elem.getStmt();
- X = N->getState()->getSVal(S, Pred->getLocationContext());
+ const Expr *RHS = cast<Expr>(Elem.getStmt());
+ SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext());
+
+ DefinedOrUnknownSVal DefinedRHS = cast<DefinedOrUnknownSVal>(RHSVal);
+ ProgramStateRef StTrue, StFalse;
+ llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
+ if (StTrue) {
+ if (StFalse) {
+ // We can't constrain the value to 0 or 1; the best we can do is a cast.
+ X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType());
+ } else {
+ // The value is known to be true.
+ X = getSValBuilder().makeIntVal(1, B->getType());
+ }
+ } else {
+ // The value is known to be false.
+ assert(StFalse && "Infeasible path!");
+ X = getSValBuilder().makeIntVal(0, B->getType());
+ }
}
Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X));
@@ -543,14 +560,15 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
QualType T = getContext().getCanonicalType(IE->getType());
unsigned NumInitElements = IE->getNumInits();
- if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
+ T->isAnyComplexType()) {
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -590,7 +608,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
const Expr *R,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
const CFGBlock *SrcBlock = 0;
@@ -631,7 +649,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
APSInt IV;
if (OOE->EvaluateAsInt(IV, getContext())) {
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
@@ -650,7 +668,7 @@ void ExprEngine::
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
QualType T = Ex->getTypeOfArgument();
@@ -683,7 +701,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
switch (U->getOpcode()) {
default: {
Bldr.takeNodes(Pred);
@@ -816,7 +834,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
evalLoad(Tmp, U, Ex, Pred, state, loc);
ExplodedNodeSet Dst2;
- StmtNodeBuilder Bldr(Tmp, Dst2, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
state = (*I)->getState();
@@ -840,16 +858,17 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
if (U->getType()->isAnyPointerType())
RHS = svalBuilder.makeArrayIndex(1);
- else
+ else if (U->getType()->isIntegralOrEnumerationType())
RHS = svalBuilder.makeIntVal(1, U->getType());
+ else
+ RHS = UnknownVal();
SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.getConjuredSymbolVal(NULL, Ex, LCtx,
- currentBuilderContext->getCurrentBlockCount());
+ svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 44a860f689da..b3baa7905782 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -25,20 +25,28 @@ using namespace ento;
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
- SVal V = state->getSVal(tempExpr, Pred->getLocationContext());
-
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+ 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.
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR || !isa<CXXTempObjectRegion>(MR)) {
+ const MemRegion *R =
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+
+ SVal L = loc::MemRegionVal(R);
+ state = state->bindLoc(L, V);
+ V = L;
+ }
- state = state->bindLoc(loc::MemRegionVal(R), V);
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
+ Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V));
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
@@ -53,9 +61,9 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
case CXXConstructExpr::CK_Complete: {
// See if we're constructing an existing region by looking at the next
// element in the CFG.
- const CFGBlock *B = currentBuilderContext->getBlock();
- if (currentStmtIdx + 1 < B->size()) {
- CFGElement Next = (*B)[currentStmtIdx+1];
+ const CFGBlock *B = currBldrCtx->getBlock();
+ if (currStmtIdx + 1 < B->size()) {
+ CFGElement Next = (*B)[currStmtIdx+1];
// Is this a constructor for a local variable?
if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) {
@@ -101,8 +109,12 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
// FIXME: This will eventually need to handle new-expressions as well.
}
- // If we couldn't find an existing region to construct into, we'll just
- // generate a symbolic region, which is fine.
+ // If we couldn't find an existing region to construct into, assume we're
+ // constructing a temporary.
+ if (!Target) {
+ MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
+ Target = MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ }
break;
}
@@ -137,7 +149,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
*Call, *this);
ExplodedNodeSet DstInvalidated;
- StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
+ StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
defaultEvalCall(Bldr, *I, *Call);
@@ -151,6 +163,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
void ExprEngine::VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest,
const Stmt *S,
+ bool IsBaseDtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext();
@@ -171,7 +184,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, State, LCtx);
+ CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
@@ -182,7 +195,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
*Call, *this);
ExplodedNodeSet DstInvalidated;
- StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
+ StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
defaultEvalCall(Bldr, *I, *Call);
@@ -198,12 +211,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// Also, we need to decide how allocators actually work -- they're not
// really part of the CXXNewExpr because they happen BEFORE the
// CXXConstructExpr subexpression. See PR12014 for some discussion.
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- unsigned blockCount = currentBuilderContext->getCurrentBlockCount();
+ unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext();
- DefinedOrUnknownSVal symVal =
- svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount);
+ DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx,
+ CNE->getType(),
+ blockCount);
ProgramStateRef State = Pred->getState();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
@@ -215,6 +229,18 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// we should be using the usual pre-/(default-)eval-/post-call checks here.
State = Call->invalidateRegions(blockCount);
+ // 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.
+ // C++11 [basic.stc.dynamic.allocation]p3.
+ FunctionDecl *FD = CNE->getOperatorNew();
+ if (FD && getContext().getLangOpts().CXXExceptions) {
+ QualType Ty = FD->getType();
+ if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>())
+ if (!ProtoType->isNothrow(getContext()))
+ State = State->assume(symVal, true);
+ }
+
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
@@ -232,11 +258,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// CXXNewExpr, we need to make sure that the constructed object is not
// immediately invalidated here. (The placement call should happen before
// the constructor call anyway.)
- FunctionDecl *FD = CNE->getOperatorNew();
if (FD && FD->isReservedGlobalPlacementOperator()) {
// Non-array placement new should always return the placement location.
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
- State = State->BindExpr(CNE, LCtx, PlacementLoc);
+ SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
+ CNE->getPlacementArg(0)->getType());
+ State = State->BindExpr(CNE, LCtx, Result);
} else {
State = State->BindExpr(CNE, LCtx, symVal);
}
@@ -259,7 +286,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
Bldr.generateNode(CDE, Pred, state);
}
@@ -274,18 +301,18 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS,
}
const LocationContext *LCtx = Pred->getLocationContext();
- SVal V = svalBuilder.getConjuredSymbolVal(CS, LCtx, VD->getType(),
- currentBuilderContext->getCurrentBlockCount());
+ SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
+ currBldrCtx->blockCount());
ProgramStateRef state = Pred->getState();
state = state->bindLoc(state->getLValue(VD, LCtx), V);
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(CS, Pred, state);
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
// Get the this object region from StoreManager.
const LocationContext *LCtx = Pred->getLocationContext();
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 3b2e4ec8243b..3ead0817f71b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -17,19 +17,22 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
-#define CXX_INLINING_ENABLED 1
-
using namespace clang;
using namespace ento;
STATISTIC(NumOfDynamicDispatchPathSplits,
"The # of times we split the path due to imprecise dynamic dispatch info");
+STATISTIC(NumInlinedCalls,
+ "The # of times we inlined a call");
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -64,35 +67,47 @@ static std::pair<const Stmt*,
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
- // Back up through the ExplodedGraph until we reach a statement node.
+ // Back up through the ExplodedGraph until we reach a statement node in this
+ // stack frame.
while (Node) {
const ProgramPoint &PP = Node->getLocation();
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
- S = SP->getStmt();
- break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
- S = CEE->getCalleeContext()->getCallSite();
- if (S)
+ if (PP.getLocationContext()->getCurrentStackFrame() == SF) {
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ S = SP->getStmt();
break;
- // If we have an implicit call, we'll probably end up with a
- // StmtPoint inside the callee, which is acceptable.
- // (It's possible a function ONLY contains implicit calls -- such as an
- // implicitly-generated destructor -- so we shouldn't just skip back to
- // the CallEnter node and keep going.)
+ } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
+ S = CEE->getCalleeContext()->getCallSite();
+ if (S)
+ break;
+
+ // If there is no statement, this is an implicitly-generated call.
+ // We'll walk backwards over it and then continue the loop to find
+ // an actual statement.
+ const CallEnter *CE;
+ do {
+ Node = Node->getFirstPred();
+ CE = Node->getLocationAs<CallEnter>();
+ } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
+
+ // Continue searching the graph.
+ }
} else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) {
// If we reached the CallEnter for this function, it has no statements.
if (CE->getCalleeContext() == SF)
break;
}
+ if (Node->pred_empty())
+ return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0);
+
Node = *Node->pred_begin();
}
const CFGBlock *Blk = 0;
if (S) {
// Now, get the enclosing basic block.
- while (Node && Node->pred_size() >=1 ) {
+ while (Node) {
const ProgramPoint &PP = Node->getLocation();
if (isa<BlockEdge>(PP) &&
(PP.getLocationContext()->getCurrentStackFrame() == SF)) {
@@ -100,6 +115,9 @@ static std::pair<const Stmt*,
Blk = EPP.getDst();
break;
}
+ if (Node->pred_empty())
+ return std::pair<const Stmt*, const CFGBlock*>(S, (CFGBlock*)0);
+
Node = *Node->pred_begin();
}
}
@@ -107,6 +125,82 @@ static std::pair<const Stmt*,
return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
}
+/// Adjusts a return value when the called function's return type does not
+/// match the caller's expression type. This can happen when a dynamic call
+/// is devirtualized, and the overridding method has a covariant (more specific)
+/// return type than the parent's method. For C++ objects, this means we need
+/// to add base casts.
+static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
+ StoreManager &StoreMgr) {
+ // For now, the only adjustments we handle apply only to locations.
+ if (!isa<Loc>(V))
+ return V;
+
+ // If the types already match, don't do any unnecessary work.
+ ExpectedTy = ExpectedTy.getCanonicalType();
+ ActualTy = ActualTy.getCanonicalType();
+ if (ExpectedTy == ActualTy)
+ return V;
+
+ // No adjustment is needed between Objective-C pointer types.
+ if (ExpectedTy->isObjCObjectPointerType() &&
+ ActualTy->isObjCObjectPointerType())
+ return V;
+
+ // C++ object pointers may need "derived-to-base" casts.
+ const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl();
+ const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl();
+ if (ExpectedClass && ActualClass) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (ActualClass->isDerivedFrom(ExpectedClass, Paths) &&
+ !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) {
+ return StoreMgr.evalDerivedToBase(V, Paths.front());
+ }
+ }
+
+ // Unfortunately, Objective-C does not enforce that overridden methods have
+ // covariant return types, so we can't assert that that never happens.
+ // Be safe and return UnknownVal().
+ return UnknownVal();
+}
+
+void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ NodeBuilder Bldr(Pred, Dst, BC);
+
+ // Find the last statement in the function and the corresponding basic block.
+ const Stmt *LastSt = 0;
+ const CFGBlock *Blk = 0;
+ llvm::tie(LastSt, Blk) = getLastStmt(Pred);
+ if (!Blk || !LastSt) {
+ return;
+ }
+
+ // If the last statement is return, everything it references should stay live.
+ if (isa<ReturnStmt>(LastSt))
+ return;
+
+ // Here, we call the Symbol Reaper with 0 stack context telling it to clean up
+ // everything on the stack. We use LastStmt as a diagnostic statement, with
+ // which the PreStmtPurgeDead point will be associated.
+ currBldrCtx = &BC;
+ removeDead(Pred, Dst, 0, 0, LastSt,
+ ProgramPoint::PostStmtPurgeDeadSymbolsKind);
+ currBldrCtx = 0;
+}
+
+static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
+ const StackFrameContext *calleeCtx) {
+ const Decl *RuntimeCallee = calleeCtx->getDecl();
+ const Decl *StaticDecl = Call->getDecl();
+ assert(RuntimeCallee);
+ if (!StaticDecl)
+ return true;
+ return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
+}
+
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
@@ -133,6 +227,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
const CFGBlock *Blk = 0;
llvm::tie(LastSt, Blk) = getLastStmt(CEBNode);
+ // Generate a CallEvent /before/ cleaning the state, so that we can get the
+ // correct value for 'this' (if necessary).
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
+
// Step 2: generate node with bound return value: CEBNode -> BindedRetNode.
// If the callee returns an expression, bind its value to CallExpr.
@@ -140,6 +239,19 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
+
+ // Ensure that the return type matches the type of the returned Expr.
+ if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) {
+ QualType ReturnedTy =
+ CallEvent::getDeclaredResultType(calleeCtx->getDecl());
+ if (!ReturnedTy.isNull()) {
+ if (const Expr *Ex = dyn_cast<Expr>(CE)) {
+ V = adjustReturnValue(V, Ex->getType(), ReturnedTy,
+ getStoreManager());
+ }
+ }
+ }
+
state = state->BindExpr(CE, callerCtx, V);
}
@@ -149,23 +261,25 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(This);
- // Always bind the region to the CXXConstructExpr.
+ // If the constructed object is a prvalue, get its bindings.
+ // Note that we have to be careful here because constructors embedded
+ // in DeclStmts are not marked as lvalues.
+ if (!CCE->isGLValue())
+ if (const MemRegion *MR = ThisV.getAsRegion())
+ if (isa<CXXTempObjectRegion>(MR))
+ ThisV = state->getSVal(cast<Loc>(ThisV));
+
state = state->BindExpr(CCE, callerCtx, ThisV);
}
}
- // Generate a CallEvent /before/ cleaning the state, so that we can get the
- // correct value for 'this' (if necessary).
- CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
-
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
// that we report the issues such as leaks in the stack contexts in which
// they occurred.
ExplodedNodeSet CleanedNodes;
- if (LastSt && Blk) {
+ if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value");
PostStmt Loc(LastSt, calleeCtx, &retValBind);
bool isNew;
@@ -175,14 +289,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
return;
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
- currentBuilderContext = &Ctx;
+ currBldrCtx = &Ctx;
// Here, we call the Symbol Reaper with 0 statement and caller location
// context, telling it to clean up everything in the callee's context
// (and it's children). We use LastStmt as a diagnostic statement, which
// which the PreStmtPurge Dead point will be associated.
removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt,
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
- currentBuilderContext = 0;
+ currBldrCtx = 0;
} else {
CleanedNodes.Add(CEBNode);
}
@@ -204,9 +318,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// result onto the work list.
// CEENode -> Dst -> WorkList
NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
- SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
+ SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx,
&Ctx);
- SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
+ SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex());
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
@@ -236,14 +350,48 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
}
}
-static unsigned getNumberStackFrames(const LocationContext *LCtx) {
- unsigned count = 0;
+void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx,
+ bool &IsRecursive, unsigned &StackDepth) {
+ IsRecursive = false;
+ StackDepth = 0;
+
while (LCtx) {
- if (isa<StackFrameContext>(LCtx))
- ++count;
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) {
+ const Decl *DI = SFC->getDecl();
+
+ // Mark recursive (and mutually recursive) functions and always count
+ // them when measuring the stack depth.
+ if (DI == D) {
+ IsRecursive = true;
+ ++StackDepth;
+ LCtx = LCtx->getParent();
+ continue;
+ }
+
+ // Do not count the small functions when determining the stack depth.
+ AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+ if (CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
+ ++StackDepth;
+ }
LCtx = LCtx->getParent();
}
- return count;
+
+}
+
+static bool IsInStdNamespace(const FunctionDecl *FD) {
+ const DeclContext *DC = FD->getEnclosingNamespaceContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return false;
+
+ while (const DeclContext *Parent = ND->getParent()) {
+ if (!isa<NamespaceDecl>(Parent))
+ break;
+ ND = cast<NamespaceDecl>(Parent);
+ }
+
+ return ND->getName() == "std";
}
// Determine if we should inline the call.
@@ -256,14 +404,18 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
if (!CalleeCFG)
return false;
- if (getNumberStackFrames(Pred->getLocationContext())
- == AMgr.InlineMaxStackDepth)
+ bool IsRecursive = false;
+ unsigned StackDepth = 0;
+ examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
+ if ((StackDepth >= AMgr.options.InlineMaxStackDepth) &&
+ ((CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
+ || IsRecursive))
return false;
if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D))
return false;
- if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize)
+ if (CalleeCFG->getNumBlockIDs() > AMgr.options.InlineMaxFunctionSize)
return false;
// Do not inline variadic calls (for now).
@@ -276,6 +428,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
return false;
}
+ if (getContext().getLangOpts().CPlusPlus) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Conditionally allow the inlining of template functions.
+ if (!getAnalysisManager().options.mayInlineTemplateFunctions())
+ if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ return false;
+
+ // Conditionally allow the inlining of C++ standard library functions.
+ if (!getAnalysisManager().options.mayInlineCXXStandardLibrary())
+ if (getContext().getSourceManager().isInSystemHeader(FD->getLocation()))
+ if (IsInStdNamespace(FD))
+ return false;
+ }
+ }
+
// It is possible that the live variables analysis cannot be
// run. If so, bail out.
if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
@@ -284,26 +451,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
return true;
}
-/// The GDM component containing the dynamic dispatch bifurcation info. When
-/// the exact type of the receiver is not known, we want to explore both paths -
-/// one on which we do inline it and the other one on which we don't. This is
-/// done to ensure we do not drop coverage.
-/// This is the map from the receiver region to a bool, specifying either we
-/// consider this region's information precise or not along the given path.
-namespace clang {
-namespace ento {
-enum DynamicDispatchMode { DynamicDispatchModeInlined = 1,
- DynamicDispatchModeConservative };
-
-struct DynamicDispatchBifurcationMap {};
-typedef llvm::ImmutableMap<const MemRegion*,
- unsigned int> DynamicDispatchBifur;
-template<> struct ProgramStateTrait<DynamicDispatchBifurcationMap>
- : public ProgramStatePartialTrait<DynamicDispatchBifur> {
- static void *GDMIndex() { static int index; return &index; }
-};
-
-}}
+// The GDM component containing the dynamic dispatch bifurcation info. When
+// the exact type of the receiver is not known, we want to explore both paths -
+// one on which we do inline it and the other one on which we don't. This is
+// done to ensure we do not drop coverage.
+// This is the map from the receiver region to a bool, specifying either we
+// consider this region's information precise or not along the given path.
+namespace {
+ enum DynamicDispatchMode {
+ DynamicDispatchModeInlined = 1,
+ DynamicDispatchModeConservative
+ };
+}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
+ CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *,
+ unsigned))
bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
NodeBuilder &Bldr, ExplodedNode *Pred,
@@ -314,24 +476,19 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
const LocationContext *ParentOfCallee = 0;
+ AnalyzerOptions &Opts = getAnalysisManager().options;
+
// FIXME: Refactor this check into a hypothetical CallEvent::canInline.
switch (Call.getKind()) {
case CE_Function:
break;
case CE_CXXMember:
case CE_CXXMemberOperator:
- if (!CXX_INLINING_ENABLED)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
return false;
break;
case CE_CXXConstructor: {
- if (!CXX_INLINING_ENABLED)
- return false;
-
- // Only inline constructors and destructors if we built the CFGs for them
- // properly.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
- !ADC->getCFGBuildOptions().AddInitializers)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
return false;
const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
@@ -341,9 +498,31 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
if (Target && isa<ElementRegion>(Target))
return false;
+ // FIXME: This is a hack. We don't use the correct region for a new
+ // expression, so if we inline the constructor its result will just be
+ // thrown away. This short-term hack is tracked in <rdar://problem/12180598>
+ // and the longer-term possible fix is discussed in PR12014.
+ const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
+ if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr))
+ if (isa<CXXNewExpr>(Parent))
+ return false;
+
+ // Inlining constructors requires including initializers in the CFG.
+ const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
+ assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
+ (void)ADC;
+
+ // If the destructor is trivial, it's always safe to inline the constructor.
+ if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
+ break;
+
+ // For other types, only inline constructors if destructor inlining is
+ // also enabled.
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
+ return false;
+
// FIXME: This is a hack. We don't handle temporary destructors
// right now, so we shouldn't inline their constructors.
- const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
if (!Target || !isa<DeclRegion>(Target))
return false;
@@ -351,15 +530,13 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_CXXDestructor: {
- if (!CXX_INLINING_ENABLED)
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
return false;
- // Only inline constructors and destructors if we built the CFGs for them
- // properly.
+ // Inlining destructors requires building the CFG correctly.
const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
- !ADC->getCFGBuildOptions().AddInitializers)
- return false;
+ assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
+ (void)ADC;
const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
@@ -371,9 +548,6 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_CXXAllocator:
- if (!CXX_INLINING_ENABLED)
- return false;
-
// Do not inline allocators until we model deallocators.
// This is unfortunate, but basically necessary for smart pointers and such.
return false;
@@ -387,8 +561,10 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
break;
}
case CE_ObjCMessage:
- if (!(getAnalysisManager().IPAMode == DynamicDispatch ||
- getAnalysisManager().IPAMode == DynamicDispatchBifurcate))
+ if (!Opts.mayInlineObjCMethod())
+ return false;
+ if (!(getAnalysisManager().options.IPAMode == DynamicDispatch ||
+ getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate))
return false;
break;
}
@@ -406,8 +582,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const StackFrameContext *CalleeSFC =
CalleeADC->getStackFrame(ParentOfCallee, CallE,
- currentBuilderContext->getBlock(),
- currentStmtIdx);
+ currBldrCtx->getBlock(),
+ currStmtIdx);
CallEnter Loc(CallE, CalleeSFC, CurLC);
@@ -426,6 +602,12 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
// added onto the work list so remove it from the node builder.
Bldr.takeNodes(Pred);
+ NumInlinedCalls++;
+
+ // Mark the decl as visited.
+ if (VisitedCallees)
+ VisitedCallees->insert(D);
+
return true;
}
@@ -520,8 +702,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conjure a symbol if the return value is unknown.
QualType ResultTy = Call.getResultType();
SValBuilder &SVB = getSValBuilder();
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- SVal R = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+ unsigned Count = currBldrCtx->blockCount();
+ SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count);
return State->BindExpr(E, LCtx, R);
}
@@ -529,8 +711,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State) {
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- State = Call.invalidateRegions(Count, State);
+ State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
// And make the result node.
@@ -562,13 +743,13 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
if (D) {
if (RD.mayHaveOtherDefinitions()) {
// Explore with and without inlining the call.
- if (getAnalysisManager().IPAMode == DynamicDispatchBifurcate) {
+ if (getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate) {
BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred);
return;
}
// Don't inline if we're not in any dynamic dispatch mode.
- if (getAnalysisManager().IPAMode != DynamicDispatch) {
+ if (getAnalysisManager().options.IPAMode != DynamicDispatch) {
conservativeEvalCall(*Call, Bldr, Pred, State);
return;
}
@@ -593,7 +774,7 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg,
// Check if we've performed the split already - note, we only want
// to split the path once per memory region.
ProgramStateRef State = Pred->getState();
- const unsigned int *BState =
+ const unsigned *BState =
State->get<DynamicDispatchBifurcationMap>(BifurReg);
if (BState) {
// If we are on "inline path", keep inlining if possible.
@@ -630,7 +811,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
- StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+ StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
if (RS->getRetValue()) {
for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index e3bc498b51e8..51dda19b5315 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -28,7 +28,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar;
- StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
// Perform the post-condition check of the ObjCIvarRefExpr and store
@@ -88,7 +88,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
ExplodedNodeSet Tmp;
- StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
@@ -112,8 +112,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType();
assert(Loc::isLocType(T));
- unsigned Count = currentBuilderContext->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count);
+ SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
+ currBldrCtx->blockCount());
SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V);
@@ -132,14 +132,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
}
-static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
- if (!Class)
- return false;
- if (Class->getIdentifier() == II)
- return true;
- return isSubclass(Class->getSuperClass(), II);
-}
-
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
@@ -157,7 +149,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
- StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
+ StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx);
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
@@ -184,68 +176,30 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// Check if the "raise" message was sent.
assert(notNilState);
- if (Msg->getSelector() == RaiseSel) {
+ if (ObjCNoRet.isImplicitNoReturn(ME)) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- Bldr.generateNode(currentStmt, Pred, State, true);
+ Bldr.generateSink(currStmt, Pred, State);
continue;
}
// Generate a transition to non-Nil state.
- if (notNilState != State)
- Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
+ if (notNilState != State) {
+ Pred = Bldr.generateNode(currStmt, Pred, notNilState);
+ assert(Pred && "Should have cached out already!");
+ }
}
} else {
- // Check for special class methods.
- if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
- if (!NSExceptionII) {
- ASTContext &Ctx = getContext();
- NSExceptionII = &Ctx.Idents.get("NSException");
- }
-
- if (isSubclass(Iface, NSExceptionII)) {
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
- if (!NSExceptionInstanceRaiseSelectors) {
- ASTContext &Ctx = getContext();
- NSExceptionInstanceRaiseSelectors =
- new Selector[NUM_RAISE_SELECTORS];
- SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
-
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format:arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- Selector S = Msg->getSelector();
- bool RaisesException = false;
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true;
- break;
- }
- }
- if (RaisesException) {
- // If we raise an exception, for now treat it as a sink.
- // Eventually we will want to handle exceptions properly.
- Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
- continue;
- }
-
- }
+ // Check for special class methods that are known to not return
+ // and that we should treat as a sink.
+ if (ObjCNoRet.isImplicitNoReturn(ME)) {
+ // If we raise an exception, for now treat it as a sink.
+ // Eventually we will want to handle exceptions properly.
+ Bldr.generateSink(currStmt, Pred, Pred->getState());
+ continue;
}
}
- // Evaluate the call.
defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 982bcbfcdf9a..fd875f66d2db 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -17,8 +17,8 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Rewrite/Rewriter.h"
-#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/FileSystem.h"
@@ -189,7 +189,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
- << D.getDescription() << "</td></tr>\n";
+ << D.getVerboseDescription() << "</td></tr>\n";
// Output any other meta data.
@@ -209,15 +209,15 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
std::string s;
llvm::raw_string_ostream os(s);
- const std::string& BugDesc = D.getDescription();
+ StringRef BugDesc = D.getVerboseDescription();
if (!BugDesc.empty())
os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
- const std::string& BugType = D.getBugType();
+ StringRef BugType = D.getBugType();
if (!BugType.empty())
os << "\n<!-- BUGTYPE " << BugType << " -->\n";
- const std::string& BugCategory = D.getCategory();
+ StringRef BugCategory = D.getCategory();
if (!BugCategory.empty())
os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
@@ -267,8 +267,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
}
if (filesMade) {
- filesMade->push_back(std::make_pair(StringRef(getName()),
- llvm::sys::path::filename(H.str())));
+ filesMade->addDiagnostic(D, getName(), llvm::sys::path::filename(H.str()));
}
// Emit the HTML to disk.
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 62e602a7e1e1..fab10cfd3d04 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -352,7 +352,7 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const FunctionDecl *FD,
+ const NamedDecl *FD,
const MemRegion*) {
ID.AddInteger(MemRegion::FunctionTextRegionKind);
ID.AddPointer(FD);
@@ -444,7 +444,7 @@ void MemRegion::dumpToStream(raw_ostream &os) const {
}
void AllocaRegion::dumpToStream(raw_ostream &os) const {
- os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
+ os << "alloca{" << (const void*) Ex << ',' << Cnt << '}';
}
void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
@@ -452,7 +452,7 @@ void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
}
void BlockTextRegion::dumpToStream(raw_ostream &os) const {
- os << "block_code{" << (void*) this << '}';
+ os << "block_code{" << (const void*) this << '}';
}
void BlockDataRegion::dumpToStream(raw_ostream &os) const {
@@ -461,12 +461,12 @@ void BlockDataRegion::dumpToStream(raw_ostream &os) const {
void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
// FIXME: More elaborate pretty-printing.
- os << "{ " << (void*) CL << " }";
+ os << "{ " << (const void*) CL << " }";
}
void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
os << "temp_object{" << getValueType().getAsString() << ','
- << (void*) Ex << '}';
+ << (const void*) Ex << '}';
}
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
@@ -748,11 +748,11 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
}
else {
assert(D->isStaticLocal());
- const Decl *D = STC->getDecl();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ const Decl *STCD = STC->getDecl();
+ if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD))
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- getFunctionTextRegion(FD));
- else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ getFunctionTextRegion(cast<NamedDecl>(STCD)));
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
const BlockTextRegion *BTR =
getBlockTextRegion(BD,
C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
@@ -761,8 +761,6 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
BTR);
}
else {
- // FIXME: For ObjC-methods, we need a new CodeTextRegion. For now
- // just use the main global memspace.
sReg = getGlobalsRegion();
}
}
@@ -845,7 +843,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
}
const FunctionTextRegion *
-MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+MemRegionManager::getFunctionTextRegion(const NamedDecl *FD) {
return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
}
@@ -990,6 +988,10 @@ const MemRegion *MemRegion::getBaseRegion() const {
return R;
}
+bool MemRegion::isSubRegionOf(const MemRegion *R) const {
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// View handling.
//===----------------------------------------------------------------------===//
@@ -1107,7 +1109,7 @@ RegionOffset MemRegion::getAsOffset() const {
// If our base region is symbolic, we don't know what type it really is.
// Pretend the type of the symbol is the true dynamic type.
// (This will at least be self-consistent for the life of the symbol.)
- Ty = SR->getSymbol()->getType(getContext())->getPointeeType();
+ Ty = SR->getSymbol()->getType()->getPointeeType();
}
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
@@ -1166,8 +1168,12 @@ RegionOffset MemRegion::getAsOffset() const {
R = FR->getSuperRegion();
const RecordDecl *RD = FR->getDecl()->getParent();
- if (!RD->isCompleteDefinition()) {
+ if (RD->isUnion() || !RD->isCompleteDefinition()) {
// We cannot compute offset for incomplete type.
+ // For unions, we could treat everything as offset 0, but we'd rather
+ // treat each field as a symbolic offset so they aren't stored on top
+ // of each other, since we depend on things in typed regions actually
+ // matching their types.
SymbolicOffsetBase = R;
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index c849778e7f23..0f48d1e1c798 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
@@ -104,11 +105,12 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
PathDiagnostic::~PathDiagnostic() {}
PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
- StringRef bugtype, StringRef desc,
- StringRef category)
+ StringRef bugtype, StringRef verboseDesc,
+ StringRef shortDesc, StringRef category)
: DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
- Desc(StripTrailingDots(desc)),
+ VerboseDesc(StripTrailingDots(verboseDesc)),
+ ShortDesc(StripTrailingDots(shortDesc)),
Category(StripTrailingDots(category)),
path(pathImpl) {}
@@ -198,6 +200,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
if (orig_size <= new_size)
return;
+ assert(orig != D);
Diags.RemoveNode(orig);
delete orig;
}
@@ -205,39 +208,151 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
Diags.InsertNode(OwningD.take());
}
+static llvm::Optional<bool> comparePath(const PathPieces &X,
+ const PathPieces &Y);
+static llvm::Optional<bool>
+compareControlFlow(const PathDiagnosticControlFlowPiece &X,
+ const PathDiagnosticControlFlowPiece &Y) {
+ FullSourceLoc XSL = X.getStartLocation().asLocation();
+ FullSourceLoc YSL = Y.getStartLocation().asLocation();
+ if (XSL != YSL)
+ return XSL.isBeforeInTranslationUnitThan(YSL);
+ FullSourceLoc XEL = X.getEndLocation().asLocation();
+ FullSourceLoc YEL = Y.getEndLocation().asLocation();
+ if (XEL != YEL)
+ return XEL.isBeforeInTranslationUnitThan(YEL);
+ return llvm::Optional<bool>();
+}
+
+static llvm::Optional<bool>
+compareMacro(const PathDiagnosticMacroPiece &X,
+ const PathDiagnosticMacroPiece &Y) {
+ return comparePath(X.subPieces, Y.subPieces);
+}
+
+static llvm::Optional<bool>
+compareCall(const PathDiagnosticCallPiece &X,
+ const PathDiagnosticCallPiece &Y) {
+ FullSourceLoc X_CEL = X.callEnter.asLocation();
+ FullSourceLoc Y_CEL = Y.callEnter.asLocation();
+ if (X_CEL != Y_CEL)
+ return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
+ FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
+ FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
+ if (X_CEWL != Y_CEWL)
+ return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
+ FullSourceLoc X_CRL = X.callReturn.asLocation();
+ FullSourceLoc Y_CRL = Y.callReturn.asLocation();
+ if (X_CRL != Y_CRL)
+ return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
+ return comparePath(X.path, Y.path);
+}
+
+static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
+ const PathDiagnosticPiece &Y) {
+ if (X.getKind() != Y.getKind())
+ return X.getKind() < Y.getKind();
+
+ FullSourceLoc XL = X.getLocation().asLocation();
+ FullSourceLoc YL = Y.getLocation().asLocation();
+ if (XL != YL)
+ return XL.isBeforeInTranslationUnitThan(YL);
+
+ if (X.getString() != Y.getString())
+ return X.getString() < Y.getString();
+
+ if (X.getRanges().size() != Y.getRanges().size())
+ return X.getRanges().size() < Y.getRanges().size();
+
+ const SourceManager &SM = XL.getManager();
+
+ for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
+ SourceRange XR = X.getRanges()[i];
+ SourceRange YR = Y.getRanges()[i];
+ if (XR != YR) {
+ if (XR.getBegin() != YR.getBegin())
+ return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
+ return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
+ }
+ }
+
+ switch (X.getKind()) {
+ case clang::ento::PathDiagnosticPiece::ControlFlow:
+ return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
+ cast<PathDiagnosticControlFlowPiece>(Y));
+ case clang::ento::PathDiagnosticPiece::Event:
+ return llvm::Optional<bool>();
+ case clang::ento::PathDiagnosticPiece::Macro:
+ return compareMacro(cast<PathDiagnosticMacroPiece>(X),
+ cast<PathDiagnosticMacroPiece>(Y));
+ case clang::ento::PathDiagnosticPiece::Call:
+ return compareCall(cast<PathDiagnosticCallPiece>(X),
+ cast<PathDiagnosticCallPiece>(Y));
+ }
+ llvm_unreachable("all cases handled");
+}
+
+static llvm::Optional<bool> comparePath(const PathPieces &X,
+ const PathPieces &Y) {
+ if (X.size() != Y.size())
+ return X.size() < Y.size();
+ for (unsigned i = 0, n = X.size(); i != n; ++i) {
+ llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]);
+ if (b.hasValue())
+ return b.getValue();
+ }
+ return llvm::Optional<bool>();
+}
+
+static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
+ FullSourceLoc XL = X.getLocation().asLocation();
+ FullSourceLoc YL = Y.getLocation().asLocation();
+ if (XL != YL)
+ return XL.isBeforeInTranslationUnitThan(YL);
+ if (X.getBugType() != Y.getBugType())
+ return X.getBugType() < Y.getBugType();
+ if (X.getCategory() != Y.getCategory())
+ return X.getCategory() < Y.getCategory();
+ if (X.getVerboseDescription() != Y.getVerboseDescription())
+ return X.getVerboseDescription() < Y.getVerboseDescription();
+ if (X.getShortDescription() != Y.getShortDescription())
+ return X.getShortDescription() < Y.getShortDescription();
+ if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
+ const Decl *XD = X.getDeclWithIssue();
+ if (!XD)
+ return true;
+ const Decl *YD = Y.getDeclWithIssue();
+ if (!YD)
+ return false;
+ SourceLocation XDL = XD->getLocation();
+ SourceLocation YDL = YD->getLocation();
+ if (XDL != YDL) {
+ const SourceManager &SM = XL.getManager();
+ return SM.isBeforeInTranslationUnit(XDL, YDL);
+ }
+ }
+ PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
+ PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
+ if (XE - XI != YE - YI)
+ return (XE - XI) < (YE - YI);
+ for ( ; XI != XE ; ++XI, ++YI) {
+ if (*XI != *YI)
+ return (*XI) < (*YI);
+ }
+ llvm::Optional<bool> b = comparePath(X.path, Y.path);
+ assert(b.hasValue());
+ return b.getValue();
+}
namespace {
struct CompareDiagnostics {
// Compare if 'X' is "<" than 'Y'.
bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
- // First compare by location
- const FullSourceLoc &XLoc = X->getLocation().asLocation();
- const FullSourceLoc &YLoc = Y->getLocation().asLocation();
- if (XLoc < YLoc)
- return true;
- if (XLoc != YLoc)
+ if (X == Y)
return false;
-
- // Next, compare by bug type.
- StringRef XBugType = X->getBugType();
- StringRef YBugType = Y->getBugType();
- if (XBugType < YBugType)
- return true;
- if (XBugType != YBugType)
- return false;
-
- // Next, compare by bug description.
- StringRef XDesc = X->getDescription();
- StringRef YDesc = Y->getDescription();
- if (XDesc < YDesc)
- return true;
- if (XDesc != YDesc)
- return false;
-
- // FIXME: Further refine by comparing PathDiagnosticPieces?
- return false;
- }
-};
+ return compare(*X, *Y);
+ }
+};
}
void PathDiagnosticConsumer::FlushDiagnostics(
@@ -250,11 +365,9 @@ void PathDiagnosticConsumer::FlushDiagnostics(
std::vector<const PathDiagnostic *> BatchDiags;
for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
et = Diags.end(); it != et; ++it) {
- BatchDiags.push_back(&*it);
+ const PathDiagnostic *D = &*it;
+ BatchDiags.push_back(D);
}
-
- // Clear out the FoldingSet.
- Diags.clear();
// Sort the diagnostics so that they are always emitted in a deterministic
// order.
@@ -269,6 +382,42 @@ void PathDiagnosticConsumer::FlushDiagnostics(
const PathDiagnostic *D = *it;
delete D;
}
+
+ // Clear out the FoldingSet.
+ Diags.clear();
+}
+
+void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
+ StringRef ConsumerName,
+ StringRef FileName) {
+ llvm::FoldingSetNodeID NodeID;
+ NodeID.Add(PD);
+ void *InsertPos;
+ PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ if (!Entry) {
+ Entry = Alloc.Allocate<PDFileEntry>();
+ Entry = new (Entry) PDFileEntry(NodeID);
+ InsertNode(Entry, InsertPos);
+ }
+
+ // Allocate persistent storage for the file name.
+ char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
+ memcpy(FileName_cstr, FileName.data(), FileName.size());
+
+ Entry->files.push_back(std::make_pair(ConsumerName,
+ StringRef(FileName_cstr,
+ FileName.size())));
+}
+
+PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
+PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
+ llvm::FoldingSetNodeID NodeID;
+ NodeID.Add(PD);
+ void *InsertPos;
+ PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
+ if (!Entry)
+ return 0;
+ return &Entry->files;
}
//===----------------------------------------------------------------------===//
@@ -437,8 +586,8 @@ PathDiagnosticLocation
const CFGBlock *BSrc = BE->getSrc();
S = BSrc->getTerminatorCondition();
}
- else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- S = PS->getStmt();
+ else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ S = SP->getStmt();
}
else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
return PathDiagnosticLocation(PIE->getLocation(), SMng);
@@ -453,6 +602,9 @@ PathDiagnosticLocation
CEE->getLocationContext(),
SMng);
}
+ else {
+ llvm_unreachable("Unexpected ProgramPoint");
+ }
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
}
@@ -463,21 +615,26 @@ PathDiagnosticLocation
assert(N && "Cannot create a location with a null node.");
const ExplodedNode *NI = N;
+ const Stmt *S = 0;
while (NI) {
ProgramPoint P = NI->getLocation();
- const LocationContext *LC = P.getLocationContext();
if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
- return PathDiagnosticLocation(PS->getStmt(), SM, LC);
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- const Stmt *Term = BE->getSrc()->getTerminator();
- if (Term) {
- return PathDiagnosticLocation(Term, SM, LC);
- }
- }
+ S = PS->getStmt();
+ else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ S = BE->getSrc()->getTerminator();
+ if (S)
+ break;
NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
}
+ if (S) {
+ const LocationContext *LC = NI->getLocationContext();
+ if (S->getLocStart().isValid())
+ return PathDiagnosticLocation(S, SM, LC);
+ return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
+ }
+
return createDeclEnd(N->getLocationContext(), SM);
}
@@ -587,24 +744,6 @@ void PathDiagnosticLocation::flatten() {
}
}
-PathDiagnosticLocation PathDiagnostic::getLocation() const {
- assert(path.size() > 0 &&
- "getLocation() requires a non-empty PathDiagnostic.");
-
- PathDiagnosticPiece *p = path.rbegin()->getPtr();
-
- while (true) {
- if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
- assert(!cp->path.empty());
- p = cp->path.rbegin()->getPtr();
- continue;
- }
- break;
- }
-
- return p->getLocation();
-}
-
//===----------------------------------------------------------------------===//
// Manipulation of PathDiagnosticCallPieces.
//===----------------------------------------------------------------------===//
@@ -753,10 +892,9 @@ void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
}
void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
- if (!path.empty())
- getLocation().Profile(ID);
+ ID.Add(getLocation());
ID.AddString(BugType);
- ID.AddString(Desc);
+ ID.AddString(VerboseDesc);
ID.AddString(Category);
}
@@ -818,42 +956,16 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
return getMessageForSymbolNotFound();
}
-/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
-/// some common place. (Same as HandleOrdinalModifier.)
-void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
- llvm::raw_svector_ostream &Out) {
- assert(ValNo != 0 && "ValNo must be strictly positive!");
-
- // We could use text forms for the first N ordinals, but the numeric
- // forms are actually nicer in diagnostics because they stand out.
- Out << ValNo;
-
- // It is critically important that we do this perfectly for
- // user-written sequences with over 100 elements.
- switch (ValNo % 100) {
- case 11:
- case 12:
- case 13:
- Out << "th"; return;
- default:
- switch (ValNo % 10) {
- case 1: Out << "st"; return;
- case 2: Out << "nd"; return;
- case 3: Out << "rd"; return;
- default: Out << "th"; return;
- }
- }
-}
-
std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
- unsigned ArgIndex) {
+ unsigned ArgIndex) {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << Msg << " via ";
- // Printed parameters start at 1, not 0.
- printOrdinal(++ArgIndex, os);
- os << " parameter";
+ os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+ << " parameter";
return os.str();
}
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index d5fdd9d2bb99..17ef4cf571e8 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -13,8 +13,9 @@
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Casting.h"
@@ -47,7 +48,6 @@ namespace {
PathGenerationScheme getGenerationScheme() const { return Extensive; }
bool supportsLogicalOpControlFlow() const { return true; }
bool supportsAllBlockEdges() const { return true; }
- virtual bool useVerboseDescription() const { return false; }
virtual bool supportsCrossFileDiagnostics() const {
return SupportsCrossFileDiagnostics;
}
@@ -247,6 +247,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
// Output the short text.
// FIXME: Really use a short string.
Indent(o, indent) << "<key>message</key>\n";
+ Indent(o, indent);
EmitString(o, P.getString()) << '\n';
// Finish up.
@@ -409,10 +410,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
"<plist version=\"1.0\">\n";
// Write the root object: a <dict> containing...
+ // - "clang_version", the string representation of clang version
// - "files", an <array> mapping from FIDs to file names
// - "diagnostics", an <array> containing the path diagnostics
- o << "<dict>\n"
- " <key>files</key>\n"
+ o << "<dict>\n" <<
+ " <key>clang_version</key>\n";
+ EmitString(o, getClangFullVersion()) << '\n';
+ o << " <key>files</key>\n"
" <array>\n";
for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
@@ -443,7 +447,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the bug type and bug category.
o << " <key>description</key>";
- EmitString(o, D->getDescription()) << '\n';
+ EmitString(o, D->getShortDescription()) << '\n';
o << " <key>category</key>";
EmitString(o, D->getCategory()) << '\n';
o << " <key>type</key>";
@@ -499,19 +503,23 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the diagnostic to the sub-diagnostic client, if any.
if (!filesMade->empty()) {
StringRef lastName;
- for (FilesMade::iterator I = filesMade->begin(), E = filesMade->end();
- I != E; ++I) {
- StringRef newName = I->first;
- if (newName != lastName) {
- if (!lastName.empty())
- o << " </array>\n";
- lastName = newName;
- o << " <key>" << lastName << "_files</key>\n";
- o << " <array>\n";
+ PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
+ if (files) {
+ for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
+ CE = files->end(); CI != CE; ++CI) {
+ StringRef newName = CI->first;
+ if (newName != lastName) {
+ if (!lastName.empty()) {
+ o << " </array>\n";
+ }
+ lastName = newName;
+ o << " <key>" << lastName << "_files</key>\n";
+ o << " <array>\n";
+ }
+ o << " <string>" << CI->second << "</string>\n";
}
- o << " <string>" << I->second << "</string>\n";
+ o << " </array>\n";
}
- o << " </array>\n";
}
// Close up the entry.
@@ -521,10 +529,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " </array>\n";
// Finish.
- o << "</dict>\n</plist>";
-
- if (filesMade) {
- StringRef Name(getName());
- filesMade->push_back(std::make_pair(Name, OutputFile));
- }
+ o << "</dict>\n</plist>";
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 2000338ee0a6..b49a11e64214 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -22,10 +22,6 @@
using namespace clang;
using namespace ento;
-// Give the vtable for ConstraintManager somewhere to live.
-// FIXME: Move this elsewhere.
-ConstraintManager::~ConstraintManager() {}
-
namespace clang { namespace ento {
/// Increments the number of times this state is referenced.
@@ -75,8 +71,8 @@ ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
StoreManagerCreator CreateSMgr,
ConstraintManagerCreator CreateCMgr,
llvm::BumpPtrAllocator &alloc,
- SubEngine &SubEng)
- : Eng(&SubEng), EnvMgr(alloc), GDMFactory(alloc),
+ SubEngine *SubEng)
+ : Eng(SubEng), EnvMgr(alloc), GDMFactory(alloc),
svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
StoreMgr.reset((*CreateSMgr)(*this));
@@ -110,47 +106,25 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
SymReaper);
NewState.setStore(newStore);
SymReaper.setReapedStore(newStore);
-
- return getPersistentState(NewState);
-}
-
-ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state,
- const StackFrameContext *InitLoc) {
- // make up an empty state for now.
- ProgramState State(this,
- EnvMgr.getInitialEnvironment(),
- StoreMgr->getInitialStore(InitLoc),
- GDMFactory.getEmptyMap());
- return getPersistentState(State);
+ ProgramStateRef Result = getPersistentState(NewState);
+ return ConstraintMgr->removeDeadBindings(Result, SymReaper);
}
ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const {
const StoreRef &newStore =
- getStateManager().StoreMgr->BindCompoundLiteral(getStore(), CL, LC, V);
+ getStateManager().StoreMgr->bindCompoundLiteral(getStore(), CL, LC, V);
return makeWithStore(newStore);
}
-ProgramStateRef ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const {
- const StoreRef &newStore =
- getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal);
- return makeWithStore(newStore);
-}
-
-ProgramStateRef ProgramState::bindDeclWithNoInit(const VarRegion* VR) const {
- const StoreRef &newStore =
- getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR);
- return makeWithStore(newStore);
-}
-
-ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V) const {
+ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const {
ProgramStateManager &Mgr = getStateManager();
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V));
const MemRegion *MR = LV.getAsRegion();
- if (MR && Mgr.getOwningEngine())
+ if (MR && Mgr.getOwningEngine() && notifyChanges)
return Mgr.getOwningEngine()->processRegionChange(newState, MR);
return newState;
@@ -204,11 +178,12 @@ ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
return makeWithStore(newStore);
}
-ProgramStateRef ProgramState::unbindLoc(Loc LV) const {
+ProgramStateRef ProgramState::killBinding(Loc LV) const {
assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
Store OldStore = getStore();
- const StoreRef &newStore = getStateManager().StoreMgr->Remove(OldStore, LV);
+ const StoreRef &newStore =
+ getStateManager().StoreMgr->killBinding(OldStore, LV);
if (newStore.getStore() == OldStore)
return this;
@@ -249,7 +224,9 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
// about).
if (!T.isNull()) {
if (SymbolRef sym = V.getAsSymbol()) {
- if (const llvm::APSInt *Int = getSymVal(sym)) {
+ if (const llvm::APSInt *Int = getStateManager()
+ .getConstraintManager()
+ .getSymVal(this, sym)) {
// FIXME: Because we don't correctly model (yet) sign-extension
// and truncation of symbolic values, we need to convert
// the integer value to the correct signedness and bitwidth.
@@ -710,7 +687,9 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) {
- assert(isa<SymbolData>(*SI));
+ if (!isa<SymbolData>(*SI))
+ continue;
+
const TaintTagType *Tag = get<TaintMap>(*SI);
Tainted = (Tag && *Tag == Kind);
@@ -734,15 +713,10 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
}
/// The GDM component containing the dynamic type info. This is a map from a
-/// symbol to it's most likely type.
-namespace clang {
-namespace ento {
-typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> DynamicTypeMap;
-template<> struct ProgramStateTrait<DynamicTypeMap>
- : public ProgramStatePartialTrait<DynamicTypeMap> {
- static void *GDMIndex() { static int index; return &index; }
-};
-}}
+/// symbol to its most likely type.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicTypeMap,
+ CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *,
+ DynamicTypeInfo))
DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
Reg = Reg->StripCasts();
@@ -758,7 +732,7 @@ DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
SymbolRef Sym = SR->getSymbol();
- return DynamicTypeInfo(Sym->getType(getStateManager().getContext()));
+ return DynamicTypeInfo(Sym->getType());
}
return DynamicTypeInfo();
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 550404a51075..411094bc1d14 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -24,9 +24,6 @@
using namespace clang;
using namespace ento;
-namespace { class ConstraintRange {}; }
-static int ConstraintRangeIndex = 0;
-
/// A Range represents the closed range [from, to]. The caller must
/// guarantee that from <= to. Note that Range is immutable, so as not
/// to subvert RangeSet's immutability.
@@ -280,23 +277,15 @@ public:
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<ConstraintRange>
- : public ProgramStatePartialTrait<ConstraintRangeTy> {
- static inline void *GDMIndex() { return &ConstraintRangeIndex; }
-};
-}
-}
+REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintRange,
+ CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef,
+ RangeSet))
namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
public:
- RangeConstraintManager(SubEngine &subengine, BasicValueFactory &BVF)
+ RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF)
: SimpleConstraintManager(subengine, BVF) {}
ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
@@ -324,12 +313,7 @@ public:
const llvm::APSInt& Adjustment);
const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
-
- // FIXME: Refactor into SimpleConstraintManager?
- bool isEqual(ProgramStateRef St, SymbolRef sym, const llvm::APSInt& V) const {
- const llvm::APSInt *i = getSymVal(St, sym);
- return i ? *i == V : false;
- }
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
@@ -343,7 +327,7 @@ private:
} // end anonymous namespace
ConstraintManager *
-ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine &Eng) {
+ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
return new RangeConstraintManager(Eng, StMgr.getBasicVals());
}
@@ -353,6 +337,30 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
return T ? T->getConcreteValue() : NULL;
}
+ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
+ SymbolRef Sym) {
+ const RangeSet *Ranges = State->get<ConstraintRange>(Sym);
+
+ // If we don't have any information about this symbol, it's underconstrained.
+ if (!Ranges)
+ return ConditionTruthVal();
+
+ // If we have a concrete value, see if it's zero.
+ if (const llvm::APSInt *Value = Ranges->getConcreteValue())
+ return *Value == 0;
+
+ BasicValueFactory &BV = getBasicVals();
+ APSIntType IntType = BV.getAPSIntType(Sym->getType());
+ llvm::APSInt Zero = IntType.getZeroValue();
+
+ // Check if zero is in the set of possible values.
+ if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty())
+ return false;
+
+ // Zero is a possible value, but it is not the /only/ possible value.
+ return ConditionTruthVal();
+}
+
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
ProgramStateRef
@@ -379,8 +387,18 @@ RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) {
// Lazily generate a new RangeSet representing all possible values for the
// given symbol type.
BasicValueFactory &BV = getBasicVals();
- QualType T = sym->getType(BV.getContext());
- return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
+ QualType T = sym->getType();
+
+ RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T));
+
+ // Special case: references are known to be non-zero.
+ if (T->isReferenceType()) {
+ APSIntType IntType = BV.getAPSIntType(T);
+ Result = Result.Intersect(BV, F, ++IntType.getZeroValue(),
+ --IntType.getZeroValue());
+ }
+
+ return Result;
}
//===------------------------------------------------------------------------===
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index bc4e4bbf602b..aed994df4110 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -15,9 +15,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/CXXInheritance.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
@@ -193,19 +190,6 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array);
- /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it.
- virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType);
-
- /// \brief Evaluates C++ dynamic_cast cast.
- /// The callback may result in the following 3 scenarios:
- /// - Successful cast (ex: derived is subclass of base).
- /// - Failed cast (ex: derived is definitely not a subclass of base).
- /// - We don't know (base is a symbolic region and we don't have
- /// enough info to determine if the cast will succeed at run time).
- /// The function returns an SVal representing the derived class; it's
- /// valid only if Failed flag is set to false.
- virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,bool &Failed);
-
StoreRef getInitialStore(const LocationContext *InitLoc) {
return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
}
@@ -244,7 +228,7 @@ public: // Made public for helper classes.
RegionBindings removeBinding(RegionBindings B, BindingKey K);
RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k);
+ BindingKey::Kind k);
RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
@@ -266,15 +250,20 @@ public: // Part of public interface to class.
.getRootWithoutRetain(), *this);
}
- StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL,
+ /// \brief Create a new store that binds a value to a compound literal.
+ ///
+ /// \param ST The original store whose bindings are the basis for the new
+ /// store.
+ ///
+ /// \param CL The compound literal to bind (the binding key).
+ ///
+ /// \param LC The LocationContext for the binding.
+ ///
+ /// \param V The value to bind to the compound literal.
+ StoreRef bindCompoundLiteral(Store ST,
+ const CompoundLiteralExpr *CL,
const LocationContext *LC, SVal V);
- StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal);
-
- StoreRef BindDeclWithNoInit(Store store, const VarRegion *) {
- return StoreRef(store, *this);
- }
-
/// BindStruct - Bind a compound value to a structure.
StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
@@ -287,7 +276,10 @@ public: // Part of public interface to class.
/// as a Default binding.
StoreRef BindAggregate(Store store, const TypedRegion *R, SVal DefaultVal);
- StoreRef Remove(Store store, Loc LV);
+ /// \brief Create a new store with the specified binding removed.
+ /// \param ST the original store, that is the basis for the new store.
+ /// \param L the location whose binding should be removed.
+ StoreRef killBinding(Store ST, Loc L);
void incrementReferenceCount(Store store) {
GetRegionBindings(store).manualRetain();
@@ -477,12 +469,8 @@ public:
}
bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
- if (C) {
- if (Visited.count(C))
- return false;
- Visited.insert(C);
- }
-
+ if (C && !Visited.insert(C))
+ return false;
WL.push_back(R);
return true;
}
@@ -534,6 +522,46 @@ bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R,
return true;
}
+static inline bool isUnionField(const FieldRegion *FR) {
+ return FR->getDecl()->getParent()->isUnion();
+}
+
+typedef SmallVector<const FieldDecl *, 8> FieldVector;
+
+void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields) {
+ assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
+
+ const MemRegion *Base = K.getConcreteOffsetRegion();
+ const MemRegion *R = K.getRegion();
+
+ while (R != Base) {
+ if (const FieldRegion *FR = dyn_cast<FieldRegion>(R))
+ if (!isUnionField(FR))
+ Fields.push_back(FR->getDecl());
+
+ R = cast<SubRegion>(R)->getSuperRegion();
+ }
+}
+
+static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields) {
+ assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
+
+ if (Fields.empty())
+ return true;
+
+ FieldVector FieldsInBindingKey;
+ getSymbolicOffsetFields(K, FieldsInBindingKey);
+
+ ptrdiff_t Delta = FieldsInBindingKey.size() - Fields.size();
+ if (Delta >= 0)
+ return std::equal(FieldsInBindingKey.begin() + Delta,
+ FieldsInBindingKey.end(),
+ Fields.begin());
+ else
+ return std::equal(FieldsInBindingKey.begin(), FieldsInBindingKey.end(),
+ Fields.begin() - Delta);
+}
+
RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
const SubRegion *R) {
BindingKey SRKey = BindingKey::Make(R, BindingKey::Default);
@@ -543,10 +571,12 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
return RBFactory.remove(B, R);
}
- if (SRKey.hasSymbolicOffset()) {
- const SubRegion *Base = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
- B = removeSubRegionBindings(B, Base);
- return addBinding(B, Base, BindingKey::Default, UnknownVal());
+ FieldVector FieldsInSymbolicSubregions;
+ bool HasSymbolicOffset = SRKey.hasSymbolicOffset();
+ if (HasSymbolicOffset) {
+ getSymbolicOffsetFields(SRKey, FieldsInSymbolicSubregions);
+ R = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
+ SRKey = BindingKey::Make(R, BindingKey::Default);
}
// This assumes the region being invalidated is char-aligned. This isn't
@@ -574,11 +604,17 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
I != E; ++I) {
BindingKey NextKey = I.getKey();
if (NextKey.getRegion() == SRKey.getRegion()) {
+ // FIXME: This doesn't catch the case where we're really invalidating a
+ // region with a symbolic offset. Example:
+ // R: points[i].y
+ // Next: points[0].x
+
if (NextKey.getOffset() > SRKey.getOffset() &&
NextKey.getOffset() - SRKey.getOffset() < Length) {
// Case 1: The next binding is inside the region we're invalidating.
// Remove it.
Result = CBFactory.remove(Result, NextKey);
+
} else if (NextKey.getOffset() == SRKey.getOffset()) {
// Case 2: The next binding is at the same offset as the region we're
// invalidating. In this case, we need to leave default bindings alone,
@@ -589,6 +625,7 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
if (NextKey.isDirect())
Result = CBFactory.remove(Result, NextKey);
}
+
} else if (NextKey.hasSymbolicOffset()) {
const MemRegion *Base = NextKey.getConcreteOffsetRegion();
if (R->isSubRegionOf(Base)) {
@@ -596,16 +633,24 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
// its concrete region. We don't know if the binding is still valid, so
// we'll be conservative and remove it.
if (NextKey.isDirect())
- Result = CBFactory.remove(Result, NextKey);
+ if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
+ Result = CBFactory.remove(Result, NextKey);
} else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) {
// Case 4: The next key is symbolic, but we changed a known
// super-region. In this case the binding is certainly no longer valid.
if (R == Base || BaseSR->isSubRegionOf(R))
- Result = CBFactory.remove(Result, NextKey);
+ if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
+ Result = CBFactory.remove(Result, NextKey);
}
}
}
+ // If we're invalidating a region with a symbolic offset, we need to make sure
+ // we don't treat the base region as uninitialized anymore.
+ // FIXME: This isn't very precise; see the example in the loop.
+ if (HasSymbolicOffset)
+ Result = CBFactory.add(Result, SRKey, UnknownVal());
+
if (Result.isEmpty())
return RBFactory.remove(B, ClusterHead);
return RBFactory.add(B, ClusterHead, Result);
@@ -724,7 +769,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
+ svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -739,8 +784,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (T->isStructureOrClassType()) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
+ DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
+ Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -748,7 +793,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
+ svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
AT->getElementType(), Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
@@ -764,8 +809,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
}
- DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
- T,Count);
+ DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
+ T,Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
B = RM.addBinding(B, baseR, BindingKey::Direct, V);
}
@@ -779,10 +824,9 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
// Bind the globals memory space to a new symbol that we will use to derive
// the bindings for all globals.
const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K);
- SVal V =
- svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, LCtx,
- /* symbol type, doesn't matter */ Ctx.IntTy,
- Count);
+ SVal V = svalBuilder.conjureSymbolVal(/* SymbolTag = */ (const void*) GS, Ex, LCtx,
+ /* type does not matter */ Ctx.IntTy,
+ Count);
B = removeBinding(B, GS);
B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
@@ -897,103 +941,6 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx));
}
-// This mirrors Type::getCXXRecordDeclForPointerType(), but there doesn't
-// appear to be another need for this in the rest of the codebase.
-static const CXXRecordDecl *GetCXXRecordDeclForReferenceType(QualType Ty) {
- if (const ReferenceType *RT = Ty->getAs<ReferenceType>())
- if (const RecordType *RCT = RT->getPointeeType()->getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(RCT->getDecl());
- return 0;
-}
-
-SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
- const CXXRecordDecl *baseDecl;
-
- if (baseType->isPointerType())
- baseDecl = baseType->getCXXRecordDeclForPointerType();
- else if (baseType->isReferenceType())
- baseDecl = GetCXXRecordDeclForReferenceType(baseType);
- else
- baseDecl = baseType->getAsCXXRecordDecl();
-
- assert(baseDecl && "not a CXXRecordDecl?");
-
- loc::MemRegionVal *derivedRegVal = dyn_cast<loc::MemRegionVal>(&derived);
- if (!derivedRegVal)
- return derived;
-
- const MemRegion *baseReg =
- MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
-
- return loc::MemRegionVal(baseReg);
-}
-
-SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType,
- bool &Failed) {
- Failed = false;
-
- loc::MemRegionVal *baseRegVal = dyn_cast<loc::MemRegionVal>(&base);
- if (!baseRegVal)
- return UnknownVal();
- const MemRegion *BaseRegion = baseRegVal->stripCasts(/*StripBases=*/false);
-
- // Assume the derived class is a pointer or a reference to a CXX record.
- derivedType = derivedType->getPointeeType();
- assert(!derivedType.isNull());
- const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl();
- if (!DerivedDecl && !derivedType->isVoidType())
- return UnknownVal();
-
- // Drill down the CXXBaseObject chains, which represent upcasts (casts from
- // derived to base).
- const MemRegion *SR = BaseRegion;
- while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) {
- QualType BaseType = TSR->getLocationType()->getPointeeType();
- assert(!BaseType.isNull());
- const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl();
- if (!SRDecl)
- return UnknownVal();
-
- // If found the derived class, the cast succeeds.
- if (SRDecl == DerivedDecl)
- return loc::MemRegionVal(TSR);
-
- if (!derivedType->isVoidType()) {
- // 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,
- /*DetectVirtual=*/false);
- if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) {
- SVal Result = loc::MemRegionVal(TSR);
- const CXXBasePath &Path = *Paths.begin();
- for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
- I != E; ++I) {
- Result = evalDerivedToBase(Result, I->Base->getType());
- }
- return Result;
- }
- }
-
- if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR))
- // Drill down the chain to get the derived classes.
- SR = R->getSuperRegion();
- else {
- // We reached the bottom of the hierarchy.
-
- // If this is a cast to void*, return the region.
- if (derivedType->isVoidType())
- return loc::MemRegionVal(TSR);
-
- // We did not find the derived class. We we must be casting the base to
- // derived, so the cast should fail.
- Failed = true;
- return UnknownVal();
- }
- }
-
- return UnknownVal();
-}
-
//===----------------------------------------------------------------------===//
// Loading values from regions.
//===----------------------------------------------------------------------===//
@@ -1047,7 +994,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
T = TR->getLocationType();
else {
const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
- T = SR->getSymbol()->getType(Ctx);
+ T = SR->getSymbol()->getType();
}
}
MR = GetElementZeroRegion(MR, T);
@@ -1540,14 +1487,14 @@ bool RegionStoreManager::includedInBindings(Store store,
// Binding values to regions.
//===----------------------------------------------------------------------===//
-StoreRef RegionStoreManager::Remove(Store store, Loc L) {
+StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {
if (isa<loc::MemRegionVal>(L))
if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
- return StoreRef(removeBinding(GetRegionBindings(store),
+ return StoreRef(removeBinding(GetRegionBindings(ST),
R).getRootWithoutRetain(),
*this);
- return StoreRef(store, *this);
+ return StoreRef(ST, *this);
}
StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
@@ -1560,6 +1507,8 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
// Check if the region is a struct region.
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
QualType Ty = TR->getValueType();
+ if (Ty->isArrayType())
+ return BindArray(store, TR, V);
if (Ty->isStructureOrClassType())
return BindStruct(store, TR, V);
if (Ty->isVectorType())
@@ -1569,13 +1518,9 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
// Binding directly to a symbolic region should be treated as binding
// to element 0.
- QualType T = SR->getSymbol()->getType(Ctx);
-
- // FIXME: Is this the right way to handle symbols that are references?
- if (const PointerType *PT = T->getAs<PointerType>())
- T = PT->getPointeeType();
- else
- T = T->getAs<ReferenceType>()->getPointeeType();
+ QualType T = SR->getSymbol()->getType();
+ if (T->isAnyPointerType() || T->isReferenceType())
+ T = T->getPointeeType();
R = GetElementZeroRegion(SR, T);
}
@@ -1589,26 +1534,12 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
return StoreRef(addBinding(B, Key, V).getRootWithoutRetain(), *this);
}
-StoreRef RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
- SVal InitVal) {
-
- QualType T = VR->getDecl()->getType();
-
- if (T->isArrayType())
- return BindArray(store, VR, InitVal);
- if (T->isStructureOrClassType())
- return BindStruct(store, VR, InitVal);
-
- return Bind(store, svalBuilder.makeLoc(VR), InitVal);
-}
-
// FIXME: this method should be merged into Bind().
-StoreRef RegionStoreManager::BindCompoundLiteral(Store store,
+StoreRef RegionStoreManager::bindCompoundLiteral(Store ST,
const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) {
- return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
- V);
+ return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V);
}
StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
@@ -1864,7 +1795,7 @@ RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
const MemRegion *R,
- BindingKey::Kind k){
+ BindingKey::Kind k){
return removeBinding(B, BindingKey::Make(R, k));
}
@@ -1897,7 +1828,6 @@ public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBindingKey(BindingKey K);
bool UpdatePostponed();
void VisitBinding(SVal V);
};
@@ -1932,17 +1862,21 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
const StackArgumentsSpaceRegion *StackReg =
cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
const StackFrameContext *RegCtx = StackReg->getStackFrame();
- if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))
+ if (CurrentLCtx &&
+ (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx)))
AddToWorkList(TR, &C);
}
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) {
- VisitBindingKey(I.getKey());
+ // Mark the symbol for any SymbolicRegion with live bindings as live itself.
+ // This means we should continue to track that symbol.
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
+ SymReaper.markLive(SymR->getSymbol());
+
+ for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
VisitBinding(I.getData());
- }
}
void removeDeadBindingsWorker::VisitBinding(SVal V) {
@@ -1979,8 +1913,8 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
E = BR->referenced_vars_end();
- for ( ; I != E; ++I)
- AddToWorkList(I.getCapturedRegion());
+ for ( ; I != E; ++I)
+ AddToWorkList(I.getCapturedRegion());
}
}
@@ -1991,20 +1925,6 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
SymReaper.markLive(*SI);
}
-void removeDeadBindingsWorker::VisitBindingKey(BindingKey K) {
- const MemRegion *R = K.getRegion();
-
- // Mark this region "live" by adding it to the worklist. This will cause
- // use to visit all regions in the cluster (if we haven't visited them
- // already).
- if (AddToWorkList(R)) {
- // Mark the symbol for any live SymbolicRegion as "live". This means we
- // should continue to track that symbol.
- if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
- SymReaper.markLive(SymR->getSymbol());
- }
-}
-
bool removeDeadBindingsWorker::UpdatePostponed() {
// See if any postponed SymbolicRegions are actually live now, after
// having done a scan.
@@ -2012,7 +1932,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
for (SmallVectorImpl<const SymbolicRegion*>::iterator
I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) {
- if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) {
+ if (const SymbolicRegion *SR = *I) {
if (SymReaper.isLive(SR->getSymbol())) {
changed |= AddToWorkList(SR);
*I = NULL;
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index d1936cd3603e..b87169a4b335 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -106,25 +106,23 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- unsigned count) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count) {
QualType T = expr->getType();
- return getConjuredSymbolVal(symbolTag, expr, LCtx, T, count);
+ return conjureSymbolVal(symbolTag, expr, LCtx, T, count);
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- QualType type,
- unsigned count) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned count) {
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(expr, LCtx, type, count, symbolTag);
+ SymbolRef sym = SymMgr.conjureSymbol(expr, LCtx, type, count, symbolTag);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -133,15 +131,14 @@ SValBuilder::getConjuredSymbolVal(const void *symbolTag,
}
-DefinedOrUnknownSVal
-SValBuilder::getConjuredSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount) {
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -157,7 +154,7 @@ SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
assert(Loc::isLocType(T));
assert(SymbolManager::canSymbolicate(T));
- SymbolRef sym = SymMgr.getConjuredSymbol(E, LCtx, T, VisitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount);
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
}
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 8437f50f911f..e34ab6a2be91 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -51,7 +51,8 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion* R = X->getRegion();
if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
- return CTR->getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
+ return FD;
}
return 0;
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 5568f1ca555d..4236ee470af4 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -67,7 +67,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
- return SU.processAssume(state, cond, assumption);
+ if (NotifyAssumeClients && SU)
+ return SU->processAssume(state, cond, assumption);
+ return state;
}
ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
@@ -113,7 +115,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
NonLoc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
- return SU.processAssume(state, cond, assumption);
+ if (NotifyAssumeClients && SU)
+ return SU->processAssume(state, cond, assumption);
+ return state;
}
static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
@@ -136,7 +140,7 @@ ProgramStateRef
SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
SymbolRef Sym, bool Assumption) {
BasicValueFactory &BVF = getBasicVals();
- QualType T = Sym->getType(BVF.getContext());
+ QualType T = Sym->getType();
// None of the constraint solvers currently support non-integer types.
if (!T->isIntegerType())
@@ -186,7 +190,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
BinaryOperator::Opcode op = SE->getOpcode();
// Implicitly compare non-comparison expressions to 0.
if (!BinaryOperator::isComparisonOp(op)) {
- QualType T = SE->getType(BasicVals.getContext());
+ QualType T = SE->getType();
const llvm::APSInt &zero = BasicVals.getValue(0, T);
op = (Assumption ? BO_NE : BO_EQ);
return assumeSymRel(state, SE, op, zero);
@@ -235,11 +239,9 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state,
assert(BinaryOperator::isComparisonOp(op) &&
"Non-comparison ops should be rewritten as comparisons to zero.");
- BasicValueFactory &BVF = getBasicVals();
- ASTContext &Ctx = BVF.getContext();
-
// Get the type used for calculating wraparound.
- APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType(Ctx));
+ BasicValueFactory &BVF = getBasicVals();
+ APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType());
// We only handle simple comparisons of the form "$sym == constant"
// or "($sym+constant1) == constant2".
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 088d70c2717f..01f0b4e4461f 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -22,10 +22,10 @@ namespace clang {
namespace ento {
class SimpleConstraintManager : public ConstraintManager {
- SubEngine &SU;
+ SubEngine *SU;
BasicValueFactory &BVF;
public:
- SimpleConstraintManager(SubEngine &subengine, BasicValueFactory &BV)
+ SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV)
: SU(subengine), BVF(BV) {}
virtual ~SimpleConstraintManager();
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index ad58a07c784e..fbc6ba055105 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -81,7 +81,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
}
if (const SymExpr *se = val.getAsSymbolicExpression()) {
- QualType T = Context.getCanonicalType(se->getType(Context));
+ QualType T = Context.getCanonicalType(se->getType());
// If types are the same or both are integers, ignore the cast.
// FIXME: Remove this hack when we support symbolic truncation/extension.
// HACK: If both castTy and T are integers, ignore the cast. This is
@@ -276,7 +276,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
// with the given constant.
// FIXME: This is an approximation of Sema::UsualArithmeticConversions.
ASTContext &Ctx = getContext();
- QualType SymbolType = LHS->getType(Ctx);
+ QualType SymbolType = LHS->getType();
uint64_t ValWidth = RHS.getBitWidth();
uint64_t TypeWidth = Ctx.getTypeSize(SymbolType);
@@ -318,7 +318,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
return makeTruthVal(false, resultTy);
case BO_Xor:
case BO_Sub:
- return makeIntVal(0, resultTy);
+ if (resultTy->isIntegralOrEnumerationType())
+ return makeIntVal(0, resultTy);
+ return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy);
case BO_Or:
case BO_And:
return evalCastFromNonLoc(lhs, resultTy);
@@ -459,7 +461,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_NE:
// Negate the comparison and make a value.
opc = NegateComparison(opc);
- assert(symIntExpr->getType(Context) == resultTy);
+ assert(symIntExpr->getType() == resultTy);
return makeNonLoc(symIntExpr->getLHS(), opc,
symIntExpr->getRHS(), resultTy);
}
@@ -505,7 +507,8 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
} else if (isa<SymbolData>(Sym)) {
// Does the symbol simplify to a constant? If so, "fold" the constant
// by setting 'lhs' to a ConcreteInt and try again.
- if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
+ if (const llvm::APSInt *Constant = state->getConstraintManager()
+ .getSymVal(state, Sym)) {
lhs = nonloc::ConcreteInt(*Constant);
continue;
}
@@ -916,14 +919,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
else if (isa<SubRegion>(region)) {
superR = region;
index = rhs;
- if (const PointerType *PT = resultTy->getAs<PointerType>()) {
- elementType = PT->getPointeeType();
- }
- else {
- const ObjCObjectPointerType *OT =
- resultTy->getAs<ObjCObjectPointerType>();
- elementType = OT->getPointeeType();
- }
+ if (resultTy->isAnyPointerType())
+ elementType = resultTy->getPointeeType();
}
if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) {
@@ -946,7 +943,7 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
return &X->getValue();
if (SymbolRef Sym = V.getAsSymbol())
- return state->getSymVal(Sym);
+ return state->getConstraintManager().getSymVal(state, Sym);
// FIXME: Add support for SymExprs.
return NULL;
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 3af60a170727..939ae54dad74 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
using namespace clang;
@@ -233,6 +234,91 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
return Result;
}
+SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) {
+ // Walk through the path to create nested CXXBaseRegions.
+ SVal Result = Derived;
+ for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
+ I != E; ++I) {
+ Result = evalDerivedToBase(Result, I->Base->getType());
+ }
+ return Result;
+}
+
+SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
+ loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived);
+ if (!DerivedRegVal)
+ return Derived;
+
+ const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl();
+ if (!BaseDecl)
+ BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "not a C++ object?");
+
+ const MemRegion *BaseReg =
+ MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());
+
+ return loc::MemRegionVal(BaseReg);
+}
+
+SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType,
+ bool &Failed) {
+ Failed = false;
+
+ loc::MemRegionVal *BaseRegVal = dyn_cast<loc::MemRegionVal>(&Base);
+ if (!BaseRegVal)
+ return UnknownVal();
+ const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false);
+
+ // Assume the derived class is a pointer or a reference to a CXX record.
+ DerivedType = DerivedType->getPointeeType();
+ assert(!DerivedType.isNull());
+ const CXXRecordDecl *DerivedDecl = DerivedType->getAsCXXRecordDecl();
+ if (!DerivedDecl && !DerivedType->isVoidType())
+ return UnknownVal();
+
+ // Drill down the CXXBaseObject chains, which represent upcasts (casts from
+ // derived to base).
+ const MemRegion *SR = BaseRegion;
+ while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) {
+ QualType BaseType = TSR->getLocationType()->getPointeeType();
+ assert(!BaseType.isNull());
+ const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl();
+ if (!SRDecl)
+ return UnknownVal();
+
+ // If found the derived class, the cast succeeds.
+ if (SRDecl == DerivedDecl)
+ return loc::MemRegionVal(TSR);
+
+ if (!DerivedType->isVoidType()) {
+ // 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,
+ /*DetectVirtual=*/false);
+ if (SRDecl->isDerivedFrom(DerivedDecl, Paths))
+ return evalDerivedToBase(loc::MemRegionVal(TSR), Paths.front());
+ }
+
+ if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR))
+ // Drill down the chain to get the derived classes.
+ SR = R->getSuperRegion();
+ else {
+ // We reached the bottom of the hierarchy.
+
+ // If this is a cast to void*, return the region.
+ if (DerivedType->isVoidType())
+ return loc::MemRegionVal(TSR);
+
+ // We did not find the derived class. We we must be casting the base to
+ // derived, so the cast should fail.
+ Failed = true;
+ return UnknownVal();
+ }
+ }
+
+ return UnknownVal();
+}
+
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 0bc192d64571..0c5098b1e7d0 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -117,21 +117,17 @@ bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
itr.push_back(SE);
- while (!isa<SymbolData>(itr.back())) expand();
}
SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
- assert(isa<SymbolData>(itr.back()));
- itr.pop_back();
- if (!itr.empty())
- while (!isa<SymbolData>(itr.back())) expand();
+ expand();
return *this;
}
SymbolRef SymExpr::symbol_iterator::operator*() {
assert(!itr.empty() && "attempting to dereference an 'end' iterator");
- return cast<SymbolData>(itr.back());
+ return itr.back();
}
void SymExpr::symbol_iterator::expand() {
@@ -187,11 +183,11 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
return cast<SymbolRegionValue>(SD);
}
-const SymbolConjured*
-SymbolManager::getConjuredSymbol(const Stmt *E, const LocationContext *LCtx,
- QualType T, unsigned Count,
- const void *SymbolTag) {
-
+const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
+ unsigned Count,
+ const void *SymbolTag) {
llvm::FoldingSetNodeID profile;
SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
void *InsertPos;
@@ -328,23 +324,24 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
return cast<SymSymExpr>(data);
}
-QualType SymbolConjured::getType(ASTContext&) const {
+QualType SymbolConjured::getType() const {
return T;
}
-QualType SymbolDerived::getType(ASTContext &Ctx) const {
+QualType SymbolDerived::getType() const {
return R->getValueType();
}
-QualType SymbolExtent::getType(ASTContext &Ctx) const {
+QualType SymbolExtent::getType() const {
+ ASTContext &Ctx = R->getMemRegionManager()->getContext();
return Ctx.getSizeType();
}
-QualType SymbolMetadata::getType(ASTContext&) const {
+QualType SymbolMetadata::getType() const {
return T;
}
-QualType SymbolRegionValue::getType(ASTContext &C) const {
+QualType SymbolRegionValue::getType() const {
return R->getValueType();
}
@@ -466,41 +463,56 @@ bool SymbolReaper::isLive(SymbolRef sym) {
markDependentsLive(sym);
return true;
}
-
- if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
- if (isLive(derived->getParentSymbol())) {
- markLive(sym);
- return true;
- }
- return false;
- }
-
- if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
- if (isLiveRegion(extent->getRegion())) {
- markLive(sym);
- return true;
- }
- return false;
+
+ bool KnownLive;
+
+ switch (sym->getKind()) {
+ case SymExpr::RegionValueKind:
+ // FIXME: We should be able to use isLiveRegion here (this behavior
+ // predates isLiveRegion), but doing so causes test failures. Investigate.
+ KnownLive = true;
+ break;
+ case SymExpr::ConjuredKind:
+ KnownLive = false;
+ break;
+ case SymExpr::DerivedKind:
+ KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
+ break;
+ case SymExpr::ExtentKind:
+ KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
+ break;
+ case SymExpr::MetadataKind:
+ KnownLive = MetadataInUse.count(sym) &&
+ isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
+ if (KnownLive)
+ MetadataInUse.erase(sym);
+ break;
+ case SymExpr::SymIntKind:
+ KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
+ break;
+ case SymExpr::IntSymKind:
+ KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
+ break;
+ case SymExpr::SymSymKind:
+ KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
+ isLive(cast<SymSymExpr>(sym)->getRHS());
+ break;
+ case SymExpr::CastSymbolKind:
+ KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
+ break;
}
- if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
- if (MetadataInUse.count(sym)) {
- if (isLiveRegion(metadata->getRegion())) {
- markLive(sym);
- MetadataInUse.erase(sym);
- return true;
- }
- }
- return false;
- }
+ if (KnownLive)
+ markLive(sym);
- // Interogate the symbol. It may derive from an input value to
- // the analyzed function/method.
- return isa<SymbolRegionValue>(sym);
+ return KnownLive;
}
bool
SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
+ if (LCtx == 0)
+ return false;
+
if (LCtx != ELCtx) {
// If the reaper's location context is a parent of the expression's
// location context, then the expression value is now "out of scope".
@@ -508,6 +520,7 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
return false;
return true;
}
+
// If no statement is provided, everything is this and parent contexts is live.
if (!Loc)
return true;
@@ -517,10 +530,16 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
const StackFrameContext *VarContext = VR->getStackFrame();
+
+ if (!VarContext)
+ return true;
+
+ if (!LCtx)
+ return false;
const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
if (VarContext == CurrentContext) {
- // If no statemetnt is provided, everything is live.
+ // If no statement is provided, everything is live.
if (!Loc)
return true;
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index 66bf4bb222d1..e09f4e365344 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -41,7 +41,6 @@ public:
PathGenerationScheme getGenerationScheme() const { return Minimal; }
bool supportsLogicalOpControlFlow() const { return true; }
bool supportsAllBlockEdges() const { return true; }
- virtual bool useVerboseDescription() const { return true; }
virtual bool supportsCrossFileDiagnostics() const { return true; }
};
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 34b5266e4b76..7dbac3cf93a0 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -34,7 +34,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
@@ -78,7 +78,6 @@ public:
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {}
virtual ~ClangDiagPathDiagConsumer() {}
virtual StringRef getName() const { return "ClangDiags"; }
- virtual bool useVerboseDescription() const { return false; }
virtual PathGenerationScheme getGenerationScheme() const { return None; }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
@@ -86,7 +85,7 @@ public:
for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
E = Diags.end(); I != E; ++I) {
const PathDiagnostic *PD = *I;
- StringRef desc = PD->getDescription();
+ StringRef desc = PD->getShortDescription();
SmallString<512> TmpStr;
llvm::raw_svector_ostream Out(TmpStr);
for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) {
@@ -121,11 +120,12 @@ namespace {
class AnalysisConsumer : public ASTConsumer,
public RecursiveASTVisitor<AnalysisConsumer> {
- enum AnalysisMode {
- ANALYSIS_SYNTAX,
- ANALYSIS_PATH,
- ANALYSIS_ALL
+ enum {
+ AM_None = 0,
+ AM_Syntax = 0x1,
+ AM_Path = 0x2
};
+ typedef unsigned AnalysisMode;
/// Mode of the analyzes while recursively visiting Decls.
AnalysisMode RecVisitorMode;
@@ -136,7 +136,7 @@ public:
ASTContext *Ctx;
const Preprocessor &PP;
const std::string OutDir;
- AnalyzerOptions Opts;
+ AnalyzerOptionsRef Opts;
ArrayRef<std::string> Plugins;
/// \brief Stores the declarations from the local translation unit.
@@ -164,19 +164,19 @@ public:
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins)
- : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
+ : RecVisitorMode(0), RecVisitorBR(0),
Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
DigestAnalyzerOptions();
- if (Opts.PrintStats) {
+ if (Opts->PrintStats) {
llvm::EnableStatistics();
TUTotalTimer = new llvm::Timer("Analyzer Total Time");
}
}
~AnalysisConsumer() {
- if (Opts.PrintStats)
+ if (Opts->PrintStats)
delete TUTotalTimer;
}
@@ -185,49 +185,52 @@ public:
PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics()));
if (!OutDir.empty()) {
- switch (Opts.AnalysisDiagOpt) {
+ switch (Opts->AnalysisDiagOpt) {
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
- } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
+ } else if (Opts->AnalysisDiagOpt == PD_TEXT) {
// Create the text client even without a specified output file since
// it just uses diagnostic notes.
createTextPathDiagnosticConsumer(PathConsumers, "", PP);
}
// Create the analyzer component creators.
- switch (Opts.AnalysisStoreOpt) {
+ switch (Opts->AnalysisStoreOpt) {
default:
llvm_unreachable("Unknown store manager.");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateStoreMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
- switch (Opts.AnalysisConstraintsOpt) {
+ switch (Opts->AnalysisConstraintsOpt) {
default:
llvm_unreachable("Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
+#include "clang/StaticAnalyzer/Core/Analyses.def"
}
}
void DisplayFunction(const Decl *D, AnalysisMode Mode) {
- if (!Opts.AnalyzerDisplayProgress)
+ if (!Opts->AnalyzerDisplayProgress)
return;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
if (Loc.isValid()) {
llvm::errs() << "ANALYZE";
- switch (Mode) {
- case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
- case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
- case ANALYSIS_ALL: break;
- };
+
+ if (Mode == AM_Syntax)
+ llvm::errs() << " (Syntax)";
+ else if (Mode == AM_Path)
+ llvm::errs() << " (Path)";
+ else
+ assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
+
llvm::errs() << ": " << Loc.getFilename();
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
@@ -246,7 +249,7 @@ public:
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
+ checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
PP.getDiagnostics()));
Mgr.reset(new AnalysisManager(*Ctx,
PP.getDiagnostics(),
@@ -255,17 +258,7 @@ public:
CreateStoreMgr,
CreateConstraintMgr,
checkerMgr.get(),
- Opts.MaxNodes, Opts.MaxLoop,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
- Opts.TrimGraph,
- Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
- Opts.EagerlyTrimEGraph,
- Opts.IPAMode,
- Opts.InlineMaxStackDepth,
- Opts.InlineMaxFunctionSize,
- Opts.InliningMode,
- Opts.NoRetryExhausted));
+ *Opts));
}
/// \brief Store the top level decls in the set to be processed later on.
@@ -277,7 +270,7 @@ public:
/// \brief Build the call graph for all the top level decls of this TU and
/// use it to define the order in which the functions should be visited.
- void HandleDeclsGallGraph(const unsigned LocalTUDeclsSize);
+ void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
/// \brief Run analyzes(syntax or path sensitive) on the given function.
/// \param Mode - determines if we are requesting syntax only or path
@@ -297,7 +290,9 @@ public:
/// Handle callbacks for arbitrary Decls.
bool VisitDecl(Decl *D) {
- checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
+ AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);
+ if (Mode & AM_Syntax)
+ checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
return true;
}
@@ -316,7 +311,6 @@ public:
}
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
if (MD->isThisDeclarationADefinition())
HandleCode(MD, RecVisitorMode);
return true;
@@ -326,7 +320,7 @@ private:
void storeTopLevelDecls(DeclGroupRef DG);
/// \brief Check if we should skip (not analyze) the given function.
- bool skipFunction(Decl *D);
+ AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
};
} // end anonymous namespace
@@ -358,7 +352,23 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
}
-void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
+static bool shouldSkipFunction(CallGraphNode *N,
+ SmallPtrSet<CallGraphNode*,24> Visited) {
+ // We want to re-analyse the functions as top level in several cases:
+ // - The 'init' methods should be reanalyzed because
+ // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns
+ // 'nil' and unless we analyze the 'init' functions as top level, we will not
+ // catch errors within defensive code.
+ // - We want to reanalyze all ObjC methods as top level to report Retain
+ // Count naming convention errors more aggressively.
+ if (isa<ObjCMethodDecl>(N->getDecl()))
+ return false;
+
+ // Otherwise, if we visited the function before, do not reanalyze it.
+ return Visited.count(N);
+}
+
+void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
// Otherwise, use the Callgraph to derive the order.
// Build the Call Graph.
CallGraph CG;
@@ -407,21 +417,21 @@ void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) {
// Push the children into the queue.
for (CallGraphNode::const_iterator CI = N->begin(),
CE = N->end(); CI != CE; ++CI) {
- if (!Visited.count(*CI))
+ if (!shouldSkipFunction(*CI, Visited))
BFSQueue.push_back(*CI);
}
// Skip the functions which have been processed already or previously
// inlined.
- if (Visited.count(N))
+ if (shouldSkipFunction(N, Visited))
continue;
// Analyze the function.
SetOfConstDecls VisitedCallees;
Decl *D = N->getDecl();
assert(D);
- HandleCode(D, ANALYSIS_PATH,
- (Mgr->InliningMode == All ? 0 : &VisitedCallees));
+ HandleCode(D, AM_Path,
+ (Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
@@ -451,7 +461,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// Run the AST-only checks using the order in which functions are defined.
// If inlining is not turned on, use the simplest function order for path
// sensitive analyzes as well.
- RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
+ RecVisitorMode = AM_Syntax;
+ if (!Mgr->shouldInlineCall())
+ RecVisitorMode |= AM_Path;
RecVisitorBR = &BR;
// Process all the top level declarations.
@@ -466,7 +478,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
}
if (Mgr->shouldInlineCall())
- HandleDeclsGallGraph(LocalTUDeclsSize);
+ HandleDeclsCallGraph(LocalTUDeclsSize);
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
@@ -513,24 +525,32 @@ static std::string getFunctionName(const Decl *D) {
return "";
}
-bool AnalysisConsumer::skipFunction(Decl *D) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- getFunctionName(D) != Opts.AnalyzeSpecificFunction)
- return true;
-
- // Don't run the actions on declarations in header files unless
- // otherwise specified.
+AnalysisConsumer::AnalysisMode
+AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
+ if (!Opts->AnalyzeSpecificFunction.empty() &&
+ getFunctionName(D) != Opts->AnalyzeSpecificFunction)
+ return AM_None;
+
+ // Unless -analyze-all is specified, treat decls differently depending on
+ // where they came from:
+ // - Main source file: run both path-sensitive and non-path-sensitive checks.
+ // - Header files: run non-path-sensitive checks only.
+ // - System headers: don't run any checks.
SourceManager &SM = Ctx->getSourceManager();
SourceLocation SL = SM.getExpansionLoc(D->getLocation());
- if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
- return true;
+ if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) {
+ if (SL.isInvalid() || SM.isInSystemHeader(SL))
+ return AM_None;
+ return Mode & ~AM_Path;
+ }
- return false;
+ return Mode;
}
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
SetOfConstDecls *VisitedCallees) {
- if (skipFunction(D))
+ Mode = getModeForDecl(D, Mode);
+ if (Mode == AM_None)
return;
DisplayFunction(D, Mode);
@@ -548,16 +568,16 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
SmallVector<Decl*, 10> WL;
WL.push_back(D);
- if (D->hasBody() && Opts.AnalyzeNestedBlocks)
+ if (D->hasBody() && Opts->AnalyzeNestedBlocks)
FindBlocks(cast<DeclContext>(D), WL);
BugReporter BR(*Mgr);
for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
if ((*WI)->hasBody()) {
- if (Mode != ANALYSIS_PATH)
+ if (Mode & AM_Syntax)
checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
+ if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
RunPathSensitiveChecks(*WI, VisitedCallees);
NumFunctionsAnalyzed++;
}
@@ -583,22 +603,22 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Set the graph auditor.
OwningPtr<ExplodedNode::Auditor> Auditor;
- if (Mgr->shouldVisualizeUbigraph()) {
+ if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
Auditor.reset(CreateUbiViz());
ExplodedNode::SetAuditor(Auditor.get());
}
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
- Mgr->getMaxNodes());
+ Mgr->options.MaxNodes);
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
ExplodedNode::SetAuditor(0);
// Visualize the exploded graph.
- if (Mgr->shouldVisualizeGraphviz())
- Eng.ViewGraph(Mgr->shouldTrimGraph());
+ if (Mgr->options.visualizeExplodedGraphWithGraphViz)
+ Eng.ViewGraph(Mgr->options.TrimGraph);
// Display warnings.
Eng.getBugReporter().FlushReports();
@@ -629,7 +649,7 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
const std::string& outDir,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
pp.getDiagnostics().setWarningsAsErrors(false);
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
index 5a16bffeacf3..b75220b62de3 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -16,11 +16,11 @@
#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include <string>
namespace clang {
-class AnalyzerOptions;
class ASTConsumer;
class Preprocessor;
class DiagnosticsEngine;
@@ -33,7 +33,7 @@ class CheckerManager;
/// options.)
ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
const std::string &output,
- const AnalyzerOptions& opts,
+ AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins);
} // end GR namespace
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index 06d148507874..aafb249c587f 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -25,6 +25,7 @@ target_link_libraries(clangStaticAnalyzerFrontend
clangLex
clangAST
clangFrontend
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangStaticAnalyzerCheckers
)
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 0229aed6bdaa..e8daa65e410a 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -17,7 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
-#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/DynamicLibrary.h"
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 49d3101f0e99..d29e564e34fe 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -2,8 +2,10 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTooling
ArgumentsAdjusters.cpp
- CommandLineClangTool.cpp
+ CommonOptionsParser.cpp
CompilationDatabase.cpp
+ FileMatchTrie.cpp
+ JSONCompilationDatabase.cpp
Refactoring.cpp
RefactoringCallbacks.cpp
Tooling.cpp
@@ -23,5 +25,6 @@ target_link_libraries(clangTooling
clangFrontend
clangAST
clangASTMatchers
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
)
diff --git a/lib/Tooling/CommandLineClangTool.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 8da2a335a557..15091c7e901e 100644
--- a/lib/Tooling/CommandLineClangTool.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -1,4 +1,4 @@
-//===--- CommandLineClangTool.cpp - command-line clang tools driver -------===//
+//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,28 +7,31 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the CommandLineClangTool class used to run clang
-// tools as separate command-line applications with a consistent common
-// interface for handling compilation database and input files.
+// This file implements the CommonOptionsParser class used to parse common
+// command-line options for clang tools, so that they can be run as separate
+// command-line applications with a consistent common interface for handling
+// compilation database and input files.
//
// It provides a common subset of command-line options, common algorithm
// for locating a compilation database and source files, and help messages
// for the basic command-line interface.
//
-// It creates a CompilationDatabase, initializes a ClangTool and runs a
-// user-specified FrontendAction over all TUs in which the given files are
-// compiled.
+// It creates a CompilationDatabase and reads common command-line options.
+//
+// This class uses the Clang Tooling infrastructure, see
+// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CommandLineClangTool.h"
+#include "llvm/Support/CommandLine.h"
+#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
-static const char *MoreHelpText =
+const char *const CommonOptionsParser::HelpMessage =
"\n"
"-p <build-path> is used to read a compile command database.\n"
"\n"
@@ -40,26 +43,27 @@ static const char *MoreHelpText =
"\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
"\texample of setting up Clang Tooling on a source tree.\n"
"\n"
- "<source0> ... specify the paths of source files. These paths are looked\n"
- "\tup in the compile command database. If the path of a file is absolute,\n"
- "\tit needs to point into CMake's source tree. If the path is relative,\n"
- "\tthe current working directory needs to be in the CMake source tree and\n"
- "\tthe file must be in a subdirectory of the current working directory.\n"
- "\t\"./\" prefixes in the relative files will be automatically removed,\n"
- "\tbut the rest of a relative path must be a suffix of a path in the\n"
- "\tcompile command database.\n"
+ "<source0> ... specify the paths of source files. These paths are\n"
+ "\tlooked up in the compile command database. If the path of a file is\n"
+ "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
+ "\trelative, the current working directory needs to be in the CMake\n"
+ "\tsource tree and the file must be in a subdirectory of the current\n"
+ "\tworking directory. \"./\" prefixes in the relative files will be\n"
+ "\tautomatically removed, but the rest of a relative path must be a\n"
+ "\tsuffix of a path in the compile command database.\n"
"\n";
-CommandLineClangTool::CommandLineClangTool() :
- BuildPath("p", cl::desc("Build path"), cl::Optional),
- SourcePaths(cl::Positional, cl::desc("<source0> [... <sourceN>]"),
- cl::OneOrMore),
- MoreHelp(MoreHelpText) {
-}
+CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) {
+ static cl::opt<std::string> BuildPath(
+ "p", cl::desc("Build path"), cl::Optional);
+
+ static cl::list<std::string> SourcePaths(
+ cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore);
-void CommandLineClangTool::initialize(int argc, const char **argv) {
- Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
+ argv));
cl::ParseCommandLineOptions(argc, argv);
+ SourcePathList = SourcePaths;
if (!Compilations) {
std::string ErrorMessage;
if (!BuildPath.empty()) {
@@ -73,8 +77,3 @@ void CommandLineClangTool::initialize(int argc, const char **argv) {
llvm::report_fatal_error(ErrorMessage);
}
}
-
-int CommandLineClangTool::run(FrontendActionFactory *ActionFactory) {
- ClangTool Tool(*Compilations, SourcePaths);
- return Tool.run(ActionFactory);
-}
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 3139cc21bb8d..4149cda3787c 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -7,132 +7,49 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains multiple implementations for CompilationDatabases.
+// This file contains implementations of the CompilationDatabase base class
+// and the FixedCompilationDatabase.
//
//===----------------------------------------------------------------------===//
+#include <sstream>
#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
-#ifdef USE_CUSTOM_COMPILATION_DATABASE
-#include "CustomCompilationDatabase.h"
-#endif
-
namespace clang {
namespace tooling {
-namespace {
-
-/// \brief A parser for escaped strings of command line arguments.
-///
-/// Assumes \-escaping for quoted arguments (see the documentation of
-/// unescapeCommandLine(...)).
-class CommandLineArgumentParser {
- public:
- CommandLineArgumentParser(StringRef CommandLine)
- : Input(CommandLine), Position(Input.begin()-1) {}
-
- std::vector<std::string> parse() {
- bool HasMoreInput = true;
- while (HasMoreInput && nextNonWhitespace()) {
- std::string Argument;
- HasMoreInput = parseStringInto(Argument);
- CommandLine.push_back(Argument);
- }
- return CommandLine;
- }
-
- private:
- // All private methods return true if there is more input available.
-
- bool parseStringInto(std::string &String) {
- do {
- if (*Position == '"') {
- if (!parseQuotedStringInto(String)) return false;
- } else {
- if (!parseFreeStringInto(String)) return false;
- }
- } while (*Position != ' ');
- return true;
- }
-
- bool parseQuotedStringInto(std::string &String) {
- if (!next()) return false;
- while (*Position != '"') {
- if (!skipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!next()) return false;
- }
- return next();
- }
-
- bool parseFreeStringInto(std::string &String) {
- do {
- if (!skipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!next()) return false;
- } while (*Position != ' ' && *Position != '"');
- return true;
- }
-
- bool skipEscapeCharacter() {
- if (*Position == '\\') {
- return next();
- }
- return true;
- }
-
- bool nextNonWhitespace() {
- do {
- if (!next()) return false;
- } while (*Position == ' ');
- return true;
- }
-
- bool next() {
- ++Position;
- return Position != Input.end();
- }
-
- const StringRef Input;
- StringRef::iterator Position;
- std::vector<std::string> CommandLine;
-};
-
-std::vector<std::string> unescapeCommandLine(
- StringRef EscapedCommandLine) {
- CommandLineArgumentParser parser(EscapedCommandLine);
- return parser.parse();
-}
-
-} // end namespace
-
CompilationDatabase::~CompilationDatabase() {}
CompilationDatabase *
CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
std::string &ErrorMessage) {
- llvm::SmallString<1024> JSONDatabasePath(BuildDirectory);
- llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- llvm::OwningPtr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
- if (!Database) {
- return NULL;
+ std::stringstream ErrorStream;
+ for (CompilationDatabasePluginRegistry::iterator
+ It = CompilationDatabasePluginRegistry::begin(),
+ Ie = CompilationDatabasePluginRegistry::end();
+ It != Ie; ++It) {
+ std::string DatabaseErrorMessage;
+ OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
+ if (CompilationDatabase *DB =
+ Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
+ return DB;
+ else
+ ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
}
- return Database.take();
+ ErrorMessage = ErrorStream.str();
+ return NULL;
}
static CompilationDatabase *
-findCompilationDatabaseFromDirectory(StringRef Directory) {
-#ifdef USE_CUSTOM_COMPILATION_DATABASE
- if (CompilationDatabase *DB =
- ::clang::tooling::findCompilationDatabaseForDirectory(Directory))
- return DB;
-#endif
+findCompilationDatabaseFromDirectory(StringRef Directory,
+ std::string &ErrorMessage) {
+ std::stringstream ErrorStream;
+ bool HasErrorMessage = false;
while (!Directory.empty()) {
std::string LoadErrorMessage;
@@ -140,8 +57,15 @@ findCompilationDatabaseFromDirectory(StringRef Directory) {
CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
return DB;
+ if (!HasErrorMessage) {
+ ErrorStream << "No compilation database found in " << Directory.str()
+ << " or any parent directory\n" << LoadErrorMessage;
+ HasErrorMessage = true;
+ }
+
Directory = llvm::sys::path::parent_path(Directory);
}
+ ErrorMessage = ErrorStream.str();
return NULL;
}
@@ -151,11 +75,12 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory);
+ CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
+ ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database for file \"" +
- SourceFile + "\"").str();
+ SourceFile + "\"\n" + ErrorMessage).str();
return DB;
}
@@ -164,14 +89,17 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
std::string &ErrorMessage) {
llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
- CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath);
+ CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
+ ErrorMessage);
if (!DB)
ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
- SourceDir + "\"").str();
+ SourceDir + "\"\n" + ErrorMessage).str();
return DB;
}
+CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
+
FixedCompilationDatabase *
FixedCompilationDatabase::loadFromCommandLine(int &Argc,
const char **Argv,
@@ -204,153 +132,10 @@ FixedCompilationDatabase::getAllFiles() const {
return std::vector<std::string>();
}
-JSONCompilationDatabase *
-JSONCompilationDatabase::loadFromFile(StringRef FilePath,
- std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
- llvm::error_code Result =
- llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
- if (Result != 0) {
- ErrorMessage = "Error while opening JSON database: " + Result.message();
- return NULL;
- }
- llvm::OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
- if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
-}
-
-JSONCompilationDatabase *
-JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
- std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
- llvm::MemoryBuffer::getMemBuffer(DatabaseString));
- llvm::OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
- if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
-}
-
-std::vector<CompileCommand>
-JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
- llvm::SmallString<128> NativeFilePath;
- llvm::sys::path::native(FilePath, NativeFilePath);
- llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefI = IndexByFile.find(NativeFilePath);
- if (CommandsRefI == IndexByFile.end())
- return std::vector<CompileCommand>();
- const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
- std::vector<CompileCommand> Commands;
- for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
- llvm::SmallString<8> DirectoryStorage;
- llvm::SmallString<1024> CommandStorage;
- Commands.push_back(CompileCommand(
- // FIXME: Escape correctly:
- CommandsRef[I].first->getValue(DirectoryStorage),
- unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
- }
- return Commands;
-}
-
-std::vector<std::string>
-JSONCompilationDatabase::getAllFiles() const {
- std::vector<std::string> Result;
-
- llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefI = IndexByFile.begin();
- const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
- CommandsRefEnd = IndexByFile.end();
- for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
- Result.push_back(CommandsRefI->first().str());
- }
-
- return Result;
-}
-
-bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
- llvm::yaml::document_iterator I = YAMLStream.begin();
- if (I == YAMLStream.end()) {
- ErrorMessage = "Error while parsing YAML.";
- return false;
- }
- llvm::yaml::Node *Root = I->getRoot();
- if (Root == NULL) {
- ErrorMessage = "Error while parsing YAML.";
- return false;
- }
- llvm::yaml::SequenceNode *Array =
- llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
- if (Array == NULL) {
- ErrorMessage = "Expected array.";
- return false;
- }
- for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
- AE = Array->end();
- AI != AE; ++AI) {
- llvm::yaml::MappingNode *Object =
- llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI);
- if (Object == NULL) {
- ErrorMessage = "Expected object.";
- return false;
- }
- llvm::yaml::ScalarNode *Directory = NULL;
- llvm::yaml::ScalarNode *Command = NULL;
- llvm::yaml::ScalarNode *File = NULL;
- for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
- KVE = Object->end();
- KVI != KVE; ++KVI) {
- llvm::yaml::Node *Value = (*KVI).getValue();
- if (Value == NULL) {
- ErrorMessage = "Expected value.";
- return false;
- }
- llvm::yaml::ScalarNode *ValueString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>(Value);
- if (ValueString == NULL) {
- ErrorMessage = "Expected string as value.";
- return false;
- }
- llvm::yaml::ScalarNode *KeyString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
- if (KeyString == NULL) {
- ErrorMessage = "Expected strings as key.";
- return false;
- }
- llvm::SmallString<8> KeyStorage;
- if (KeyString->getValue(KeyStorage) == "directory") {
- Directory = ValueString;
- } else if (KeyString->getValue(KeyStorage) == "command") {
- Command = ValueString;
- } else if (KeyString->getValue(KeyStorage) == "file") {
- File = ValueString;
- } else {
- ErrorMessage = ("Unknown key: \"" +
- KeyString->getRawValue() + "\"").str();
- return false;
- }
- }
- if (!File) {
- ErrorMessage = "Missing key: \"file\".";
- return false;
- }
- if (!Command) {
- ErrorMessage = "Missing key: \"command\".";
- return false;
- }
- if (!Directory) {
- ErrorMessage = "Missing key: \"directory\".";
- return false;
- }
- llvm::SmallString<8> FileStorage;
- llvm::SmallString<128> NativeFilePath;
- llvm::sys::path::native(File->getValue(FileStorage), NativeFilePath);
- IndexByFile[NativeFilePath].push_back(
- CompileCommandRef(Directory, Command));
- }
- return true;
-}
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+extern volatile int JSONAnchorSource;
+static int JSONAnchorDest = JSONAnchorSource;
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/CustomCompilationDatabase.h b/lib/Tooling/CustomCompilationDatabase.h
deleted file mode 100644
index b375f8d25634..000000000000
--- a/lib/Tooling/CustomCompilationDatabase.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//===--- CustomCompilationDatabase.h --------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains a hook to supply a custom \c CompilationDatabase
-// implementation.
-//
-// The mechanism can be used by IDEs or non-public code bases to integrate with
-// their build system. Currently we support statically linking in an
-// implementation of \c findCompilationDatabaseForDirectory and enabling it
-// with -DUSE_CUSTOM_COMPILATION_DATABASE when compiling the Tooling library.
-//
-// FIXME: The strategy forward is to provide a plugin system that can load
-// custom compilation databases and make enabling that a build option.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
-#define LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
-
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-namespace tooling {
-class CompilationDatabase;
-
-/// \brief Returns a CompilationDatabase for the given \c Directory.
-///
-/// \c Directory can be any directory within a project. This methods will
-/// then try to find compilation database files in \c Directory or any of its
-/// parents. If a compilation database cannot be found or loaded, returns NULL.
-clang::tooling::CompilationDatabase *findCompilationDatabaseForDirectory(
- llvm::StringRef Directory);
-
-} // namespace tooling
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
new file mode 100644
index 000000000000..8f25a8c2bcfb
--- /dev/null
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -0,0 +1,188 @@
+//===--- FileMatchTrie.cpp - ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of a FileMatchTrie.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sstream>
+#include "clang/Tooling/FileMatchTrie.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/PathV2.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief Default \c PathComparator using \c llvm::sys::fs::equivalent().
+struct DefaultPathComparator : public PathComparator {
+ virtual ~DefaultPathComparator() {}
+ virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB);
+ }
+};
+
+/// \brief A node of the \c FileMatchTrie.
+///
+/// Each node has storage for up to one path and a map mapping a path segment to
+/// child nodes. The trie starts with an empty root node.
+class FileMatchTrieNode {
+public:
+ /// \brief Inserts 'NewPath' into this trie. \c ConsumedLength denotes
+ /// the number of \c NewPath's trailing characters already consumed during
+ /// recursion.
+ ///
+ /// An insert of a path
+ /// 'p'starts at the root node and does the following:
+ /// - If the node is empty, insert 'p' into its storage and abort.
+ /// - If the node has a path 'p2' but no children, take the last path segment
+ /// 's' of 'p2', put a new child into the map at 's' an insert the rest of
+ /// 'p2' there.
+ /// - Insert a new child for the last segment of 'p' and insert the rest of
+ /// 'p' there.
+ ///
+ /// An insert operation is linear in the number of a path's segments.
+ void insert(StringRef NewPath, unsigned ConsumedLength = 0) {
+ // We cannot put relative paths into the FileMatchTrie as then a path can be
+ // a postfix of another path, violating a core assumption of the trie.
+ if (llvm::sys::path::is_relative(NewPath))
+ return;
+ if (Path.empty()) {
+ // This is an empty leaf. Store NewPath and return.
+ Path = NewPath;
+ return;
+ }
+ if (Children.empty()) {
+ // This is a leaf, ignore duplicate entry if 'Path' equals 'NewPath'.
+ if (NewPath == Path)
+ return;
+ // Make this a node and create a child-leaf with 'Path'.
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(Path).drop_back(ConsumedLength)));
+ Children[Element].Path = Path;
+ }
+ StringRef Element(llvm::sys::path::filename(
+ StringRef(NewPath).drop_back(ConsumedLength)));
+ Children[Element].insert(NewPath, ConsumedLength + Element.size() + 1);
+ }
+
+ /// \brief Tries to find the node under this \c FileMatchTrieNode that best
+ /// matches 'FileName'.
+ ///
+ /// If multiple paths fit 'FileName' equally well, \c IsAmbiguous is set to
+ /// \c true and an empty string is returned. If no path fits 'FileName', an
+ /// empty string is returned. \c ConsumedLength denotes the number of
+ /// \c Filename's trailing characters already consumed during recursion.
+ ///
+ /// To find the best matching node for a given path 'p', the
+ /// \c findEquivalent() function is called recursively for each path segment
+ /// (back to fron) of 'p' until a node 'n' is reached that does not ..
+ /// - .. have children. In this case it is checked
+ /// whether the stored path is equivalent to 'p'. If yes, the best match is
+ /// found. Otherwise continue with the parent node as if this node did not
+ /// exist.
+ /// - .. a child matching the next path segment. In this case, all children of
+ /// 'n' are an equally good match for 'p'. All children are of 'n' are found
+ /// recursively and their equivalence to 'p' is determined. If none are
+ /// equivalent, continue with the parent node as if 'n' didn't exist. If one
+ /// is equivalent, the best match is found. Otherwise, report and ambigiuity
+ /// error.
+ StringRef findEquivalent(const PathComparator& Comparator,
+ StringRef FileName,
+ bool &IsAmbiguous,
+ unsigned ConsumedLength = 0) const {
+ if (Children.empty()) {
+ if (Comparator.equivalent(StringRef(Path), FileName))
+ return StringRef(Path);
+ return StringRef();
+ }
+ StringRef Element(llvm::sys::path::filename(FileName.drop_back(
+ ConsumedLength)));
+ llvm::StringMap<FileMatchTrieNode>::const_iterator MatchingChild =
+ Children.find(Element);
+ if (MatchingChild != Children.end()) {
+ StringRef Result = MatchingChild->getValue().findEquivalent(
+ Comparator, FileName, IsAmbiguous,
+ ConsumedLength + Element.size() + 1);
+ if (!Result.empty() || IsAmbiguous)
+ return Result;
+ }
+ std::vector<StringRef> AllChildren;
+ getAll(AllChildren, MatchingChild);
+ StringRef Result;
+ for (unsigned i = 0; i < AllChildren.size(); i++) {
+ if (Comparator.equivalent(AllChildren[i], FileName)) {
+ if (Result.empty()) {
+ Result = AllChildren[i];
+ } else {
+ IsAmbiguous = true;
+ return StringRef();
+ }
+ }
+ }
+ return Result;
+ }
+
+private:
+ /// \brief Gets all paths under this FileMatchTrieNode.
+ void getAll(std::vector<StringRef> &Results,
+ llvm::StringMap<FileMatchTrieNode>::const_iterator Except) const {
+ if (Path.empty())
+ return;
+ if (Children.empty()) {
+ Results.push_back(StringRef(Path));
+ return;
+ }
+ for (llvm::StringMap<FileMatchTrieNode>::const_iterator
+ It = Children.begin(), E = Children.end();
+ It != E; ++It) {
+ if (It == Except)
+ continue;
+ It->getValue().getAll(Results, Children.end());
+ }
+ }
+
+ // The stored absolute path in this node. Only valid for leaf nodes, i.e.
+ // nodes where Children.empty().
+ std::string Path;
+
+ // The children of this node stored in a map based on the next path segment.
+ llvm::StringMap<FileMatchTrieNode> Children;
+};
+
+FileMatchTrie::FileMatchTrie()
+ : Root(new FileMatchTrieNode), Comparator(new DefaultPathComparator()) {}
+
+FileMatchTrie::FileMatchTrie(PathComparator *Comparator)
+ : Root(new FileMatchTrieNode), Comparator(Comparator) {}
+
+FileMatchTrie::~FileMatchTrie() {
+ delete Root;
+}
+
+void FileMatchTrie::insert(StringRef NewPath) {
+ Root->insert(NewPath);
+}
+
+StringRef FileMatchTrie::findEquivalent(StringRef FileName,
+ llvm::raw_ostream &Error) const {
+ if (llvm::sys::path::is_relative(FileName)) {
+ Error << "Cannot resolve relative paths";
+ return StringRef();
+ }
+ bool IsAmbiguous = false;
+ StringRef Result = Root->findEquivalent(*Comparator, FileName, IsAmbiguous);
+ if (IsAmbiguous)
+ Error << "Path is ambiguous";
+ return Result;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
new file mode 100644
index 000000000000..cf35a2566637
--- /dev/null
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -0,0 +1,303 @@
+//===--- JSONCompilationDatabase.cpp - ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the JSONCompilationDatabase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/JSONCompilationDatabase.h"
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/system_error.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// \brief A parser for escaped strings of command line arguments.
+///
+/// Assumes \-escaping for quoted arguments (see the documentation of
+/// unescapeCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(StringRef CommandLine)
+ : Input(CommandLine), Position(Input.begin()-1) {}
+
+ std::vector<std::string> parse() {
+ bool HasMoreInput = true;
+ while (HasMoreInput && nextNonWhitespace()) {
+ std::string Argument;
+ HasMoreInput = parseStringInto(Argument);
+ CommandLine.push_back(Argument);
+ }
+ return CommandLine;
+ }
+
+ private:
+ // All private methods return true if there is more input available.
+
+ bool parseStringInto(std::string &String) {
+ do {
+ if (*Position == '"') {
+ if (!parseQuotedStringInto(String)) return false;
+ } else {
+ if (!parseFreeStringInto(String)) return false;
+ }
+ } while (*Position != ' ');
+ return true;
+ }
+
+ bool parseQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '"') {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
+ bool parseFreeStringInto(std::string &String) {
+ do {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ } while (*Position != ' ' && *Position != '"');
+ return true;
+ }
+
+ bool skipEscapeCharacter() {
+ if (*Position == '\\') {
+ return next();
+ }
+ return true;
+ }
+
+ bool nextNonWhitespace() {
+ do {
+ if (!next()) return false;
+ } while (*Position == ' ');
+ return true;
+ }
+
+ bool next() {
+ ++Position;
+ return Position != Input.end();
+ }
+
+ const StringRef Input;
+ StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+std::vector<std::string> unescapeCommandLine(
+ StringRef EscapedCommandLine) {
+ CommandLineArgumentParser parser(EscapedCommandLine);
+ return parser.parse();
+}
+
+} // end namespace
+
+class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
+ virtual CompilationDatabase *loadFromDirectory(
+ StringRef Directory, std::string &ErrorMessage) {
+ llvm::SmallString<1024> JSONDatabasePath(Directory);
+ llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+ llvm::OwningPtr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
+ if (!Database)
+ return NULL;
+ return Database.take();
+ }
+};
+
+// Register the JSONCompilationDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
+X("json-compilation-database", "Reads JSON formatted compilation databases");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONCompilationDatabasePlugin.
+volatile int JSONAnchorSource = 0;
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
+ llvm::error_code Result =
+ llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
+ if (Result != 0) {
+ ErrorMessage = "Error while opening JSON database: " + Result.message();
+ return NULL;
+ }
+ llvm::OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ llvm::MemoryBuffer::getMemBuffer(DatabaseString));
+ llvm::OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+std::vector<CompileCommand>
+JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+ llvm::SmallString<128> NativeFilePath;
+ llvm::sys::path::native(FilePath, NativeFilePath);
+ std::vector<StringRef> PossibleMatches;
+ std::string Error;
+ llvm::raw_string_ostream ES(Error);
+ StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
+ if (Match.empty()) {
+ if (Error.empty())
+ Error = "No match found.";
+ llvm::outs() << Error << "\n";
+ return std::vector<CompileCommand>();
+ }
+ llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.find(Match);
+ if (CommandsRefI == IndexByFile.end())
+ return std::vector<CompileCommand>();
+ const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
+ std::vector<CompileCommand> Commands;
+ for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
+ llvm::SmallString<8> DirectoryStorage;
+ llvm::SmallString<1024> CommandStorage;
+ Commands.push_back(CompileCommand(
+ // FIXME: Escape correctly:
+ CommandsRef[I].first->getValue(DirectoryStorage),
+ unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
+ }
+ return Commands;
+}
+
+std::vector<std::string>
+JSONCompilationDatabase::getAllFiles() const {
+ std::vector<std::string> Result;
+
+ llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.begin();
+ const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefEnd = IndexByFile.end();
+ for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
+ Result.push_back(CommandsRefI->first().str());
+ }
+
+ return Result;
+}
+
+bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
+ llvm::yaml::document_iterator I = YAMLStream.begin();
+ if (I == YAMLStream.end()) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ llvm::yaml::Node *Root = I->getRoot();
+ if (Root == NULL) {
+ ErrorMessage = "Error while parsing YAML.";
+ return false;
+ }
+ llvm::yaml::SequenceNode *Array =
+ llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
+ if (Array == NULL) {
+ ErrorMessage = "Expected array.";
+ return false;
+ }
+ for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
+ AE = Array->end();
+ AI != AE; ++AI) {
+ llvm::yaml::MappingNode *Object =
+ llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI);
+ if (Object == NULL) {
+ ErrorMessage = "Expected object.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *Directory = NULL;
+ llvm::yaml::ScalarNode *Command = NULL;
+ llvm::yaml::ScalarNode *File = NULL;
+ for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
+ KVE = Object->end();
+ KVI != KVE; ++KVI) {
+ llvm::yaml::Node *Value = (*KVI).getValue();
+ if (Value == NULL) {
+ ErrorMessage = "Expected value.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *ValueString =
+ llvm::dyn_cast<llvm::yaml::ScalarNode>(Value);
+ if (ValueString == NULL) {
+ ErrorMessage = "Expected string as value.";
+ return false;
+ }
+ llvm::yaml::ScalarNode *KeyString =
+ llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
+ if (KeyString == NULL) {
+ ErrorMessage = "Expected strings as key.";
+ return false;
+ }
+ llvm::SmallString<8> KeyStorage;
+ if (KeyString->getValue(KeyStorage) == "directory") {
+ Directory = ValueString;
+ } else if (KeyString->getValue(KeyStorage) == "command") {
+ Command = ValueString;
+ } else if (KeyString->getValue(KeyStorage) == "file") {
+ File = ValueString;
+ } else {
+ ErrorMessage = ("Unknown key: \"" +
+ KeyString->getRawValue() + "\"").str();
+ return false;
+ }
+ }
+ if (!File) {
+ ErrorMessage = "Missing key: \"file\".";
+ return false;
+ }
+ if (!Command) {
+ ErrorMessage = "Missing key: \"command\".";
+ return false;
+ }
+ if (!Directory) {
+ ErrorMessage = "Missing key: \"directory\".";
+ return false;
+ }
+ llvm::SmallString<8> FileStorage;
+ StringRef FileName = File->getValue(FileStorage);
+ llvm::SmallString<128> NativeFilePath;
+ if (llvm::sys::path::is_relative(FileName)) {
+ llvm::SmallString<8> DirectoryStorage;
+ llvm::SmallString<128> AbsolutePath(
+ Directory->getValue(DirectoryStorage));
+ llvm::sys::path::append(AbsolutePath, FileName);
+ llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
+ } else {
+ llvm::sys::path::native(FileName, NativeFilePath);
+ }
+ IndexByFile[NativeFilePath].push_back(
+ CompileCommandRef(Directory, Command));
+ MatchTrie.insert(NativeFilePath.str());
+ }
+ return true;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index 628435307c0b..c5002ef9fcfc 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/Support/raw_os_ostream.h"
@@ -164,12 +164,11 @@ Replacements &RefactoringTool::getReplacements() { return Replace; }
int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
int Result = Tool.run(ActionFactory);
LangOptions DefaultLangOptions;
- DiagnosticOptions DefaultDiagnosticOptions;
- TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(),
- DefaultDiagnosticOptions);
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
- &DiagnosticPrinter, false);
+ &*DiagOpts, &DiagnosticPrinter, false);
SourceManager Sources(Diagnostics, Tool.getFiles());
Rewriter Rewrite(Sources, DefaultLangOptions);
if (!applyAllReplacements(Replace, Rewrite)) {
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index e93e0c97f710..af20254811aa 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -97,17 +97,22 @@ static clang::CompilerInvocation *newInvocation(
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName) {
+ return runToolOnCodeWithArgs(
+ ToolAction, Code, std::vector<std::string>(), FileName);
+}
+
+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);
- const char *const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileNameRef.data()
- };
+ 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(
- std::vector<std::string>(
- CommandLine,
- CommandLine + llvm::array_lengthof(CommandLine)),
- ToolAction, &Files);
+ ToolInvocation Invocation(Commands, ToolAction, &Files);
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
@@ -154,11 +159,12 @@ bool ToolInvocation::run() {
for (int I = 0, E = CommandLine.size(); I != E; ++I)
Argv.push_back(CommandLine[I].c_str());
const char *const BinaryName = Argv[0];
- DiagnosticOptions DefaultDiagnosticOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter DiagnosticPrinter(
- llvm::errs(), DefaultDiagnosticOptions);
- DiagnosticsEngine Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
- new DiagnosticIDs()), &DiagnosticPrinter, false);
+ llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagnosticPrinter, false);
const llvm::OwningPtr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index f1335910f169..68b2941f8769 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -74,8 +74,9 @@ RuntimeDirs :=
ifeq ($(OS),Darwin)
RuntimeDirs += darwin
RuntimeLibrary.darwin.Configs := \
- eprintf 10.4 osx cc_kext \
- asan_osx profile_osx
+ eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \
+ asan_osx.a asan_osx_dynamic.dylib \
+ profile_osx.a profile_ios.a
endif
# On Linux, include a library which has all the runtime functions.
@@ -83,14 +84,37 @@ ifeq ($(OS),Linux)
RuntimeDirs += linux
RuntimeLibrary.linux.Configs :=
+# TryCompile compiler source flags
+# Returns exit code of running a compiler invocation.
+TryCompile = \
+ $(shell \
+ cflags=""; \
+ for flag in $(3); do \
+ cflags="$$cflags $$flag"; \
+ done; \
+ $(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 += \
- full-i386 profile-i386 asan-i386
+ full-i386.a profile-i386.a asan-i386.a
endif
+
ifeq ($(ARCH),x86_64)
RuntimeLibrary.linux.Configs += \
- full-x86_64 profile-x86_64 asan-x86_64 tsan-x86_64
+ full-x86_64.a profile-x86_64.a asan-x86_64.a tsan-x86_64.a
+# We need to build 32-bit ASan library on 64-bit platform, and add it to the
+# list of runtime libraries to make "clang -faddress-sanitizer -m32" work.
+# We check that Clang can produce working 32-bit binaries by compiling a simple
+# 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 += asan-i386.a
+endif
+ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
+RuntimeLibrary.linux.Configs += asan-arm-android.so
+endif
endif
endif
@@ -109,6 +133,7 @@ BuildRuntimeLibraries:
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
ProjObjRoot=$(PROJ_OBJ_DIR) \
CC="$(ToolDir)/clang" \
+ LLVM_ANDROID_TOOLCHAIN_DIR="$(LLVM_ANDROID_TOOLCHAIN_DIR)" \
$(RuntimeDirs:%=clang_%)
.PHONY: BuildRuntimeLibraries
CleanRuntimeLibraries:
@@ -126,6 +151,10 @@ $(PROJ_resources_lib):
define RuntimeLibraryTemplate
$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a: BuildRuntimeLibraries
@true
+$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.so: BuildRuntimeLibraries
+ @true
+$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.dylib: BuildRuntimeLibraries
+ @true
.PRECIOUS: $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a
# Rule to copy the libraries to their resource directory location.
@@ -134,8 +163,20 @@ $(ResourceLibDir)/$1/libclang_rt.%.a: \
$(ResourceLibDir)/$1/.dir
$(Echo) Copying runtime library $1/$$* to build dir
$(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.a $$@
+$(ResourceLibDir)/$1/libclang_rt.%.so: \
+ $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.so \
+ $(ResourceLibDir)/$1/.dir
+ $(Echo) Copying runtime library $1/$$* to build dir
+ $(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.so $$@
+$(ResourceLibDir)/$1/libclang_rt.%.dylib: \
+ $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.dylib \
+ $(ResourceLibDir)/$1/.dir
+ $(Echo) Copying runtime library $1/$$* to build dir
+ $(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.dylib $$@
+ $(Echo) Fixing LC_ID_DYLIB of $$@
+ $(Verb) install_name_tool $$@ -id $$@
RuntimeLibrary.$1: \
- $(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%.a)
+ $(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%)
.PHONY: RuntimeLibrary.$1
$(PROJ_resources_lib)/$1: $(PROJ_resources_lib)
@@ -145,10 +186,18 @@ $(PROJ_resources_lib)/$1/libclang_rt.%.a: \
$(ResourceLibDir)/$1/libclang_rt.%.a | $(PROJ_resources_lib)/$1
$(Echo) Installing compiler runtime library: $1/$$*
$(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
+$(PROJ_resources_lib)/$1/libclang_rt.%.so: \
+ $(ResourceLibDir)/$1/libclang_rt.%.so | $(PROJ_resources_lib)/$1
+ $(Echo) Installing compiler runtime library: $1/$$*
+ $(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
+$(PROJ_resources_lib)/$1/libclang_rt.%.dylib: \
+ $(ResourceLibDir)/$1/libclang_rt.%.dylib | $(PROJ_resources_lib)/$1
+ $(Echo) Installing compiler runtime library: $1/$$*
+ $(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
# Rule to install runtime libraries.
RuntimeLibraryInstall.$1: \
- $(RuntimeLibrary.$1.Configs:%=$(PROJ_resources_lib)/$1/libclang_rt.%.a)
+ $(RuntimeLibrary.$1.Configs:%=$(PROJ_resources_lib)/$1/libclang_rt.%)
.PHONY: RuntimeLibraryInstall.$1
endef
$(foreach lib,$(RuntimeDirs), $(eval $(call RuntimeLibraryTemplate,$(lib))))
diff --git a/runtime/compiler-rt/clang_linux_test_input.c b/runtime/compiler-rt/clang_linux_test_input.c
new file mode 100644
index 000000000000..e65ce9860af4
--- /dev/null
+++ b/runtime/compiler-rt/clang_linux_test_input.c
@@ -0,0 +1,4 @@
+// This file is used to check if we can produce working executables
+// for i386 and x86_64 archs on Linux.
+#include <stdlib.h>
+int main(){}
diff --git a/test/ARCMT/cxx-checking.mm b/test/ARCMT/cxx-checking.mm
index 9f9e3d864312..2f5d5d51655a 100644
--- a/test/ARCMT/cxx-checking.mm
+++ b/test/ARCMT/cxx-checking.mm
@@ -1,16 +1,16 @@
-// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fsyntax-only -fblocks -Warc-abi %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fsyntax-only -fblocks %s
// DISABLE: mingw32
// Classes that have an Objective-C object pointer.
-struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+struct HasObjectMember0 {
id x;
};
-struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+struct HasObjectMember1 {
id x[3];
};
-struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+struct HasObjectMember2 {
id x[3][2];
};
@@ -27,11 +27,11 @@ struct HasObjectMember3 {
__unsafe_unretained id x[3][2];
};
-struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+struct HasBlockPointerMember0 {
int (^bp)(int);
};
-struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+struct HasBlockPointerMember1 {
int (^bp[2][3])(int);
};
@@ -39,20 +39,17 @@ struct NonPOD {
NonPOD(const NonPOD&);
};
-struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+struct HasObjectMemberAndNonPOD0 {
id x;
NonPOD np;
};
-struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+struct HasObjectMemberAndNonPOD1 {
NonPOD np;
id x[3];
};
-struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+struct HasObjectMemberAndNonPOD2 {
NonPOD np;
id x[3][2];
};
@@ -64,14 +61,12 @@ struct HasObjectMemberAndNonPOD3 {
id x[3][2];
};
-struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
-// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+struct HasBlockPointerMemberAndNonPOD0 {
NonPOD np;
int (^bp)(int);
};
-struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
-// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+struct HasBlockPointerMemberAndNonPOD1 {
NonPOD np;
int (^bp[2][3])(int);
};
diff --git a/test/ARCMT/verify.m b/test/ARCMT/verify.m
index 9110fe6efae2..bfb3b4b8ab55 100644
--- a/test/ARCMT/verify.m
+++ b/test/ARCMT/verify.m
@@ -8,6 +8,7 @@
#error should not be ignored
// expected-error@-1 {{should not be ignored}}
-// CHECK: error: 'error' diagnostics seen but not expected:
+// CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics'
+// CHECK-NEXT: error: 'error' diagnostics seen but not expected:
// CHECK-NEXT: (frontend): error reading '{{.*}}verify.m.tmp.invalid'
-// CHECK-NEXT: 1 error generated.
+// CHECK-NEXT: 2 errors generated.
diff --git a/test/ASTMerge/exprs.c b/test/ASTMerge/exprs.c
index 0a4e1e51e24d..c82e6831f5c6 100644
--- a/test/ASTMerge/exprs.c
+++ b/test/ASTMerge/exprs.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/exprs1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/exprs2.c
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
diff --git a/test/Analysis/CFContainers-invalid.c b/test/Analysis/CFContainers-invalid.c
new file mode 100644
index 000000000000..3268e1eae253
--- /dev/null
+++ b/test/Analysis/CFContainers-invalid.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues -triple x86_64-apple-darwin -verify %s
+// expected-no-diagnostics
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFArray * CFArrayRef;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef const struct __CFSet * CFSetRef;
+
+extern const CFAllocatorRef kCFAllocatorDefault;
+
+// Unexpected declarations for these:
+CFArrayRef CFArrayCreate(CFAllocatorRef);
+CFDictionaryRef CFDictionaryCreate(CFAllocatorRef);
+CFSetRef CFSetCreate(CFAllocatorRef);
+
+void testNoCrash() {
+ (void)CFArrayCreate(kCFAllocatorDefault);
+ (void)CFDictionaryCreate(kCFAllocatorDefault);
+ (void)CFSetCreate(kCFAllocatorDefault);
+}
diff --git a/test/Analysis/CFContainers.mm b/test/Analysis/CFContainers.mm
index 7d6c175d1fc2..b01942310f7b 100644
--- a/test/Analysis/CFContainers.mm
+++ b/test/Analysis/CFContainers.mm
@@ -94,16 +94,16 @@ CFSetRef CFSetCreate(CFAllocatorRef allocator, const void **values, CFIndex numV
#define NULL __null
// Done with the headers.
-// Test experimental.osx.cocoa.ContainerAPI checker.
+// Test alpha.osx.cocoa.ContainerAPI checker.
void testContainers(int **xNoWarn, CFIndex count) {
int x[] = { 1, 2, 3 };
- CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);// expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+ CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);// expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
CFArrayRef fooNoWarn = CFArrayCreate(kCFAllocatorDefault, (const void **) xNoWarn, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0); // no warning
CFArrayRef fooNoWarn2 = CFArrayCreate(kCFAllocatorDefault, 0, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in 0
CFArrayRef fooNoWarn3 = CFArrayCreate(kCFAllocatorDefault, NULL, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in NULL
- CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks); // expected-warning {{The first argument to 'CFSetCreate' must be a C array of pointer-sized values}}
+ CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks); // expected-warning {{The second argument to 'CFSetCreate' must be a C array of pointer-sized values}}
CFArrayRef* pairs = new CFArrayRef[count];
CFSetRef fSet = CFSetCreate(kCFAllocatorDefault, (const void**) pairs, count - 1, &kCFTypeSetCallBacks);// no warning
}
@@ -125,8 +125,8 @@ void CreateDict(int *elems) {
const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks;
const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks;
CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning
- CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The first argument to 'CFDictionaryCreate' must be a C array of}}
- CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
+ CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of}} expected-warning {{cast to 'const void **' from smaller integer type 'int'}}
+ CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The third argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
}
void OutOfBoundsSymbolicOffByOne(const void ** input, CFIndex S) {
@@ -177,11 +177,11 @@ void TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count
CFArrayCreate(0, (const void **) &fn, count, 0); // false negative
CFArrayCreate(0, (const void **) fn, count, 0); // no warning
- CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+ CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
char cc[] = { 0, 2, 3 };
- CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
- CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+ CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+ CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The second argument to 'CFArrayCreate' must be a C array of pointer-sized}}
}
void TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) {
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index 4884bb9ea888..e12306216e60 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
index 537e49785130..ebb3b1ac1ed8 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
typedef signed long CFIndex;
diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
index e0c9be1c1ebf..853bfb24dacd 100644
--- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=basic -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=range -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -verify %s -analyzer-constraints=range -analyzer-store=region
+// expected-no-diagnostics
typedef struct objc_selector *SEL;
typedef signed char BOOL;
diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c
index 1bd20fa1cfa1..e2da36459a23 100644
--- a/test/Analysis/CGColorSpace.c
+++ b/test/Analysis/CGColorSpace.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify %s
typedef struct CGColorSpace *CGColorSpaceRef;
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index cdec1d50f2ca..af645da79989 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
new file mode 100644
index 000000000000..e762d0a1bdfb
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -0,0 +1,57 @@
+#pragma clang system_header
+
+namespace std {
+ template <class T1, class T2>
+ struct pair {
+ T1 first;
+ T2 second;
+
+ pair() : first(), second() {}
+ pair(const T1 &a, const T2 &b) : first(a), second(b) {}
+
+ template<class U1, class U2>
+ pair(const pair<U1, U2> &other) : first(other.first), second(other.second) {}
+ };
+
+ typedef __typeof__(sizeof(int)) size_t;
+
+ template<typename T>
+ class vector {
+ T *_start;
+ T *_finish;
+ T *_end_of_storage;
+ public:
+ vector() : _start(0), _finish(0), _end_of_storage(0) {}
+ ~vector();
+
+ size_t size() const {
+ return size_t(_finish - _start);
+ }
+
+ void push_back();
+ T pop_back();
+
+ T &operator[](size_t n) {
+ return _start[n];
+ }
+
+ const T &operator[](size_t n) const {
+ return _start[n];
+ }
+
+ T *begin() { return _start; }
+ const T *begin() const { return _start; }
+
+ T *end() { return _finish; }
+ const T *end() const { return _finish; }
+ };
+
+ class exception {
+ public:
+ exception() throw();
+ virtual ~exception() throw();
+ virtual const char *what() const throw() {
+ return 0;
+ }
+ };
+}
diff --git a/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h b/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h
new file mode 100644
index 000000000000..99986f454995
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h
@@ -0,0 +1,11 @@
+
+#pragma clang system_header
+
+typedef struct __sFILE {
+ unsigned char *_p;
+} FILE;
+FILE *fopen(const char * restrict, const char * restrict) __asm("_" "fopen" );
+int fputc(int, FILE *);
+int fputs(const char * restrict, FILE * restrict) __asm("_" "fputs" );
+int fclose(FILE *);
+void exit(int);
diff --git a/test/Analysis/system-header-simulator-objc.h b/test/Analysis/Inputs/system-header-simulator-objc.h
index a647b3740406..a647b3740406 100644
--- a/test/Analysis/system-header-simulator-objc.h
+++ b/test/Analysis/Inputs/system-header-simulator-objc.h
diff --git a/test/Analysis/system-header-simulator.h b/test/Analysis/Inputs/system-header-simulator.h
index 5790fb9cff4a..e28b89060372 100644
--- a/test/Analysis/system-header-simulator.h
+++ b/test/Analysis/Inputs/system-header-simulator.h
@@ -15,7 +15,9 @@ int fscanf(FILE *restrict, const char *restrict, ...);
// Note, on some platforms errno macro gets replaced with a function call.
extern int errno;
-unsigned long strlen(const char *);
+typedef __typeof(sizeof(int)) size_t;
+
+size_t strlen(const char *);
char *strcpy(char *restrict, const char *restrict);
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
index 589fcf57f40c..b465959791b0 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.cocoa.Dealloc %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.Dealloc %s -verify
+// expected-no-diagnostics
typedef signed char BOOL;
@protocol NSObject
- (BOOL)isEqual:(id)object;
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index 578658eab694..1d77d1e3702b 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 4035cc93130a..9339069f4c4f 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
index 495f8e19d8ef..a2e7297d873d 100644
--- a/test/Analysis/NSWindow.m
+++ b/test/Analysis/NSWindow.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
// These declarations were reduced using Delta-Debugging from Foundation.h
// on Mac OS X. The test cases are below.
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index 1d948fa66f6d..6d547f47f66c 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// expected-no-diagnostics
#include <stdarg.h>
diff --git a/test/Analysis/OSAtomic_mac.cpp b/test/Analysis/OSAtomic_mac.cpp
index 8ad7b3c3da66..f93895893c59 100644
--- a/test/Analysis/OSAtomic_mac.cpp
+++ b/test/Analysis/OSAtomic_mac.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,osx -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// expected-no-diagnostics
// Test handling of OSAtomicCompareAndSwap when C++ inserts "no-op" casts and we
// do a forced load and binding to the environment on an expression that would regularly
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index b9ed9b9a7e5f..1712feff5b78 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -Wno-objc-root-class %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -Wno-objc-root-class %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -Wno-objc-root-class %s -verify
+// expected-no-diagnostics
// The point of this test cases is to exercise properties in the static
// analyzer
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
index 13078a32232b..b5a3e7cdbf12 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s
int printf(const char *, ...);
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index 5436063738a6..fb368e33f140 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index ea139d28af82..4684ae963995 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=experimental.osx.cocoa.Dealloc %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core -analyzer-checker=alpha.osx.cocoa.Dealloc %s -verify
// Tests for the checker which checks missing/extra ivar 'release' calls
// in dealloc.
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 38d0bc0b5293..4d76fd347e24 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
//===----------------------------------------------------------------------===//
// Delta-debugging produced forward declarations.
diff --git a/test/Analysis/PR9741.cpp b/test/Analysis/PR9741.cpp
index 7497d5627c91..2807c44ab7bc 100644
--- a/test/Analysis/PR9741.cpp
+++ b/test/Analysis/PR9741.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -cc1 -std=c++11 -Wuninitialized -verify %s
+// expected-no-diagnostics
void f() {
int a[] = { 1, 2, 3 };
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 0d749ec3cbaf..4d58f1c20d5b 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=basic -Wno-tautological-compare %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare -Wtautological-constant-out-of-range-compare %s
void clang_analyzer_eval(bool);
@@ -129,10 +128,10 @@ void tautologies(unsigned a) {
// Tautologies from outside the range of the symbol
void tautologiesOutside(unsigned char a) {
- clang_analyzer_eval(a <= 0x100); // expected-warning{{TRUE}}
- clang_analyzer_eval(a < 0x100); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a <= 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
+ clang_analyzer_eval(a < 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
- clang_analyzer_eval(a != 0x100); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a != 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
clang_analyzer_eval(a != -1); // expected-warning{{TRUE}}
clang_analyzer_eval(a > -1); // expected-warning{{TRUE}}
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
new file mode 100644
index 000000000000..990f5784b42b
--- /dev/null
+++ b/test/Analysis/analyzer-config.c
@@ -0,0 +1,13 @@
+// RUN: %clang --analyze %s -o /dev/null -Xclang -analyzer-checker=debug.ConfigDumper > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+void bar() {}
+void foo() { bar(); }
+
+// CHECK: [config]
+// CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: faux-bodies = true
+// CHECK-NEXT: graph-trim-interval = 1000
+// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: [stats]
+// CHECK-NEXT: num-entries = 4
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
new file mode 100644
index 000000000000..fb142669b428
--- /dev/null
+++ b/test/Analysis/analyzer-config.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang --analyze %s -o /dev/null -Xclang -analyzer-checker=debug.ConfigDumper > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+void bar() {}
+void foo() { bar(); }
+
+class Foo {
+public:
+ void bar() {}
+ void foo() { bar(); }
+};
+
+// CHECK: [config]
+// CHECK-NEXT: c++-inlining = methods
+// CHECK-NEXT: c++-stdlib-inlining = true
+// CHECK-NEXT: c++-template-inlining = true
+// CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: faux-bodies = true
+// CHECK-NEXT: graph-trim-interval = 1000
+// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: [stats]
+// CHECK-NEXT: num-entries = 7
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index 244bc977b511..d628c47cb0c0 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -analyzer-ipa=inlining -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-constraints=range -verify %s
void clang_analyzer_eval(int);
@@ -184,3 +183,110 @@ int testConcreteInvalidationDoubleStruct(int index) {
}
+int testNonOverlappingStructFieldsSimple() {
+ S val;
+
+ val.x = 1;
+ val.y = 2;
+ clang_analyzer_eval(val.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(val.y == 2); // expected-warning{{TRUE}}
+
+ return val.z; // expected-warning{{garbage}}
+}
+
+int testNonOverlappingStructFieldsSymbolicBase(int index, int anotherIndex) {
+ SS vals;
+
+ vals.a[index].x = 42;
+ vals.a[index].y = 42;
+ clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(vals.a[index].y == 42); // expected-warning{{TRUE}}
+
+ vals.a[anotherIndex].x = 42;
+ clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(vals.a[index].y == 42); // expected-warning{{TRUE}}
+
+ // FIXME: False negative. No bind ever set a field 'z'.
+ return vals.a[index].z; // no-warning
+}
+
+int testStructFieldChains(int index, int anotherIndex) {
+ SS vals[4];
+
+ vals[index].a[0].x = 42;
+ vals[anotherIndex].a[1].y = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}}
+
+ // This doesn't affect anything in the 'a' array field.
+ vals[anotherIndex].b[1].x = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(vals[anotherIndex].b[1].x == 42); // expected-warning{{TRUE}}
+
+ // This doesn't affect anything in the 'b' array field.
+ vals[index].a[anotherIndex].x = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(vals[anotherIndex].a[0].x == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(vals[anotherIndex].b[1].x == 42); // expected-warning{{TRUE}}
+
+ // FIXME: False negative. No bind ever set a field 'z'.
+ return vals[index].a[0].z; // no-warning
+}
+
+int testStructFieldChainsNested(int index, int anotherIndex) {
+ SS vals[4];
+
+ vals[index].a[0].x = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+
+ vals[index].b[0] = makeS();
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+
+ vals[index].a[0] = makeS();
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}}
+
+ vals[index].a[0].x = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+
+ return 0;
+}
+
+
+// --------------------
+// False positives
+// --------------------
+
+int testMixSymbolicAndConcrete(int index, int anotherIndex) {
+ SS vals;
+
+ vals.a[index].x = 42;
+ vals.a[0].y = 42;
+
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}}
+ // Should be TRUE; we set this explicitly.
+ clang_analyzer_eval(vals.a[0].y == 42); // expected-warning{{TRUE}}
+
+ vals.a[anotherIndex].y = 42;
+
+ // Should be UNKNOWN; we set an 'x'.
+ clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}}
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(vals.a[0].y == 42); // expected-warning{{UNKNOWN}}
+
+ return vals.a[0].x; // no-warning
+}
+
+void testFieldChainIsNotEnough(int index) {
+ SS vals[4];
+
+ vals[index].a[0].x = 42;
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}}
+
+ vals[index].a[1] = makeS();
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}}
+}
+
diff --git a/test/Analysis/array-struct-region.cpp b/test/Analysis/array-struct-region.cpp
new file mode 100644
index 000000000000..12ae5d3eba6e
--- /dev/null
+++ b/test/Analysis/array-struct-region.cpp
@@ -0,0 +1,176 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+ int field;
+
+#if __cplusplus
+ const struct S *getThis() const { return this; }
+ const struct S *operator +() const { return this; }
+
+ bool check() const { return this == this; }
+ bool operator !() const { return this != this; }
+
+ int operator *() const { return field; }
+#endif
+};
+
+#if __cplusplus
+const struct S *operator -(const struct S &s) { return &s; }
+bool operator ~(const struct S &s) { return &s != &s; }
+#endif
+
+
+#ifdef INLINE
+struct S getS() {
+ struct S s = { 42 };
+ return s;
+}
+#else
+struct S getS();
+#endif
+
+
+void testAssignment() {
+ struct S s = getS();
+
+ if (s.field != 42) return;
+ clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
+
+ s.field = 0;
+ clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}}
+
+#if __cplusplus
+ clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
+ clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
+ clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
+ clang_analyzer_eval(!s); // expected-warning{{FALSE}}
+ clang_analyzer_eval(~s); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}}
+#endif
+}
+
+
+void testImmediateUse() {
+ int x = getS().field;
+
+ if (x != 42) return;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+
+#if __cplusplus
+ clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}}
+ clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}}
+ clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}}
+ clang_analyzer_eval(!getS()); // expected-warning{{FALSE}}
+ clang_analyzer_eval(~getS()); // expected-warning{{FALSE}}
+#endif
+}
+
+int getConstrainedField(struct S s) {
+ if (s.field != 42) return 42;
+ return s.field;
+}
+
+int getAssignedField(struct S s) {
+ s.field = 42;
+ return s.field;
+}
+
+void testArgument() {
+ clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}}
+}
+
+void testImmediateUseParens() {
+ int x = ((getS())).field;
+
+ if (x != 42) return;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}}
+
+#if __cplusplus
+ clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}}
+ clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}}
+ clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}}
+#endif
+}
+
+
+//--------------------
+// C++-only tests
+//--------------------
+
+#if __cplusplus
+void testReferenceAssignment() {
+ const S &s = getS();
+
+ if (s.field != 42) return;
+ clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}}
+ clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(s.check()); // expected-warning{{TRUE}}
+ clang_analyzer_eval(!s); // expected-warning{{FALSE}}
+ clang_analyzer_eval(~s); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}}
+}
+
+
+int getConstrainedFieldRef(const S &s) {
+ if (s.field != 42) return 42;
+ return s.field;
+}
+
+bool checkThis(const S &s) {
+ return s.getThis() == &s;
+}
+
+bool checkThisOp(const S &s) {
+ return +s == &s;
+}
+
+bool checkThisStaticOp(const S &s) {
+ return -s == &s;
+}
+
+void testReferenceArgument() {
+ clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}}
+ clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}}
+ clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}}
+}
+
+
+int getConstrainedFieldOp(S s) {
+ if (*s != 42) return 42;
+ return *s;
+}
+
+int getConstrainedFieldRefOp(const S &s) {
+ if (*s != 42) return 42;
+ return *s;
+}
+
+void testImmediateUseOp() {
+ int x = *getS();
+ if (x != 42) return;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}}
+}
+
+#endif
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index 1b36190729b5..c22f9796e580 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.CastToStruct -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.CastToStruct -analyzer-store=region -analyzer-constraints=range -verify %s
struct s {
int data;
@@ -176,3 +175,11 @@ void f18() {
if (*q) { // no-warning
}
}
+
+
+// [PR13927] offsetof replacement macro flagged as "dereference of a null pointer"
+int offset_of_data_array(void)
+{
+ return ((char *)&(((struct s*)0)->data_array)) - ((char *)0); // no-warning
+}
+
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 566e6caed60d..e4b49dc10f1b 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// XPASS: *
diff --git a/test/Analysis/base-init.cpp b/test/Analysis/base-init.cpp
index e63d50855e10..34e01aa5d7fc 100644
--- a/test/Analysis/base-init.cpp
+++ b/test/Analysis/base-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -verify %s
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/bitwise-ops.c b/test/Analysis/bitwise-ops.c
new file mode 100644
index 000000000000..bf282eca27d4
--- /dev/null
+++ b/test/Analysis/bitwise-ops.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+#define CHECK(expr) if (!(expr)) return; clang_analyzer_eval(expr)
+
+void testPersistentConstraints(int x, int y) {
+ // Sanity check
+ CHECK(x); // expected-warning{{TRUE}}
+ CHECK(x & 1); // expected-warning{{TRUE}}
+
+ // False positives due to SValBuilder giving up on certain kinds of exprs.
+ CHECK(1 - x); // expected-warning{{UNKNOWN}}
+ CHECK(x & y); // expected-warning{{UNKNOWN}}
+} \ No newline at end of file
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index ff376d17a1a1..54ff58c64f42 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -26,10 +26,12 @@ typedef struct _NSZone NSZone;
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@interface NSObject <NSObject> {}
+ (id)alloc;
+- (id)copy;
@end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
-@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
-- ( const char *)UTF8String;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (const char *)UTF8String;
- (id)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
@end
@class NSString, NSData;
@@ -85,4 +87,10 @@ void test2_b() {
void test2_c() {
typedef void (^myblock)(void);
myblock f = ^() { f(); }; // expected-warning{{Variable 'f' is uninitialized when captured by block}}
-} \ No newline at end of file
+}
+
+
+void testMessaging() {
+ // <rdar://problem/12119814>
+ [[^(){} copy] release];
+}
diff --git a/test/Analysis/bool-assignment.cpp b/test/Analysis/bool-assignment.cpp
index e57312999449..9361d93aab35 100644
--- a/test/Analysis/bool-assignment.cpp
+++ b/test/Analysis/bool-assignment.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify %s
// Test C++'s bool
diff --git a/test/Analysis/bool-assignment2.c b/test/Analysis/bool-assignment2.c
index 9de26cf34958..22f4237adfd4 100644
--- a/test/Analysis/bool-assignment2.c
+++ b/test/Analysis/bool-assignment2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c99 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -std=c99 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify %s
// Test stdbool.h's _Bool
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index d383d421d444..69d281afee4a 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index f862ddf57315..1c0f35749b22 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// expected-no-diagnostics
// Test if the 'storage' region gets properly initialized after it is cast to
// 'struct sockaddr *'.
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index 6f19211976b7..1a78940eee25 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// 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
diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c
index 529210986916..7fce2263c23b 100644
--- a/test/Analysis/cfref_PR2519.c
+++ b/test/Analysis/cfref_PR2519.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// expected-no-diagnostics
typedef unsigned char Boolean;
typedef signed long CFIndex;
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
index ea4c3ee6d549..0023d13703ab 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// expected-no-diagnostics
// This test case was reported in <rdar:problem/6080742>.
// It tests path-sensitivity with respect to '!(cfstring != 0)' (negation of inequality).
diff --git a/test/Analysis/chroot.c b/test/Analysis/chroot.c
index 1948f48471f1..1b818a8e6322 100644
--- a/test/Analysis/chroot.c
+++ b/test/Analysis/chroot.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Chroot -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.Chroot -analyzer-store region -verify %s
extern int chroot(const char* path);
extern int chdir(const char* path);
diff --git a/test/Analysis/comparison-implicit-casts.cpp b/test/Analysis/comparison-implicit-casts.cpp
index df9d8700099e..96aa0ffe16b4 100644
--- a/test/Analysis/comparison-implicit-casts.cpp
+++ b/test/Analysis/comparison-implicit-casts.cpp
@@ -1,5 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-constraints=basic -triple i386-apple-darwin9 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-constraints=basic -triple x86_64-apple-darwin9 -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-constraints=range -triple i386-apple-darwin9 -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-constraints=range -triple x86_64-apple-darwin9 -verify %s
diff --git a/test/Analysis/complex-init-list.cpp b/test/Analysis/complex-init-list.cpp
new file mode 100644
index 000000000000..bbff64b7a13f
--- /dev/null
+++ b/test/Analysis/complex-init-list.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// expected-no-diagnostics
+
+// Do not crash on initialization to complex numbers.
+void init_complex() {
+ _Complex float valid1 = { 0.0f, 0.0f };
+}
diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c
index c118a61455af..3900bcbfae68 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
#include <stdint.h>
diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c
index f6c445ebf56e..819afca967c9 100644
--- a/test/Analysis/concrete-address.c
+++ b/test/Analysis/concrete-address.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// expected-no-diagnostics
void foo() {
int *p = (int*) 0x10000; // Should not crash here.
diff --git a/test/Analysis/conditional-operator-path-notes.c b/test/Analysis/conditional-operator-path-notes.c
new file mode 100644
index 000000000000..de313a7f5f6f
--- /dev/null
+++ b/test/Analysis/conditional-operator-path-notes.c
@@ -0,0 +1,1083 @@
+// RUN: %clang --analyze %s -Xanalyzer -analyzer-output=text -Xclang -verify
+// RUN: %clang --analyze %s -o %t
+// RUN: FileCheck --input-file=%t %s
+
+void testCondOp(int *p) {
+ int *x = p ? p : p;
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{'?' condition is false}}
+ // expected-note@-3 {{Variable 'x' initialized to a null pointer value}}
+ *x = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void testCondProblem(int *p) {
+ if (p) return;
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{Taking false branch}}
+
+ int x = *p ? 0 : 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}}
+ (void)x;
+}
+
+void testLHSProblem(int *p) {
+ int x = !p ? *p : 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{'?' condition is true}}
+ // expected-note@-3 {{Dereference of null pointer (loaded from variable 'p')}}
+ (void)x;
+}
+
+void testRHSProblem(int *p) {
+ int x = p ? 1 : *p; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{'?' condition is false}}
+ // expected-note@-3 {{Dereference of null pointer (loaded from variable 'p')}}
+ (void)x;
+}
+
+void testBinaryCondOp(int *p) {
+ int *x = p ?: p;
+ // expected-note@-1 {{'?' condition is false}}
+ // expected-note@-2 {{Variable 'x' initialized to a null pointer value}}
+ *x = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void testBinaryLHSProblem(int *p) {
+ if (p) return;
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{Taking false branch}}
+
+ int x = *p ?: 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}}
+ (void)x;
+}
+
+// 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>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>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>6</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>6</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>6</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>6</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>6</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;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>6</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>6</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>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>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>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>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>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>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>6</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>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>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>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;x&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>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>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>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>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>10</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>10</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>10</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;x&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;x&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;x&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>testCondOp</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>15</integer>
+// CHECK-NEXT: <key>col</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>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>15</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>15</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>15</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>15</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>15</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 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>15</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>15</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>19</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>19</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>19</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>19</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>19</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>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>testCondProblem</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>25</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>25</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>25</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>25</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>25</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;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>25</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>25</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>25</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>25</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>25</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>25</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>25</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>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>testLHSProblem</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>11</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>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>33</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>33</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>33</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;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>33</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>33</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>33</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>33</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>33</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>33</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>33</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>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>testRHSProblem</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</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>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>41</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>41</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>41</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>41</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>41</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>41</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>41</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>41</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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>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>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>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;x&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>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>4</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>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;x&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;x&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;x&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>testBinaryCondOp</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// 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: </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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</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>49</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>49</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>49</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>49</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>49</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 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>49</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>49</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>53</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>53</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>53</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>53</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>53</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>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>testBinaryLHSProblem</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</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: </array>
diff --git a/test/Analysis/coverage.c b/test/Analysis/coverage.c
index 811691391eb1..66f0a5e385b9 100644
--- a/test/Analysis/coverage.c
+++ b/test/Analysis/coverage.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -analyzer-max-loop 4 -verify %s
-#include "system-header-simulator.h"
+#include "Inputs/system-header-simulator.h"
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/cstring-syntax-cxx.cpp b/test/Analysis/cstring-syntax-cxx.cpp
index f8975abc185b..bae3d0a16423 100644
--- a/test/Analysis/cstring-syntax-cxx.cpp
+++ b/test/Analysis/cstring-syntax-cxx.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -verify %s
+// expected-no-diagnostics
// Ensure we don't crash on C++ declarations with special names.
struct X {
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor-inlining.mm
index fe4781c16e28..ac963e5d9b09 100644
--- a/test/Analysis/ctor-inlining.mm
+++ b/test/Analysis/ctor-inlining.mm
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -Wno-null-dereference -verify %s
void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
struct Wrapper {
__strong id obj;
@@ -86,4 +87,33 @@ namespace ConstructorVirtualCalls {
}
}
+namespace TemporaryConstructor {
+ class BoolWrapper {
+ public:
+ BoolWrapper() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ value = true;
+ }
+ bool value;
+ };
+
+ void test() {
+ // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined.
+ if (BoolWrapper().value)
+ return;
+ }
+}
+
+namespace ConstructorUsedAsRValue {
+ using TemporaryConstructor::BoolWrapper;
+
+ bool extractValue(BoolWrapper b) {
+ return b.value;
+ }
+
+ void test() {
+ bool result = extractValue(BoolWrapper());
+ clang_analyzer_eval(result); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/cxx-crashes.cpp b/test/Analysis/cxx-crashes.cpp
index 8912bf68de3f..e3f812540d0b 100644
--- a/test/Analysis/cxx-crashes.cpp
+++ b/test/Analysis/cxx-crashes.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
+// REQUIRES: LP64
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/cxx-method-names.cpp b/test/Analysis/cxx-method-names.cpp
index 8afbb85c1730..21be5e4bd3f4 100644
--- a/test/Analysis/cxx-method-names.cpp
+++ b/test/Analysis/cxx-method-names.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,osx,experimental.unix,experimental.security.taint -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,osx,alpha.unix,alpha.security.taint -analyzer-store region -verify %s
+// expected-no-diagnostics
class Evil {
public:
diff --git a/test/Analysis/cxx11-crashes.cpp b/test/Analysis/cxx11-crashes.cpp
index 16bfc891000f..d0b9222b6a66 100644
--- a/test/Analysis/cxx11-crashes.cpp
+++ b/test/Analysis/cxx11-crashes.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -std=c++11 -verify %s
+// expected-no-diagnostics
// radar://11485149, PR12871
class PlotPoint {
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index b8d195d05a76..165a12b59b1f 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
void f1() {
int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 43d8796ce091..86d84f0fbfa4 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
//===----------------------------------------------------------------------===//
@@ -110,3 +109,43 @@ namespace foo {
}
}
+//===----------------------------------------------------------------------===//
+// Dead stores in with EH code.
+//===----------------------------------------------------------------------===//
+
+void test_5_Aux();
+int test_5() {
+ int x = 0;
+ try {
+ x = 2; // no-warning
+ test_5_Aux();
+ }
+ catch (int z) {
+ return x + z;
+ }
+ return 1;
+}
+
+
+int test_6_aux(unsigned x);
+
+void test_6() {
+ unsigned currDestLen = 0; // no-warning
+ try {
+ while (test_6_aux(currDestLen)) {
+ currDestLen += 2; // no-warning
+ }
+ }
+ catch (void *) {}
+}
+
+void test_6b() {
+ unsigned currDestLen = 0; // no-warning
+ try {
+ while (test_6_aux(currDestLen)) {
+ currDestLen += 2; // expected-warning {{Value stored to 'currDestLen' is never read}}
+ break;
+ }
+ }
+ catch (void *) {}
+}
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
index fe565547e12a..5a807ed52c99 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
index 7fc4f2bb9616..28e9006c18e5 100644
--- a/test/Analysis/delegates.m
+++ b/test/Analysis/delegates.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -Wno-objc-root-class -verify %s
+// expected-no-diagnostics
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index f8336785de8f..30e7a3127ba2 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.c b/test/Analysis/diagnostics/deref-track-symbolic-region.c
new file mode 100644
index 000000000000..3ba2707f1aec
--- /dev/null
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.c
@@ -0,0 +1,354 @@
+// 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 - | FileCheck %s
+
+struct S {
+ int *x;
+ int y;
+};
+
+int *foo();
+
+void inlined(struct S *s, int m) {
+ if (s->x)
+ //expected-note@-1{{Taking false branch}}
+ //expected-note@-2{{Assuming pointer value is null}}
+
+ m++;
+
+}
+void test(struct S syz, int *pp) {
+ int m = 0;
+ syz.x = foo();
+ inlined(&syz, m);
+ // expected-note@-1{{Calling 'inlined'}}
+ // expected-note@-2{{Returning from 'inlined'}}
+ m += *syz.x; // expected-warning{{Dereference of null pointer (loaded from field 'x')}}
+ // expected-note@-1{{Dereference of null pointer (loaded from field 'x')}}
+}
+
+//CHECK: <dict>
+//CHECK: <key>files</key>
+//CHECK: <array>
+//CHECK: </array>
+//CHECK: <key>diagnostics</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>path</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>20</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>20</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>18</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Calling &apos;inlined&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Calling &apos;inlined&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>1</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Entered call from &apos;test&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Entered call from &apos;test&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>1</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>4</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>4</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>4</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>7</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>7</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>7</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>7</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>12</integer>
+//CHECK: <key>col</key><integer>10</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Assuming pointer value is null</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Assuming pointer value is null</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>18</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Returning from &apos;inlined&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Returning from &apos;inlined&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>22</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>13</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>13</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+//CHECK: <key>category</key><string>Logic error</string>
+//CHECK: <key>type</key><string>Dereference of null pointer</string>
+//CHECK: <key>issue_context_kind</key><string>function</string>
+//CHECK: <key>issue_context</key><string>test</string>
+//CHECK: <key>issue_hash</key><integer>6</integer>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>25</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </plist>
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
new file mode 100644
index 000000000000..fb493d7c93ae
--- /dev/null
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+
+struct S {
+ int *x;
+ int y;
+};
+
+S &getSomeReference();
+void test(S *p) {
+ S &r = *p; //expected-note {{Variable 'r' initialized here}}
+ if (p) return;
+ //expected-note@-1{{Taking false branch}}
+ //expected-note@-2{{Assuming 'p' is null}}
+ r.y = 5; // expected-warning {{Access to field 'y' results in a dereference of a null pointer (loaded from variable 'r')}}
+ // expected-note@-1{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 'r')}}
+}
diff --git a/test/Analysis/diagnostics/undef-value-caller.c b/test/Analysis/diagnostics/undef-value-caller.c
index 928839d0404d..627b334971b6 100644
--- a/test/Analysis/diagnostics/undef-value-caller.c
+++ b/test/Analysis/diagnostics/undef-value-caller.c
@@ -4,235 +4,162 @@
#include "undef-value-callee.h"
// This code used to cause a crash since we were not adding fileID of the header to the plist diagnostic.
-// Note, in the future, we do not even need to step into this callee since it does not influence the result.
+
int test_calling_unimportant_callee(int argc, char *argv[]) {
int x;
callee();
return x; // expected-warning {{Undefined or garbage value returned to caller}}
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: </array>
-// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;callee&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;callee&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>2</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>1</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;test_calling_unimportant_callee&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;test_calling_unimportant_callee&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returning from &apos;callee&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returning from &apos;callee&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Undefined or garbage value returned to caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Undefined or garbage value returned to caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Undefined or garbage value returned to caller</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Garbage return value</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_calling_unimportant_callee</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+//CHECK: <dict>
+//CHECK: <key>files</key>
+//CHECK: <array>
+//CHECK: </array>
+//CHECK: <key>diagnostics</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>path</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>9</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>9</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>9</integer>
+//CHECK: <key>col</key><integer>7</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>9</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>9</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>10</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>10</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>10</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>10</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>8</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>10</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>10</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Undefined or garbage value returned to caller</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Undefined or garbage value returned to caller</string>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>description</key><string>Undefined or garbage value returned to caller</string>
+//CHECK: <key>category</key><string>Logic error</string>
+//CHECK: <key>type</key><string>Garbage return value</string>
+//CHECK: <key>issue_context_kind</key><string>function</string>
+//CHECK: <key>issue_context</key><string>test_calling_unimportant_callee</string>
+//CHECK: <key>issue_hash</key><integer>3</integer>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>11</integer>
+//CHECK: <key>col</key><integer>3</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </plist>
diff --git a/test/Analysis/diagnostics/undef-value-param.c b/test/Analysis/diagnostics/undef-value-param.c
new file mode 100644
index 000000000000..88d87cfdced3
--- /dev/null
+++ b/test/Analysis/diagnostics/undef-value-param.c
@@ -0,0 +1,1183 @@
+// 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 - | FileCheck %s
+
+void foo_irrelevant(int c) {
+ if (c)
+ return;
+ c++;
+ return;
+}
+void foo(int c, int *x) {
+ if (c)
+ //expected-note@-1{{Assuming 'c' is not equal to 0}}
+ //expected-note@-2{{Taking true branch}}
+ return;
+ *x = 5;
+}
+
+int use(int c) {
+ int xx; //expected-note{{Variable 'xx' declared without an initial value}}
+ int *y = &xx;
+ foo (c, y);
+ //expected-note@-1{{Calling 'foo'}}
+ //expected-note@-2{{Returning from 'foo'}}
+ foo_irrelevant(c);
+ return xx+3; //expected-warning{{The left operand of '+' is a garbage value}}
+ //expected-note@-1{{The left operand of '+' is a garbage value}}
+}
+
+void initArray(int x, double XYZ[3]) {
+ if (x <= 0) //expected-note {{Taking true branch}}
+ //expected-note@-1 {{Assuming 'x' is <= 0}}
+ return;
+ XYZ[0] = 1;
+ XYZ[1] = 1;
+ XYZ[2] = 1;
+}
+int testPassingParentRegionArray(int x) {
+ double XYZ[3];
+ initArray(x, XYZ); //expected-note {{Calling 'initArray'}}
+ //expected-note@-1 {{Returning from 'initArray'}}
+ return 1 * XYZ[1]; //expected-warning {{The right operand of '*' is a garbage value}}
+ //expected-note@-1 {{The right operand of '*' is a garbage value}}
+}
+
+double *getValidPtr();
+struct WithFields {
+ double *f1;
+};
+void initStruct(int x, struct WithFields *X) {
+ if (x <= 0) //expected-note {{Taking true branch}}
+ //expected-note@-1 {{Assuming 'x' is <= 0}}
+
+ return;
+ X->f1 = getValidPtr();
+}
+double testPassingParentRegionStruct(int x) {
+ struct WithFields st;
+ st.f1 = 0;
+ initStruct(x, &st); //expected-note {{Calling 'initStruct'}}
+ //expected-note@-1 {{Returning from 'initStruct'}}
+ return (*st.f1); //expected-warning {{Dereference of null pointer}}
+ //expected-note@-1{{Dereference of null pointer (loaded from field 'f1')}}
+}
+
+// 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>19</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>19</integer>
+// 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>19</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>Variable &apos;xx&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;xx&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>19</integer>
+// 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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
+// 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>21</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>21</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>21</integer>
+// 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>21</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;foo&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;foo&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>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;use&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use&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>0</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>0</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>11</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>11</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>11</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>11</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>11</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;c&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;c&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>11</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>11</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>14</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>14</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>21</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>21</integer>
+// 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>21</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;foo&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;foo&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>5</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>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>24</integer>
+// 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>24</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>24</integer>
+// 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>24</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>25</integer>
+// 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>25</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>25</integer>
+// 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>25</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>25</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>25</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>25</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>25</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>25</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>The left operand of &apos;+&apos; is a garbage value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The left operand of &apos;+&apos; is a garbage value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The left operand of &apos;+&apos; is a garbage value</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Result of operation is garbage or undefined</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>use</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</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: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>39</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>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>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>Calling &apos;initArray&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;initArray&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>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;testPassingParentRegionArray&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testPassingParentRegionArray&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>0</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>0</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>5</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>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>30</integer>
+// 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>30</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>30</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>30</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>30</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>30</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>30</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 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>9</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>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>32</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>32</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</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>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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;initArray&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;initArray&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>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>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>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>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>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>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>41</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>41</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>41</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>41</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>41</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>The right operand of &apos;*&apos; is a garbage value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The right operand of &apos;*&apos; is a garbage value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The right operand of &apos;*&apos; is a garbage value</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Result of operation is garbage or undefined</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testPassingParentRegionArray</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</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: <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>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>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>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>59</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>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>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>Calling &apos;initStruct&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;initStruct&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>49</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;testPassingParentRegionStruct&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testPassingParentRegionStruct&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>49</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>49</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>50</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>50</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>50</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>50</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>50</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>Assuming &apos;x&apos; is &lt;= 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 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>50</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>50</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>53</integer>
+// 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>53</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>59</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>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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;initStruct&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;initStruct&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>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>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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</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>61</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>61</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>61</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>Dereference of null pointer (loaded from field &apos;f1&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;f1&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from field &apos;f1&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>testPassingParentRegionStruct</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</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/undef-value-param.m b/test/Analysis/diagnostics/undef-value-param.m
new file mode 100644
index 000000000000..d2a7a087b8c7
--- /dev/null
+++ b/test/Analysis/diagnostics/undef-value-param.m
@@ -0,0 +1,476 @@
+// 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 - | FileCheck %s
+
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+typedef const void * CFTypeRef;
+extern void CFRelease(CFTypeRef cf);
+
+@interface Cell : NSObject
+- (void)test;
+@end
+
+@interface SpecialString
++ (id)alloc;
+- (oneway void)release;
+@end
+
+typedef SpecialString* SCDynamicStoreRef;
+static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x);
+SCDynamicStoreRef anotherCreateRef(unsigned *err, unsigned x);
+
+@implementation Cell
+- (void) test {
+ SCDynamicStoreRef storeRef = 0; //expected-note{{Variable 'storeRef' initialized to nil}}
+ CreateRef(&storeRef, 4);
+ //expected-note@-1{{Calling 'CreateRef'}}
+ //expected-note@-2{{Returning from 'CreateRef'}}
+ CFRelease(storeRef); //expected-warning {{Null pointer argument in call to CFRelease}}
+ //expected-note@-1{{Null pointer argument in call to CFRelease}}
+}
+@end
+
+static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x) {
+ unsigned err = 0;
+ SCDynamicStoreRef ref = anotherCreateRef(&err, x); // why this is being inlined?
+ if (err) {
+ //expected-note@-1{{Assuming 'err' is not equal to 0}}
+ //expected-note@-2{{Taking true branch}}
+ CFRelease(ref);
+ ref = 0;
+ }
+ *storeRef = ref;
+}
+
+//CHECK: <dict>
+//CHECK: <key>files</key>
+//CHECK: <array>
+//CHECK: </array>
+//CHECK: <key>diagnostics</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>path</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>33</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>33</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>33</integer>
+//CHECK: <key>col</key><integer>30</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Variable &apos;storeRef&apos; initialized to nil</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Variable &apos;storeRef&apos; initialized to nil</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>33</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>33</integer>
+//CHECK: <key>col</key><integer>21</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>13</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>27</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Calling &apos;CreateRef&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Calling &apos;CreateRef&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>42</integer>
+//CHECK: <key>col</key><integer>1</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Entered call from &apos;test&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Entered call from &apos;test&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>42</integer>
+//CHECK: <key>col</key><integer>1</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>42</integer>
+//CHECK: <key>col</key><integer>6</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>43</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>43</integer>
+//CHECK: <key>col</key><integer>12</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>43</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>43</integer>
+//CHECK: <key>col</key><integer>12</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>6</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>6</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>11</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>11</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Assuming &apos;err&apos; is not equal to 0</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Assuming &apos;err&apos; is not equal to 0</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>45</integer>
+//CHECK: <key>col</key><integer>11</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>48</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>48</integer>
+//CHECK: <key>col</key><integer>17</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>48</integer>
+//CHECK: <key>col</key><integer>9</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>48</integer>
+//CHECK: <key>col</key><integer>17</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>51</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>51</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>27</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>1</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Returning from &apos;CreateRef&apos;</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Returning from &apos;CreateRef&apos;</string>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>control</string>
+//CHECK: <key>edges</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>start</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>34</integer>
+//CHECK: <key>col</key><integer>13</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>end</key>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>13</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>kind</key><string>event</string>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <key>ranges</key>
+//CHECK: <array>
+//CHECK: <array>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>15</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>22</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </array>
+//CHECK: <key>depth</key><integer>0</integer>
+//CHECK: <key>extended_message</key>
+//CHECK: <string>Null pointer argument in call to CFRelease</string>
+//CHECK: <key>message</key>
+//CHECK: <string>Null pointer argument in call to CFRelease</string>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: <key>description</key><string>Null pointer argument in call to CFRelease</string>
+//CHECK: <key>category</key><string>API Misuse (Apple)</string>
+//CHECK: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
+//CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
+//CHECK: <key>issue_context</key><string>test</string>
+//CHECK: <key>issue_hash</key><integer>5</integer>
+//CHECK: <key>location</key>
+//CHECK: <dict>
+//CHECK: <key>line</key><integer>37</integer>
+//CHECK: <key>col</key><integer>5</integer>
+//CHECK: <key>file</key><integer>0</integer>
+//CHECK: </dict>
+//CHECK: </dict>
+//CHECK: </array>
+//CHECK: </dict>
+//CHECK: </plist>
diff --git a/test/Analysis/domtest.c b/test/Analysis/domtest.c
index 0f370db5c132..dd72117f8c95 100644
--- a/test/Analysis/domtest.c
+++ b/test/Analysis/domtest.c
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang -cc1 -analyze -analyzer-checker=debug.DumpDominators %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpDominators %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// Test the DominatorsTree implementation with various control flows
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index 1f45925561c9..f46194599d4e 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
class A {
public:
@@ -102,7 +103,7 @@ void testMultipleInheritance3() {
// Remove dead bindings...
doSomething();
// destructor called here
- // expected-warning@27 {{Attempt to free released memory}}
+ // expected-warning@28 {{Attempt to free released memory}}
}
}
@@ -227,3 +228,76 @@ namespace DestructorVirtualCalls {
clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
}
}
+
+
+namespace DestructorsShouldNotAffectReturnValues {
+ class Dtor {
+ public:
+ ~Dtor() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+ };
+
+ void *allocate() {
+ Dtor d;
+ return malloc(4); // no-warning
+ }
+
+ void test() {
+ // At one point we had an issue where the statements inside an
+ // inlined destructor kept us from finding the return statement,
+ // leading the analyzer to believe that the malloc'd memory had leaked.
+ void *p = allocate();
+ free(p); // no-warning
+ }
+}
+
+namespace MultipleInheritanceVirtualDtors {
+ class VirtualDtor {
+ protected:
+ virtual ~VirtualDtor() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+ };
+
+ class NonVirtualDtor {
+ protected:
+ ~NonVirtualDtor() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+ };
+
+ class SubclassA : public VirtualDtor, public NonVirtualDtor {
+ public:
+ virtual ~SubclassA() {}
+ };
+ class SubclassB : public NonVirtualDtor, public VirtualDtor {
+ public:
+ virtual ~SubclassB() {}
+ };
+
+ void test() {
+ SubclassA a;
+ SubclassB b;
+ }
+}
+
+namespace ExplicitDestructorCall {
+ class VirtualDtor {
+ public:
+ virtual ~VirtualDtor() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ }
+ };
+
+ class Subclass : public VirtualDtor {
+ public:
+ virtual ~Subclass() {
+ clang_analyzer_checkInlined(false); // no-warning
+ }
+ };
+
+ void destroy(Subclass *obj) {
+ obj->VirtualDtor::~VirtualDtor();
+ }
+}
diff --git a/test/Analysis/dtors-in-dtor-cfg-output.cpp b/test/Analysis/dtors-in-dtor-cfg-output.cpp
index 68ba37ebf399..f0546fc8bffa 100644
--- a/test/Analysis/dtors-in-dtor-cfg-output.cpp
+++ b/test/Analysis/dtors-in-dtor-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
// XPASS: *
class A {
diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c
index 7452a0a124fe..1b2681181b40 100644
--- a/test/Analysis/elementtype.c
+++ b/test/Analysis/elementtype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region %s
typedef struct added_obj_st {
int type;
diff --git a/test/Analysis/engine/replay-without-inlining.c b/test/Analysis/engine/replay-without-inlining.c
index 9ec2d08f3993..06029731694b 100644
--- a/test/Analysis/engine/replay-without-inlining.c
+++ b/test/Analysis/engine/replay-without-inlining.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -verify %s
+// expected-no-diagnostics
typedef struct {
char I[4];
diff --git a/test/Analysis/exceptions.mm b/test/Analysis/exceptions.mm
new file mode 100644
index 000000000000..dab1b5e8c9c8
--- /dev/null
+++ b/test/Analysis/exceptions.mm
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -analyze -fexceptions -fobjc-exceptions -fcxx-exceptions -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
+
+void clang_analyzer_checkInlined(bool);
+
+typedef typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+
+id getException();
+void inlinedObjC() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ @throw getException();
+}
+
+int testObjC() {
+ int a; // uninitialized
+ void *mem = malloc(4); // no-warning (ObjC exceptions are usually fatal)
+ inlinedObjC();
+ free(mem);
+ return a; // no-warning
+}
+
+
+void inlinedCXX() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ throw -1;
+}
+
+int testCXX() {
+ int a; // uninitialized
+ // FIXME: this should be reported as a leak, because C++ exceptions are
+ // often not fatal.
+ void *mem = malloc(4);
+ inlinedCXX();
+ free(mem);
+ return a; // no-warning
+}
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index b592c330e601..675dd4ebf612 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
//
// Just exercise the analyzer on code that has at one point caused issues
// (i.e., no assertions or crashes).
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index 2e72c77d9fac..12e8bbf3671c 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
+
+void clang_analyzer_eval(int);
unsigned foo();
typedef struct bf { unsigned x:2; } bf;
@@ -26,3 +28,11 @@ void test() {
Point p;
(void)(p = getit()).x;
}
+
+
+void testLazyCompoundVal() {
+ Point p = {42, 0};
+ Point q;
+ clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index f688db7fb8dd..0b283ee5d4aa 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.unix.MallocWithAnnotations -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,alpha.unix.MallocWithAnnotations -fblocks -verify %s
void free(void *);
void t1 () {
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index 709ebf779376..9abb560e7583 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
index 71a7285e1f1d..2d64b49a8baf 100644
--- a/test/Analysis/global-region-invalidation.c
+++ b/test/Analysis/global-region-invalidation.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,alpha.security.taint,debug.TaintTest,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
// Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header.
-#include "system-header-simulator.h"
+#include "Inputs/system-header-simulator.h"
// Test that system header does not invalidate the internal global.
int size_rdar9373039 = 1;
diff --git a/test/Analysis/idempotent-operations-limited-loops.c b/test/Analysis/idempotent-operations-limited-loops.c
index 71e7c27b6ce3..c8c51cf87a58 100644
--- a/test/Analysis/idempotent-operations-limited-loops.c
+++ b/test/Analysis/idempotent-operations-limited-loops.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,alpha.deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,alpha.deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,alpha.deadcode.IdempotentOperations %s -verify
void always_warning() { int *p = 0; *p = 0xDEADBEEF; } // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
diff --git a/test/Analysis/idempotent-operations.c b/test/Analysis/idempotent-operations.c
index 6cc9a01b77ae..04c9bc1893e8 100644
--- a/test/Analysis/idempotent-operations.c
+++ b/test/Analysis/idempotent-operations.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=alpha.deadcode.IdempotentOperations -verify %s
// Basic tests
@@ -234,3 +234,11 @@ void rdar8601243() {
(void) start;
}
+
+float testFloatCast(int i) {
+ float f = i;
+
+ // Don't crash when trying to create a "zero" float.
+ return f - f;
+}
+
diff --git a/test/Analysis/idempotent-operations.cpp b/test/Analysis/idempotent-operations.cpp
index 51b590566adf..966366568e23 100644
--- a/test/Analysis/idempotent-operations.cpp
+++ b/test/Analysis/idempotent-operations.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=alpha.deadcode.IdempotentOperations -verify %s
// C++ specific false positives
diff --git a/test/Analysis/idempotent-operations.m b/test/Analysis/idempotent-operations.m
index 9a9820c3b2a4..306376dd5757 100644
--- a/test/Analysis/idempotent-operations.m
+++ b/test/Analysis/idempotent-operations.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=alpha.deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
typedef unsigned long NSUInteger;
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index d43c8cfd9a0a..92d581b82a31 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -cfg-add-implicit-dtors -std=c++11 -verify %s
-
-// We don't inline constructors unless we have destructors turned on.
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
void clang_analyzer_eval(bool);
@@ -57,10 +55,6 @@ void testDelegatingConstructor() {
}
-// ------------------------------------
-// False negatives
-// ------------------------------------
-
struct RefWrapper {
RefWrapper(int *p) : x(*p) {}
RefWrapper(int &r) : x(r) {}
@@ -69,10 +63,20 @@ struct RefWrapper {
void testReferenceMember() {
int *p = 0;
- RefWrapper X(p); // should warn in the constructor
+ RefWrapper X(p); // expected-warning@-7 {{Dereference of null pointer}}
}
void testReferenceMember2() {
int *p = 0;
- RefWrapper X(*p); // should warn here
+ // FIXME: We should warn here, since we're creating the reference here.
+ RefWrapper X(*p); // expected-warning@-12 {{Dereference of null pointer}}
}
+
+
+extern "C" char *strdup(const char *);
+
+class StringWrapper {
+ char *str;
+public:
+ StringWrapper(const char *input) : str(strdup(input)) {} // no-warning
+};
diff --git a/test/Analysis/inline-not-supported.c b/test/Analysis/inline-not-supported.c
index bff0e4d0b22c..756d5d8b8dbf 100644
--- a/test/Analysis/inline-not-supported.c
+++ b/test/Analysis/inline-not-supported.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -verify %s
// For now, don't inline varargs.
void foo(int *x, ...) {
@@ -16,7 +16,7 @@ void taz() {
baz(0, 2); // no-warning
}
-// For now, don't inline blocks.
+// For now, don't inline global blocks.
void (^qux)(int *p) = ^(int *p) { *p = 1; };
void test_qux() {
qux(0); // no-warning
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index 1523e82cc2ea..999ebdbd3ab9 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -1,40 +1,53 @@
-// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -fblocks -o %t
+// 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: FileCheck -input-file %t %s
// <rdar://problem/10967815>
void mmm(int y) {
if (y != 0)
- y++;
+ y++;
}
int foo(int x, int y) {
- mmm(y);
- if (x != 0)
- x++;
- return 5/x;
+ mmm(y);
+ if (x != 0) {
+ // expected-note@-1 {{Assuming 'x' is equal to 0}}
+ // expected-note@-2 {{Taking false branch}}
+ x++;
+ }
+ return 5/x; // expected-warning{{Division by zero}} expected-note{{Division by zero}}
}
// Test a bug triggering only when inlined.
void has_bug(int *p) {
- *p = 0xDEADBEEF;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}
void test_has_bug() {
has_bug(0);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling 'has_bug'}}
}
void triggers_bug(int *p) {
- *p = 0xDEADBEEF;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}
// This function triggers a bug by calling triggers_bug(). The diagnostics
// should show when p is assumed to be null.
void bar(int *p) {
- if (!!p)
+ if (!!p) {
+ // expected-note@-1 {{Assuming 'p' is null}}
+ // expected-note@-2 {{Taking false branch}}
return;
+ }
- if (p == 0)
+ if (p == 0) {
+ // expected-note@-1 {{Taking true branch}}
triggers_bug(p);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling 'triggers_bug'}}
+ }
}
// ========================================================================== //
@@ -42,1148 +55,1841 @@ void bar(int *p) {
// ========================================================================== //
void test_block__capture_null() {
- int *p = 0;
- ^(){ *p = 1; }();
+ int *p = 0; // expected-note{{Variable 'p' initialized to a null pointer value}}
+ ^(){ // expected-note {{Calling anonymous block}}
+ *p = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
+ }();
+
}
void test_block_ret() {
- int *p = ^(){ int *q = 0; return q; }();
- *p = 1;
+ int *p = ^(){ // expected-note {{Calling anonymous block}} expected-note{{Returning to caller}} expected-note {{Variable 'p' initialized to a null pointer value}}
+ int *q = 0; // expected-note {{Variable 'q' initialized to a null pointer value}}
+ return q; // expected-note {{Returning null pointer (loaded from 'q')}}
+ }();
+ *p = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}
void test_block_blockvar() {
__block int *p;
- ^(){ p = 0; }();
- *p = 1;
+ ^(){ // expected-note{{Calling anonymous block}} expected-note{{Returning to caller}}
+ p = 0; // expected-note{{Null pointer value stored to 'p'}}
+ }();
+ *p = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}
void test_block_arg() {
int *p;
- ^(int **q){ *q = 0; }(&p);
- *p = 1;
+ ^(int **q){ // expected-note{{Calling anonymous block}} expected-note{{Returning to caller}}
+ *q = 0; // expected-note{{Null pointer value stored to 'p'}}
+ }(&p);
+ *p = 1; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}} expected-note{{Dereference of null pointer (loaded from variable 'p')}}
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;x&apos; is equal to 0</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;x&apos; is equal to 0</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Division by zero</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Division by zero</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Division by zero</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Division by zero</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>foo</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;has_bug&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;has_bug&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;test_has_bug&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;test_has_bug&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>has_bug</string>
-// CHECK: <key>issue_hash</key><integer>1</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>16</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;triggers_bug&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;triggers_bug&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;bar&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;bar&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>triggers_bug</string>
-// CHECK: <key>issue_hash</key><integer>1</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling anonymous block</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling anonymous block</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;test_block__capture_null&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;test_block__capture_null&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_block_ret</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_block_blockvar</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>62</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>62</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>62</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>62</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_block_arg</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>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>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>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>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>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>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>13</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>13</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>13</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>13</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>13</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;x&apos; is equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&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>13</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>13</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>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>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>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>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>18</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>18</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>18</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>18</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>18</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>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>foo</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>18</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>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>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>27</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>27</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>27</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>27</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>27</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>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &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>27</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Calling &apos;has_bug&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;has_bug&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;test_has_bug&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_has_bug&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>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>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>4</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>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;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>has_bug</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// 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: </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>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>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>39</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>39</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>39</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>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>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>47</integer>
+// 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>47</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>47</integer>
+// 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>47</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>47</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>47</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>47</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</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>47</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>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &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>47</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>47</integer>
+// 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>47</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;triggers_bug&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;triggers_bug&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>32</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;bar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;bar&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>32</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>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>3</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>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>33</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>33</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>33</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;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>triggers_bug</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// 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>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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</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_block__capture_null&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_block__capture_null&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>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>60</integer>
+// 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>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>60</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>60</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>60</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>1</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// 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>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>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>12</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>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>66</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>66</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>69</integer>
+// 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>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>66</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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_block_ret&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_block_ret&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>66</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>66</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>67</integer>
+// 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>67</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>67</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>67</integer>
+// 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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>67</integer>
+// 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>67</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>5</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>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>68</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>68</integer>
+// 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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &apos;q&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &apos;q&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>66</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>66</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>69</integer>
+// 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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning to caller</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>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>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>12</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>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>66</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>66</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>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>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>66</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>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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>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>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>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>70</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>70</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>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: </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_block_ret</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>74</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>75</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>75</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>75</integer>
+// CHECK-NEXT: <key>col</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>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>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>75</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_block_blockvar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_block_blockvar&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>3</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>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>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>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>76</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>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>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>1</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>75</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>75</integer>
+// CHECK-NEXT: <key>col</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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning to caller</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>3</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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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_block_blockvar</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</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_block_arg&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_block_arg&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>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>84</integer>
+// 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>84</integer>
+// 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>84</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>84</integer>
+// 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>84</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning to caller</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>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>86</integer>
+// CHECK-NEXT: <key>col</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>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>86</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>86</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>86</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_block_arg</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>86</integer>
+// 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/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
index 9248ad2632f5..356ab7211412 100644
--- a/test/Analysis/inline-unique-reports.c
+++ b/test/Analysis/inline-unique-reports.c
@@ -1,4 +1,4 @@
-// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t > /dev/null 2>&1
+// RUN: %clang --analyze %s -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 944e1e2985f1..8cba63f17e0d 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_checkInlined(int);
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index 6b9a885f50f3..ddcf5d01c34c 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -1,8 +1,18 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
+typedef __typeof__(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+
+// This is the standard placement new.
+inline void* operator new(size_t, void* __p) throw()
+{
+ return __p;
+}
+
+
class A {
public:
int getZero() { return 0; }
@@ -193,3 +203,167 @@ namespace Invalidation {
}
};
}
+
+namespace DefaultArgs {
+ int takesDefaultArgs(int i = 42) {
+ return -i;
+ }
+
+ void testFunction() {
+ clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}}
+ }
+
+ class Secret {
+ public:
+ static const int value = 42;
+ int get(int i = value) {
+ return i;
+ }
+ };
+
+ void testMethod() {
+ Secret obj;
+ clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
+
+ // FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>.
+ clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
+
+ // FIXME: Even if we constrain the variable, we still have a problem.
+ // See PR13385 or <rdar://problem/12156507>.
+ if (Secret::value != 42)
+ return;
+ clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
+ }
+}
+
+namespace OperatorNew {
+ class IntWrapper {
+ public:
+ int value;
+
+ IntWrapper(int input) : value(input) {
+ // We don't want this constructor to be inlined unless we can actually
+ // use the proper region for operator new.
+ // See PR12014 and <rdar://problem/12180598>.
+ clang_analyzer_checkInlined(false); // no-warning
+ }
+ };
+
+ void test() {
+ IntWrapper *obj = new IntWrapper(42);
+ // should be TRUE
+ clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
+ }
+
+ void testPlacement() {
+ IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper)));
+ IntWrapper *alias = new (obj) IntWrapper(42);
+
+ clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}}
+
+ // should be TRUE
+ clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
+ }
+}
+
+
+namespace VirtualWithSisterCasts {
+ // This entire set of tests exercises casts from sister classes and
+ // from classes outside the hierarchy, which can very much confuse
+ // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions.
+ // These examples used to cause crashes in +Asserts builds.
+ struct Parent {
+ virtual int foo();
+ int x;
+ };
+
+ struct A : Parent {
+ virtual int foo() { return 42; }
+ };
+
+ struct B : Parent {
+ virtual int foo();
+ };
+
+ struct Grandchild : public A {};
+
+ struct Unrelated {};
+
+ void testDowncast(Parent *b) {
+ A *a = (A *)(void *)b;
+ clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+
+ a->x = 42;
+ clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
+ }
+
+ void testRelated(B *b) {
+ A *a = (A *)(void *)b;
+ clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+
+ a->x = 42;
+ clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
+ }
+
+ void testUnrelated(Unrelated *b) {
+ A *a = (A *)(void *)b;
+ clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
+
+ a->x = 42;
+ clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
+ }
+
+ void testCastViaNew(B *b) {
+ Grandchild *g = new (b) Grandchild();
+ // FIXME: We actually now have perfect type info because of 'new'.
+ // This should be TRUE.
+ clang_analyzer_eval(g->foo() == 42); // expected-warning{{UNKNOWN}}
+
+ g->x = 42;
+ clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}}
+ }
+}
+
+
+namespace QualifiedCalls {
+ void test(One *object) {
+ // This uses the One class from the top of the file.
+ clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}}
+
+ // getZero is non-virtual.
+ clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}}
+}
+}
+
+
+namespace rdar12409977 {
+ struct Base {
+ int x;
+ };
+
+ struct Parent : public Base {
+ virtual Parent *vGetThis();
+ Parent *getThis() { return vGetThis(); }
+ };
+
+ struct Child : public Parent {
+ virtual Child *vGetThis() { return this; }
+ };
+
+ void test() {
+ Child obj;
+ obj.x = 42;
+
+ // Originally, calling a devirtualized method with a covariant return type
+ // caused a crash because the return value had the wrong type. When we then
+ // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of
+ // the object region and we get an assertion failure.
+ clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index 473146c0be4b..bae7434518e2 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index 968d82acd6e1..e7f4775925a1 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
// Test when entering f1(), we set the right AnalysisDeclContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index e7715e01dda1..71a379a02c75 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
int g(int a) {
return a;
diff --git a/test/Analysis/inlining/DynDispatchBifurcate.m b/test/Analysis/inlining/DynDispatchBifurcate.m
index 6637dfdba571..1fffb6503680 100644
--- a/test/Analysis/inlining/DynDispatchBifurcate.m
+++ b/test/Analysis/inlining/DynDispatchBifurcate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
@@ -179,3 +179,13 @@ int testPropertySynthesized(PublicClass *p) {
[p setValue1:0];
return 5/[p value1];
}
+
+// Test definition not available edge case.
+@interface DefNotAvailClass : NSObject
+@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/InlineObjCInstanceMethod.m b/test/Analysis/inlining/InlineObjCInstanceMethod.m
index 31b6d5baa6f8..f6aa50a24802 100644
--- a/test/Analysis/inlining/InlineObjCInstanceMethod.m
+++ b/test/Analysis/inlining/InlineObjCInstanceMethod.m
@@ -1,15 +1,32 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s
#include "InlineObjCInstanceMethod.h"
+typedef const struct __CFString * CFStringRef;
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+extern CFStringRef getString(void);
+
// Method is defined in the parent; called through self.
@interface MyParent : NSObject
- (int)getInt;
+- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
@end
@implementation MyParent
- (int)getInt {
return 0;
}
+
+- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
+ CFStringRef Str = ((void*)0);
+ Str = getString();
+ if (Str) {
+ CFRetain(Str);
+ }
+ return Str;
+}
+
@end
@interface MyClass : MyParent
@@ -83,4 +100,49 @@
// Don't crash if we don't know the receiver's region.
void randomlyMessageAnObject(MyClass *arr[], int i) {
(void)[arr[i] getInt];
-} \ No newline at end of file
+}
+
+
+@interface EvilChild : MyParent
+- (id)getInt;
+- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained));
+@end
+
+@implementation EvilChild
+- (id)getInt { // expected-warning {{types are incompatible}}
+ return self;
+}
+- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) {
+ CFStringRef Str = ((void*)0);
+ Str = getString();
+ if (Str) {
+ CFRetain(Str);
+ }
+ return Str;
+}
+
+@end
+
+int testNonCovariantReturnType() {
+ MyParent *obj = [[EvilChild alloc] init];
+
+ // Devirtualization allows us to directly call -[EvilChild getInt], but
+ // that returns an id, not an int. There is an off-by-default warning for
+ // this, -Woverriding-method-mismatch, and an on-by-default analyzer warning,
+ // osx.cocoa.IncompatibleMethodTypes. This code would probably crash at
+ // runtime, but at least the analyzer shouldn't crash.
+ int x = 1 + [obj getInt];
+
+ [obj release];
+ return 5/(x-1); // no-warning
+}
+
+int testCovariantReturnTypeNoErrorSinceTypesMatch() {
+ MyParent *obj = [[EvilChild alloc] init];
+
+ CFStringRef S = ((void*)0);
+ S = [obj testCovariantReturnType];
+ if (S)
+ CFRelease(S);
+ CFRelease(obj);
+}
diff --git a/test/Analysis/inlining/RetainCountExamples.m b/test/Analysis/inlining/RetainCountExamples.m
index 2b682c2b4bf0..276ab5209517 100644
--- a/test/Analysis/inlining/RetainCountExamples.m
+++ b/test/Analysis/inlining/RetainCountExamples.m
@@ -15,6 +15,7 @@ typedef struct objc_object {
-(id)copy;
- (Class)class;
-(id)retain;
+- (oneway void)release;
@end
@interface SelfStaysLive : NSObject
@@ -30,4 +31,97 @@ typedef struct objc_object {
void selfStaysLive() {
SelfStaysLive *foo = [[SelfStaysLive alloc] init];
[foo release];
-} \ No newline at end of file
+}
+
+// Test that retain release checker warns on leaks and use-after-frees when
+// self init is not enabled.
+// radar://12115830
+@interface ParentOfCell : NSObject
+- (id)initWithInt: (int)inInt;
+@end
+@interface Cell : ParentOfCell{
+ int x;
+}
+- (id)initWithInt: (int)inInt;
++ (void)testOverRelease;
++ (void)testLeak;
+@property int x;
+@end
+@implementation Cell
+@synthesize x;
+- (id) initWithInt: (int)inInt {
+ [super initWithInt: inInt];
+ self.x = inInt; // no-warning
+ return self; // Self Init checker would produce a warning here.
+}
++ (void) testOverRelease {
+ Cell *sharedCell3 = [[Cell alloc] initWithInt: 3];
+ [sharedCell3 release];
+ [sharedCell3 release]; // expected-warning {{Reference-counted object is used after it is released}}
+}
++ (void) testLeak {
+ Cell *sharedCell4 = [[Cell alloc] initWithInt: 3]; // expected-warning {{leak}}
+}
+@end
+
+// We should stop tracking some objects even when we inline the call.
+// Specialically, the objects passed into calls with delegate and callback
+// parameters.
+@class DelegateTest;
+typedef void (*ReleaseCallbackTy) (DelegateTest *c);
+
+@interface Delegate : NSObject
+@end
+
+@interface DelegateTest : NSObject {
+ Delegate *myDel;
+}
+// Object initialized with a delagate which could potentially release it.
+- (id)initWithDelegate: (id) d;
+
+- (void) setDelegate: (id) d;
+
+// Releases object through callback.
++ (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc;
+
++ (void)test: (Delegate *)d;
+
+@property (assign) Delegate* myDel;
+@end
+
+void releaseObj(DelegateTest *c);
+
+// Releases object through callback.
+void updateObject(DelegateTest *c, ReleaseCallbackTy rel) {
+ rel(c);
+}
+
+@implementation DelegateTest
+@synthesize myDel;
+
+- (id) initWithDelegate: (id) d {
+ if ((self = [super init]))
+ myDel = d;
+ return self;
+}
+
+- (void) setDelegate: (id) d {
+ myDel = d;
+}
+
++ (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc {
+ rc(obj);
+}
+
++ (void) test: (Delegate *)d {
+ DelegateTest *obj1 = [[DelegateTest alloc] initWithDelegate: d]; // no-warning
+ DelegateTest *obj2 = [[DelegateTest alloc] init]; // no-warning
+ DelegateTest *obj3 = [[DelegateTest alloc] init]; // no-warning
+ updateObject(obj2, releaseObj);
+ [DelegateTest updateObject: obj3
+ WithCallback: releaseObj];
+ DelegateTest *obj4 = [[DelegateTest alloc] init]; // no-warning
+ [obj4 setDelegate: d];
+}
+@end
+
diff --git a/test/Analysis/inlining/assume-super-init-does-not-return-nil.m b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
new file mode 100644
index 000000000000..cda1e87918e6
--- /dev/null
+++ b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -analyze -analyzer-ipa=dynamic-bifurcate -analyzer-checker=core,osx -verify %s
+
+typedef signed char BOOL;
+
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+- (oneway void)release;
+@end
+
+@interface Cell : NSObject {
+ int x;
+}
+- (id) init;
+- (void)test;
+@end
+
+@implementation Cell
+- (id) init {
+ if ((self = [super init])) {
+ return self;
+ }
+ // Test that this is being analyzed.
+ int m;
+ m = m + 1; //expected-warning {{The left operand of '+' is a garbage value}}
+ return self;
+}
+
+// Make sure that we do not propagate the 'nil' check from inlined 'init' to 'test'.
+- (void) test {
+ Cell *newCell = [[Cell alloc] init];
+ newCell->x = 5; // no-warning
+ [newCell release];
+}
+@end
diff --git a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
index fa473aebce32..37713481a48d 100644
--- a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
+++ b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
@@ -15,3 +15,19 @@ void testKnown() {
A a;
clang_analyzer_eval(a.get() == 0); // expected-warning{{TRUE}}
}
+
+
+namespace ReinterpretDisruptsDynamicTypeInfo {
+ class Parent {};
+
+ class Child : public Parent {
+ public:
+ virtual int foo() { return 42; }
+ };
+
+ void test(Parent *a) {
+ Child *b = reinterpret_cast<Child *>(a);
+ if (!b) return;
+ clang_analyzer_eval(b->foo() == 42); // expected-warning{{UNKNOWN}}
+ }
+}
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.c b/test/Analysis/inlining/eager-reclamation-path-notes.c
new file mode 100644
index 000000000000..6c7c05aa4012
--- /dev/null
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.c
@@ -0,0 +1,788 @@
+// 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: FileCheck --input-file=%t.plist %s
+
+void use(int *ptr, int val) {
+ *ptr = val; // expected-warning {{Dereference of null pointer (loaded from variable 'ptr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'ptr')}}
+}
+
+int compute() {
+ // Do something that will take enough processing to trigger trimming.
+ // FIXME: This is actually really sensitive. If the interval timing is just
+ // wrong, the node for the actual dereference may also be collected, and all
+ // the path notes will disappear. <rdar://problem/12511814>
+ return 2 + 3 + 4 + 5 + 6;
+}
+
+void testSimple() {
+ int *p = 0;
+ // expected-note@-1 {{Variable 'p' initialized to a null pointer value}}
+ use(p, compute());
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'ptr'}}
+ // expected-note@-2 {{Calling 'use'}}
+}
+
+
+void use2(int *ptr, int val) {
+ *ptr = val; // expected-warning {{Dereference of null pointer (loaded from variable 'ptr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'ptr')}}
+}
+
+void passThrough(int *p) {
+ use2(p, compute());
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'ptr'}}
+ // expected-note@-2 {{Calling 'use2'}}
+}
+
+void testChainedCalls() {
+ int *ptr = 0;
+ // expected-note@-1 {{Variable 'ptr' initialized to a null pointer value}}
+ passThrough(ptr);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling 'passThrough'}}
+}
+
+// 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>19</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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>21</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>21</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>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>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>21</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>21</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>21</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>21</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>21</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>21</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>21</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>21</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>21</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>Passing null pointer value via 1st parameter &apos;ptr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;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>21</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>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>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;use&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;use&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>5</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;testSimple&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testSimple&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>5</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>5</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>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>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>6</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>6</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>6</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;ptr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;ptr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;ptr&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>use</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>39</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>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>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>Variable &apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;ptr&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>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>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>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>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>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>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>41</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>41</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</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>41</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>41</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>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &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>41</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>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>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;passThrough&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;passThrough&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>32</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;testChainedCalls&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testChainedCalls&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>32</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>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>3</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>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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>33</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>33</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>33</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>33</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>33</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>33</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>33</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>33</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>33</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>33</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>33</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>Passing null pointer value via 1st parameter &apos;ptr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;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>33</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;use2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;use2&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>27</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;passThrough&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;passThrough&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>1</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>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>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>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>28</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>28</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>28</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;ptr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;ptr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;ptr&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>use2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: </array>
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
new file mode 100644
index 000000000000..20cc31148759
--- /dev/null
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -0,0 +1,184 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+
+int opaquePropertyCheck(void *object);
+int coin();
+
+int *getNull() {
+ return 0;
+}
+
+int *dynCastToInt(void *ptr) {
+ if (opaquePropertyCheck(ptr))
+ return (int *)ptr;
+ return 0;
+}
+
+int *dynCastOrNull(void *ptr) {
+ if (!ptr)
+ return 0;
+ if (opaquePropertyCheck(ptr))
+ return (int *)ptr;
+ return 0;
+}
+
+
+void testDynCast(void *p) {
+ int *casted = dynCastToInt(p);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testDynCastOrNull(void *p) {
+ int *casted = dynCastOrNull(p);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+
+void testBranch(void *p) {
+ int *casted;
+
+ // Although the report will be suppressed on one branch, it should still be
+ // valid on the other.
+ if (coin()) {
+ casted = dynCastToInt(p);
+ } else {
+ if (p)
+ return;
+ casted = (int *)p;
+ }
+
+ *casted = 1; // expected-warning {{Dereference of null pointer}}
+}
+
+void testBranchReversed(void *p) {
+ int *casted;
+
+ // Although the report will be suppressed on one branch, it should still be
+ // valid on the other.
+ if (coin()) {
+ if (p)
+ return;
+ casted = (int *)p;
+ } else {
+ casted = dynCastToInt(p);
+ }
+
+ *casted = 1; // expected-warning {{Dereference of null pointer}}
+}
+
+
+// --------------------------
+// "Suppression suppression"
+// --------------------------
+
+void testDynCastOrNullOfNull() {
+ // Don't suppress when one of the arguments is NULL.
+ int *casted = dynCastOrNull(0);
+ *casted = 1;
+#if !SUPPRESSED || NULL_ARGS
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testDynCastOfNull() {
+ // Don't suppress when one of the arguments is NULL.
+ int *casted = dynCastToInt(0);
+ *casted = 1;
+#if !SUPPRESSED || NULL_ARGS
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+int *lookUpInt(int unused) {
+ if (coin())
+ return 0;
+ static int x;
+ return &x;
+}
+
+void testZeroIsNotNull() {
+ // /Do/ suppress when the argument is 0 (an integer).
+ int *casted = lookUpInt(0);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testTrackNull() {
+ // /Do/ suppress if the null argument came from another call returning null.
+ int *casted = dynCastOrNull(getNull());
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testTrackNullVariable() {
+ // /Do/ suppress if the null argument came from another call returning null.
+ int *ptr;
+ ptr = getNull();
+ int *casted = dynCastOrNull(ptr);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+
+// ---------------------------------------
+// FALSE NEGATIVES (over-suppression)
+// ---------------------------------------
+
+void testNoArguments() {
+ // In this case the function has no branches, and MUST return null.
+ int *casted = getNull();
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+int *getNullIfNonNull(void *input) {
+ if (input)
+ return 0;
+ static int x;
+ return &x;
+}
+
+void testKnownPath(void *input) {
+ if (!input)
+ return;
+
+ // In this case we have a known value for the argument, and thus the path
+ // through the function doesn't ever split.
+ int *casted = getNullIfNonNull(input);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+int *alwaysReturnNull(void *input) {
+ if (opaquePropertyCheck(input))
+ return 0;
+ return 0;
+}
+
+void testAlwaysReturnNull(void *input) {
+ // In this case all paths out of the function return 0, but they are all
+ // dominated by a branch whose condition we don't know!
+ int *casted = alwaysReturnNull(input);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
index 0885eafa5b93..9e708028930c 100644
--- a/test/Analysis/inlining/path-notes.c
+++ b/test/Analysis/inlining/path-notes.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=plist-multi-file %s -o - | FileCheck %s
+// 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: FileCheck --input-file=%t.plist %s
void zero(int **p) {
*p = 0;
@@ -18,8 +19,7 @@ void testZero(int *a) {
void check(int *p) {
if (p) {
// expected-note@-1 + {{Assuming 'p' is null}}
- // expected-note@-2 + {{Assuming pointer value is null}}
- // expected-note@-3 + {{Taking false branch}}
+ // expected-note@-2 + {{Taking false branch}}
return;
}
return;
@@ -57,1235 +57,3178 @@ void testStoreCheck(int *a) {
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: <string>{{.*}}path-notes.c</string>
-// CHECK: </array>
+int *getZero() {
+ int *p = 0;
+ // expected-note@-1 + {{Variable 'p' initialized to a null pointer value}}
+ // ^ This note checks that we add a second visitor for the return value.
+ return p;
+ // expected-note@-1 + {{Returning null pointer (loaded from 'p')}}
+}
+
+void testReturnZero() {
+ *getZero() = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Dereference of null pointer}}
+}
+
+int testReturnZero2() {
+ return *getZero(); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Dereference of null pointer}}
+}
+
+void testInitZero() {
+ int *a = getZero();
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Variable 'a' initialized to a null pointer value}}
+ *a = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
+}
+
+void testStoreZero(int *a) {
+ a = getZero();
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Null pointer value stored to 'a'}}
+ *a = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
+}
+
+void usePointer(int *p) {
+ *p = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+}
+
+void testUseOfNullPointer() {
+ // Test the case where an argument expression is itself a call.
+ usePointer(getZero());
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-4 {{Calling 'usePointer'}}
+}
+
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;zero&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;zero&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;testZero&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;testZero&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Null pointer value stored to &apos;a&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Null pointer value stored to &apos;a&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returning from &apos;zero&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returning from &apos;zero&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testZero</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testCheck</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>32</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;a&apos; initialized here</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;a&apos; initialized here</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testInitCheck</string>
-// CHECK: <key>issue_hash</key><integer>6</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Value assigned to &apos;a&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Value assigned to &apos;a&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>25</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returning from &apos;check&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;a&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testStoreCheck</string>
-// CHECK: <key>issue_hash</key><integer>6</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>11</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>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>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>Calling &apos;zero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;zero&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>5</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;testZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testZero&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>5</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>5</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>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>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>6</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>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>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>Null pointer value stored to &apos;a&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &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>11</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>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>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>Returning from &apos;zero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;zero&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>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>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>14</integer>
+// CHECK-NEXT: <key>col</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>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>14</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>14</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>14</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;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>testZero</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// 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>29</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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>Calling &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;check&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>19</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;testCheck&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testCheck&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>19</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>19</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>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>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>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>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>20</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>20</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>20</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>20</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>20</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>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>20</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>20</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>29</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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>Returning from &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;check&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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>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>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>32</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>32</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>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: </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;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>testCheck</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>40</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>40</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</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>Variable &apos;a&apos; initialized here</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;a&apos; initialized here</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>40</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// 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>42</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>42</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>42</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Calling &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;check&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>19</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;testInitCheck&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testInitCheck&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>19</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>19</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>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>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>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>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>20</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>20</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>20</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>20</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>20</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>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>20</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>20</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>42</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>42</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Returning from &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;check&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>42</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>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>45</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>45</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>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: </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;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>testInitCheck</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>50</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>Value assigned to &apos;a&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value assigned to &apos;a&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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>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>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>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>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>Calling &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;check&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>19</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;testStoreCheck&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testStoreCheck&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>19</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>19</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>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>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>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>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>20</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>20</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>20</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>20</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>20</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>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>20</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>20</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>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>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>Returning from &apos;check&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;check&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>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>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>55</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>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: </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;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>testStoreCheck</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>69</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>69</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>69</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>69</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>69</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>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testReturnZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testReturnZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>Returning null pointer (loaded from &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &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>69</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>69</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>69</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>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&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>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>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>69</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>69</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>69</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>69</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>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>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>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>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>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>testReturnZero</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// 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: </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>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>11</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</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>76</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>76</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testReturnZero2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testReturnZero2&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>Returning null pointer (loaded from &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &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>76</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>76</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>76</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&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>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>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>11</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>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>76</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>76</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>76</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>76</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>76</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>76</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>76</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: </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>testReturnZero2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</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>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>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>12</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>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>83</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>83</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>83</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>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testInitZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testInitZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>Returning null pointer (loaded from &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &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>83</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>83</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>83</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&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>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>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>12</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>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>83</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>83</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>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>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>83</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>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>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>Variable &apos;a&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;a&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>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>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>87</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</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>87</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>87</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>87</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;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>testInitZero</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</integer>
+// 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>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>92</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>92</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>92</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>92</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>92</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>92</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>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testStoreZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testStoreZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>Returning null pointer (loaded from &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &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>92</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>92</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>92</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&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>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>92</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>92</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>92</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>92</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>92</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>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>92</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>92</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>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>92</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>Null pointer value stored to &apos;a&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;a&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>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>92</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>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>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>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>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>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;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>testStoreZero</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// 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: </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>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</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>107</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>107</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>107</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>107</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>107</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>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testUseOfNullPointer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testUseOfNullPointer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>Returning null pointer (loaded from &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer (loaded from &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>107</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>107</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>107</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&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>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</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>107</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>107</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>107</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>107</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>107</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>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &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>107</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>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</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;usePointer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;usePointer&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>100</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;testUseOfNullPointer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testUseOfNullPointer&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>100</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>100</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>101</integer>
+// CHECK-NEXT: <key>col</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>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>101</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>101</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>101</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;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>usePointer</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>101</integer>
+// 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/path-notes.m b/test/Analysis/inlining/path-notes.m
new file mode 100644
index 000000000000..b15b86968270
--- /dev/null
+++ b/test/Analysis/inlining/path-notes.m
@@ -0,0 +1,469 @@
+// 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: FileCheck --input-file=%t.plist %s
+
+@interface Test
+@property int *p;
+@end
+
+int *getZeroIfNil(Test *x) {
+ return x.p;
+ // expected-note@-1 {{No method is called because the receiver is nil}}
+ // expected-note@-2 {{Returning null pointer}}
+}
+
+void testReturnZeroIfNil() {
+ *getZeroIfNil(0) = 1; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1 {{Calling 'getZeroIfNil'}}
+ // expected-note@-2 {{Passing nil object reference via 1st parameter 'x'}}
+ // expected-note@-3 {{Returning from 'getZeroIfNil'}}
+ // expected-note@-4 {{Dereference of null pointer}}
+}
+
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>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>16</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>16</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</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>16</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>16</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>Passing nil object reference via 1st parameter &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing nil object reference via 1st parameter &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</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>16</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>16</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>16</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</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>16</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;getZeroIfNil&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZeroIfNil&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;testReturnZeroIfNil&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testReturnZeroIfNil&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>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>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>No method is called because the receiver is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>No method is 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>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <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>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>10</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>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>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>Returning null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</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>16</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>Returning from &apos;getZeroIfNil&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZeroIfNil&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>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>16</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>16</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>16</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>16</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>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>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>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>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>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>testReturnZeroIfNil</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// 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: </array>
diff --git a/test/Analysis/inlining/retain-count-self-init.m b/test/Analysis/inlining/retain-count-self-init.m
new file mode 100644
index 000000000000..ee8dbe391c42
--- /dev/null
+++ b/test/Analysis/inlining/retain-count-self-init.m
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.SelfInit -analyzer-ipa=dynamic-bifurcate -verify %s
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+- (oneway void)release;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+
+// We do not want to overhelm user with error messages in case they forgot to
+// assign to self and check that the result of [super init] is non-nil. So
+// stop tracking the receiver of init with respect to Retain Release checker.
+// radar://12115830
+@interface ParentOfCell : NSObject
+- (id)initWithInt: (int)inInt;
+@end
+@interface Cell : ParentOfCell{
+ int x;
+}
+- (id)init;
++ (void)test;
+@property int x;
+@end
+@implementation Cell
+@synthesize x;
+- (id) init {
+ [super init];
+ self.x = 3; // no-warning
+ return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self)}}
+}
+- (id) initWithInt: (int)inInt {
+ [super initWithInt: inInt];
+ self.x = inInt; // no-warning
+ return self; // expected-warning {{Returning 'self' while it is not set to the result of '[(super or self)}}
+}
+- (id) init2 {
+ [self init]; // The call [self init] is inlined. We will warn inside the inlined body.
+ self.x = 2; // no-warning
+ return self;
+}
+
+- (id) initWithIntGood: (int)inInt {
+ if (self = [super initWithInt: inInt]) {
+ self.x = inInt;
+ }
+ return self;
+}
++ (void) test {
+ Cell *sharedCell1 = [[Cell alloc] init];
+ [sharedCell1 release];
+ Cell *sharedCell2 = [[Cell alloc] initWithInt: 3];
+ [sharedCell2 release];
+ Cell *sharedCell3 = [[Cell alloc] initWithIntGood: 3];
+ [sharedCell3 release];
+}
+
+@end
+
diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
new file mode 100644
index 000000000000..cec782151c95
--- /dev/null
+++ b/test/Analysis/inlining/stl.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=dynamic -analyzer-config c++-stdlib-inlining=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=dynamic -analyzer-config c++-stdlib-inlining=true -DINLINE=1 -verify %s
+
+#include "../Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+void testVector(std::vector<int> &nums) {
+ if (nums.begin()) return;
+ if (nums.end()) return;
+
+ clang_analyzer_eval(nums.size() == 0);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
+
+void testException(std::exception e) {
+ // Notice that the argument is NOT passed by reference, so we can devirtualize.
+ const char *x = e.what();
+ clang_analyzer_eval(x == 0);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
diff --git a/test/Analysis/inlining/test-always-inline-size-option.c b/test/Analysis/inlining/test-always-inline-size-option.c
new file mode 100644
index 000000000000..6b3c13d2b672
--- /dev/null
+++ b/test/Analysis/inlining/test-always-inline-size-option.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-inline-max-stack-depth=3 -analyzer-config ipa-always-inline-size=3 -verify %s
+
+void clang_analyzer_eval(int);
+int nested5() {
+ if (5 < 3)
+ return 0;
+ else
+ if (3 == 3)
+ return 0;
+ return 0;
+}
+int nested4() {
+ return nested5();
+}
+int nested3() {
+ return nested4();
+}
+int nested2() {
+ return nested3();
+}
+int nested1() {
+ return nested2();
+}
+
+void testNested() {
+ clang_analyzer_eval(nested1() == 0); // expected-warning{{TRUE}}
+}
+
+// Make sure we terminate a recursive path.
+int recursive() {
+ return recursive();
+}
+int callRecursive() {
+ return recursive();
+}
+
+int mutuallyRecursive1();
+
+int mutuallyRecursive2() {
+ return mutuallyRecursive1();
+}
+
+int mutuallyRecursive1() {
+ return mutuallyRecursive2();
+}
+int callMutuallyRecursive() {
+ return mutuallyRecursive1();
+}
diff --git a/test/Analysis/inlining/test_objc_inlining_option.m b/test/Analysis/inlining/test_objc_inlining_option.m
new file mode 100644
index 000000000000..34502c4aa81d
--- /dev/null
+++ b/test/Analysis/inlining/test_objc_inlining_option.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s
+// expected-no-diagnostics
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+
+// Vanila: ObjC class method is called by name.
+@interface MyParent : NSObject
++ (int)getInt;
+@end
+@interface MyClass : MyParent
++ (int)getInt;
+@end
+@implementation MyClass
++ (int)testClassMethodByName {
+ int y = [MyClass getInt];
+ return 5/y; // no-warning
+}
++ (int)getInt {
+ return 0;
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/ivars.m b/test/Analysis/ivars.m
index 42e92d259a9f..c717da63ee61 100644
--- a/test/Analysis/ivars.m
+++ b/test/Analysis/ivars.m
@@ -130,3 +130,11 @@ struct S makeS();
}
@end
+
+
+int testNull(Root *obj) {
+ if (obj) return 0;
+
+ int *x = &obj->uniqueID;
+ return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+}
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
index 585a32ddc342..fe6c61d1e824 100644
--- a/test/Analysis/keychainAPI.m
+++ b/test/Analysis/keychainAPI.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-ipa=inlining -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
// Fake typedefs.
typedef unsigned int OSStatus;
diff --git a/test/Analysis/logical-ops.c b/test/Analysis/logical-ops.c
new file mode 100644
index 000000000000..a1223b39fa89
--- /dev/null
+++ b/test/Analysis/logical-ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+void testAnd(int i, int *p) {
+ int *nullP = 0;
+ int *knownP = &i;
+ clang_analyzer_eval((knownP && knownP) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval((knownP && nullP) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((knownP && p) == 1); // expected-warning{{UNKNOWN}}
+}
+
+void testOr(int i, int *p) {
+ int *nullP = 0;
+ int *knownP = &i;
+ clang_analyzer_eval((nullP || knownP) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval((nullP || nullP) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((nullP || p) == 1); // expected-warning{{UNKNOWN}}
+}
+
+
+// PR13461
+int testTypeIsInt(int i, void *p) {
+ if (i | (p && p))
+ return 1;
+ return 0;
+}
diff --git a/test/Analysis/lvalue.cpp b/test/Analysis/lvalue.cpp
index 0cc42f50372b..9a6bd5939743 100644
--- a/test/Analysis/lvalue.cpp
+++ b/test/Analysis/lvalue.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// expected-no-diagnostics
int f1() {
int x = 0, y = 1;
diff --git a/test/Analysis/malloc-annotations.c b/test/Analysis/malloc-annotations.c
index 9c040b688d2b..2a078b6f8277 100644
--- a/test/Analysis/malloc-annotations.c
+++ b/test/Analysis/malloc-annotations.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,experimental.unix.MallocWithAnnotations -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,alpha.unix.MallocWithAnnotations -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
diff --git a/test/Analysis/malloc-interprocedural.c b/test/Analysis/malloc-interprocedural.c
index 589bc4fdef59..79cbf247dd94 100644
--- a/test/Analysis/malloc-interprocedural.c
+++ b/test/Analysis/malloc-interprocedural.c
@@ -1,15 +1,17 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-ipa=inlining -analyzer-inline-max-stack-depth=5 -analyzer-inline-max-function-size=6 -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -verify %s
-#include "system-header-simulator.h"
+#include "Inputs/system-header-simulator.h"
-typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void *valloc(size_t);
void free(void *);
void *realloc(void *ptr, size_t size);
void *reallocf(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
-extern void exit(int) __attribute__ ((__noreturn__));
+
+void exit(int) __attribute__ ((__noreturn__));
+void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
+size_t strlen(const char *);
static void my_malloc1(void **d, size_t size) {
*d = malloc(size);
@@ -96,3 +98,34 @@ int uafAndCallsFooWithEmptyReturn() {
fooWithEmptyReturn(12);
return *x; // expected-warning {{Use of memory after it is freed}}
}
+
+
+// If we inline any of the malloc-family functions, the checker shouldn't also
+// try to do additional modeling. <rdar://problem/12317671>
+char *strndup(const char *str, size_t n) {
+ if (!str)
+ return 0;
+
+ // DO NOT FIX. This is to test that we are actually using the inlined
+ // behavior!
+ if (n < 5)
+ return 0;
+
+ size_t length = strlen(str);
+ if (length < n)
+ n = length;
+
+ char *result = malloc(n + 1);
+ memcpy(result, str, n);
+ result[n] = '\0';
+ return result;
+}
+
+void useStrndup(size_t n) {
+ if (n == 0)
+ (void)strndup(0, 20); // no-warning
+ else if (n < 5)
+ (void)strndup("hi there", n); // no-warning
+ else
+ (void)strndup("hi there", n); // expected-warning{{leak}}
+}
diff --git a/test/Analysis/malloc-overflow.c b/test/Analysis/malloc-overflow.c
index 714fd3d308ad..2f443caf4a17 100644
--- a/test/Analysis/malloc-overflow.c
+++ b/test/Analysis/malloc-overflow.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.MallocOverflow -verify %s
#define NULL ((void *) 0)
typedef __typeof__(sizeof(int)) size_t;
diff --git a/test/Analysis/malloc-overflow.cpp b/test/Analysis/malloc-overflow.cpp
index c1ac6be4b029..e3a0408863e6 100644
--- a/test/Analysis/malloc-overflow.cpp
+++ b/test/Analysis/malloc-overflow.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.MallocOverflow -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.MallocOverflow -verify %s
+// expected-no-diagnostics
class A {
public:
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index 11eef3e14006..12430a6ffbf3 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -1,5 +1,6 @@
+// RUN: rm -f %t
// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o %t %s
-// RUN: FileCheck --input-file %t %s
+// RUN: FileCheck -input-file %t %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@@ -168,4265 +169,4344 @@ void use_function_with_leak7() {
function_with_leak7();
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>diagnosticTest</string>
-// CHECK: <key>issue_hash</key><integer>5</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>14</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>30</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>21</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>21</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>21</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>myArrayAllocation</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>21</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Attempt to reallocate memory</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Attempt to reallocate memory</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>26</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reallocation failed</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reallocation failed</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>27</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>reallocDiagnostics</string>
-// CHECK: <key>issue_hash</key><integer>5</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;wrapper&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;wrapper&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>34</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;test_wrapper&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;test_wrapper&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>34</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>34</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;x&apos; is non-null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;x&apos; is non-null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_wrapper</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;my_malloc_and_free&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;my_malloc_and_free&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;test_double_action_call&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;test_double_action_call&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;my_free&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;my_free&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>2</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>2</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is released</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is released</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>2</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returned released memory via 1st parameter</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returned released memory via 1st parameter</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returned released memory via 1st parameter</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returned released memory via 1st parameter</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Use of memory after it is freed</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Use of memory after it is freed</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Use of memory after it is freed</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Use-after-free</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_double_action_call</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>61</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>30</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>30</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;my_realloc&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;my_realloc&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;reallocIntra&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;reallocIntra&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Attempt to reallocate memory</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Attempt to reallocate memory</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>67</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reallocation failed</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reallocation failed</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>68</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reallocation of 1st parameter failed</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reallocation of 1st parameter failed</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>reallocIntra</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>84</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>84</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>80</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_ret&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_ret&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>80</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>80</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>85</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>86</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>86</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>86</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>use_ret</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>86</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>92</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>97</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>97</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>97</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>LeakedSymbol</string>
-// CHECK: <key>issue_hash</key><integer>8</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>97</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>105</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>105</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>105</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak1&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak1&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak1&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak1&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak1</string>
-// CHECK: <key>issue_hash</key><integer>1</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>114</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>114</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>114</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak2&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak2&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>109</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak2&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak2&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>109</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>109</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>110</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>111</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>111</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>111</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak2</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>111</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak3&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak3&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>117</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak3&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak3&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>117</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>117</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>120</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>120</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>120</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak3</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>120</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak4&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak4&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>126</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak4&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak4&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>126</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>126</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>127</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>131</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>131</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>131</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak4</string>
-// CHECK: <key>issue_hash</key><integer>5</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>131</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>145</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>145</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>145</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak5&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak5&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak5&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak5&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>141</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>142</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>142</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>142</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak5</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>142</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>156</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>156</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>156</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak6&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak6&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>151</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak6&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak6&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>151</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>151</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>152</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>153</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>153</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>153</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>function_with_leak6</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>153</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Calling &apos;function_with_leak7&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Calling &apos;function_with_leak7&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>164</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak7&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Entered call from &apos;use_function_with_leak7&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>164</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>164</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>24</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>165</integer>
-// CHECK: <key>col</key><integer>28</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is allocated</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>25</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>1</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Returned allocated memory</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Memory is never released; potential leak</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Memory is never released; potential leak</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Memory is never released; potential leak</string>
-// CHECK: <key>category</key><string>Memory Error</string>
-// CHECK: <key>type</key><string>Memory leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>use_function_with_leak7</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>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>11</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>11</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>11</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>11</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>11</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;in&apos; is &gt; 5</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;in&apos; is &gt; 5</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>9</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>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>12</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>12</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>12</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>12</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>12</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>12</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>12</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</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>12</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: <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>12</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>12</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: <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>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>15</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>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;p&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>diagnosticTest</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
+// 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>20</integer>
+// 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>20</integer>
+// 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>20</integer>
+// 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>20</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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>20</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>20</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>20</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>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>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>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>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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;A&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>myArrayAllocation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// 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: </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>25</integer>
+// 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>25</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>25</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>25</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</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>25</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>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>25</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>25</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// 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>27</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>27</integer>
+// 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>27</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>27</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>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>27</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>27</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>27</integer>
+// CHECK-NEXT: <key>col</key><integer>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>28</integer>
+// 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>28</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>28</integer>
+// 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>28</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>28</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>28</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>28</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>28</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>28</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;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>control</string>
+// CHECK-NEXT: <key>edges</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>9</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>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>28</integer>
+// 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>28</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>28</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>28</integer>
+// 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>28</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>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>28</integer>
+// 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>28</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>29</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>29</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>29</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>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>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>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>44</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>44</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>44</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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;wrapper&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>35</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_wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_wrapper&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>35</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>35</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>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>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>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>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>36</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>36</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>36</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>36</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>36</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>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>36</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>36</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>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>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>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>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>38</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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>38</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>38</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Assuming &apos;x&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&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>38</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>44</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>44</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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returned allocated memory</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returned allocated 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>44</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>44</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</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>46</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>46</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>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>test_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</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>60</integer>
+// 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>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>61</integer>
+// 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>61</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>61</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>61</integer>
+// 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>61</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>Calling &apos;my_malloc_and_free&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;my_malloc_and_free&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>53</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_double_action_call&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_double_action_call&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>53</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>54</integer>
+// 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>54</integer>
+// 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>54</integer>
+// 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>54</integer>
+// 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>10</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>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>54</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>54</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>54</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>1</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>54</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>54</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>55</integer>
+// 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>55</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>55</integer>
+// 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>55</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>56</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>56</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>56</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>56</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>56</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;my_free&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;my_free&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>50</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;my_malloc_and_free&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;my_malloc_and_free&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>50</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>50</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>51</integer>
+// 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>51</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>51</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>51</integer>
+// 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>51</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is released</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>56</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>56</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>56</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returned released memory via 1st parameter</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>7</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>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>57</integer>
+// 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>57</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>61</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>61</integer>
+// 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>61</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>Returned released memory via 1st parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returned released memory via 1st parameter</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>61</integer>
+// 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>61</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>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>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>62</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>62</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>62</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>Use of memory after it is freed</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Use of memory after it is freed</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
+// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_double_action_call</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>75</integer>
+// 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>75</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>75</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>75</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>75</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>75</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>75</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: </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>75</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>75</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>76</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>76</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>76</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>76</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>76</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;my_realloc&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;my_realloc&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>66</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;reallocIntra&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;reallocIntra&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>66</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// 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>67</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>67</integer>
+// 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>67</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>68</integer>
+// 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>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>5</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>18</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>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>68</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</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>68</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>1</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>68</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>68</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>69</integer>
+// 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>69</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>69</integer>
+// 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>69</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>69</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>69</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>69</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>69</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>69</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>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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>69</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>69</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>69</integer>
+// 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>69</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>69</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>69</integer>
+// 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>69</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>1</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>69</integer>
+// 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>69</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>70</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>70</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>76</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>76</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>76</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reallocation of 1st parameter failed</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reallocation of 1st parameter 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>76</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>76</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>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>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>77</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>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>reallocIntra</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// 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: </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>85</integer>
+// 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>85</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>86</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>86</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>86</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>86</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>86</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>Calling &apos;malloc_wrapper_ret&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;malloc_wrapper_ret&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>81</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;use_ret&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_ret&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>81</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>81</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>82</integer>
+// 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>82</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>82</integer>
+// 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>82</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>82</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>82</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>82</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>82</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>82</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 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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>86</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>86</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>86</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>Returned allocated memory</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returned allocated 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>86</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>86</integer>
+// CHECK-NEXT: <key>col</key><integer>26</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</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>87</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>87</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>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;v&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>use_ret</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</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>91</integer>
+// 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>91</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>5</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>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>93</integer>
+// 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>93</integer>
+// 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>93</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>93</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>93</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>93</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>93</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>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>93</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>93</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>98</integer>
+// 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>98</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>98</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>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;m&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>LeakedSymbol</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
+// 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>106</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>106</integer>
+// 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>106</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;function_with_leak1&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak1&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>102</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;use_function_with_leak1&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak1&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>102</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>102</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>103</integer>
+// 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>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>control</string>
+// CHECK-NEXT: <key>edges</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>5</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>103</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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>103</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>103</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>103</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
+// 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>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>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>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak1</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
+// 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>115</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>115</integer>
+// 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>115</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;function_with_leak2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak2&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>110</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;use_function_with_leak2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak2&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>110</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>110</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>111</integer>
+// 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>111</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>111</integer>
+// 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>111</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>111</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>111</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</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>111</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>111</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>111</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>111</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// 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>112</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>112</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>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// 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>124</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>124</integer>
+// 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>124</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;function_with_leak3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak3&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>118</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;use_function_with_leak3&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak3&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>118</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>118</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>119</integer>
+// 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>119</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>119</integer>
+// 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>119</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>22</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>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>119</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>119</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>119</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>119</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// 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>120</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>120</integer>
+// 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>120</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>120</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>120</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>120</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>120</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>120</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&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>120</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>120</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>121</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>121</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>121</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak3</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</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>135</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>135</integer>
+// 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>135</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;function_with_leak4&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak4&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>127</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;use_function_with_leak4&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak4&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>127</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>127</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>128</integer>
+// 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>128</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>128</integer>
+// 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>128</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>128</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>128</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</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>128</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>128</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>128</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>128</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>129</integer>
+// 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>129</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>129</integer>
+// 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>129</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>129</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>129</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>129</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>129</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>129</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>1</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>129</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>129</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>132</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>132</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>132</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak4</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>132</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>146</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>146</integer>
+// 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>146</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;function_with_leak5&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak5&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>141</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;use_function_with_leak5&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak5&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>141</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>141</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>142</integer>
+// 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>142</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>142</integer>
+// 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>142</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>142</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>142</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</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>142</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>142</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>142</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>142</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</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>143</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>12</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>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak5</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</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: <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>157</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>157</integer>
+// 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>157</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;function_with_leak6&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak6&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>152</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;use_function_with_leak6&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak6&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>152</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>152</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>153</integer>
+// 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>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>5</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>22</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>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>153</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>153</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</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>153</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>153</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// 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>154</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>154</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>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; 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>function_with_leak6</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// 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>169</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>169</integer>
+// 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>169</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;function_with_leak7&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak7&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>165</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;use_function_with_leak7&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak7&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>165</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>165</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>166</integer>
+// 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>166</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>166</integer>
+// 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>166</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>166</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>166</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>166</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>166</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>166</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 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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>169</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>169</integer>
+// 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>169</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returned allocated memory</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returned allocated 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>169</integer>
+// 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>169</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>170</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>170</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>170</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>Memory is never released; potential leak</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is never released; potential leak</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak</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>use_function_with_leak7</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>170</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: </array>
diff --git a/test/Analysis/malloc-sizeof.c b/test/Analysis/malloc-sizeof.c
index 6eb466ac6a11..7a8585fa8442 100644
--- a/test/Analysis/malloc-sizeof.c
+++ b/test/Analysis/malloc-sizeof.c
@@ -34,3 +34,19 @@ void ignore_const() {
const char ***y = (const char ***)malloc(1 * sizeof(char *)); // expected-warning {{Result of 'malloc' is converted to a pointer of type 'const char **', which is incompatible with sizeof operand type 'char *'}}
free(x);
}
+
+int *mallocArraySize() {
+ static const int sTable[10];
+ static const int nestedTable[10][2];
+ int *table = malloc(sizeof sTable);
+ int *table1 = malloc(sizeof nestedTable);
+ int (*table2)[2] = malloc(sizeof nestedTable);
+ int (*table3)[10][2] = malloc(sizeof nestedTable);
+ return table;
+}
+
+int *mallocWrongArraySize() {
+ static const double sTable[10];
+ int *table = malloc(sizeof sTable); // expected-warning {{Result of 'malloc' is converted to a pointer of type 'int', which is incompatible with sizeof operand type 'const double [10]'}}
+ return table;
+}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index e3d92d9ad671..68308fd61a08 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
-#include "system-header-simulator.h"
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
+// REQUIRES: LP64
+
+#include "Inputs/system-header-simulator.h"
void clang_analyzer_eval(int);
@@ -1000,17 +1002,36 @@ void freeButNoMalloc(int *p, int x){
}
struct HasPtr {
- int *p;
+ char *p;
};
-int* reallocButNoMalloc(struct HasPtr *a, int c, int size) {
+char* reallocButNoMalloc(struct HasPtr *a, int c, int size) {
int *s;
- a->p = (int *)realloc(a->p, size);
- if (a->p == 0)
- return 0; // expected-warning{{Memory is never released; potential leak}}
+ char *b = realloc(a->p, size);
+ char *m = realloc(a->p, size); // expected-warning {{Attempt to free released memory}}
return a->p;
}
+// We should not warn in this case since the caller will presumably free a->p in all cases.
+int reallocButNoMallocPR13674(struct HasPtr *a, int c, int size) {
+ int *s;
+ char *b = realloc(a->p, size);
+ if (b == 0)
+ return -1;
+ a->p = b;
+ return 0;
+}
+
+// Test realloc with no visible malloc.
+void *test(void *ptr) {
+ void *newPtr = realloc(ptr, 4);
+ if (newPtr == 0) {
+ if (ptr)
+ free(ptr); // no-warning
+ }
+ return newPtr;
+}
+
// ----------------------------------------------------------------------------
// False negatives.
diff --git a/test/Analysis/malloc.cpp b/test/Analysis/malloc.cpp
index 72b92722133b..220d74625bc0 100644
--- a/test/Analysis/malloc.cpp
+++ b/test/Analysis/malloc.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@@ -6,6 +6,11 @@ void free(void *);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
+
+void checkThatMallocCheckerIsRunning() {
+ malloc(4); // expected-warning{{leak}}
+}
+
// Test for radar://11110132.
struct Foo {
mutable void* m_data;
@@ -35,3 +40,23 @@ void r11160612_3(CanFreeMemory* p) {
const_ptr_and_callback_def_param(0, x, 12, p->myFree);
}
+
+namespace PR13751 {
+ class OwningVector {
+ void **storage;
+ size_t length;
+ public:
+ OwningVector();
+ ~OwningVector();
+ void push_back(void *Item) {
+ storage[length++] = Item;
+ }
+ };
+
+ void testDestructors() {
+ OwningVector v;
+ v.push_back(malloc(4));
+ // no leak warning; freed in destructor
+ }
+}
+
diff --git a/test/Analysis/malloc.m b/test/Analysis/malloc.m
index 08206f3bf14c..21d2dafa38b6 100644
--- a/test/Analysis/malloc.m
+++ b/test/Analysis/malloc.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -Wno-objc-root-class -fblocks %s
-#include "system-header-simulator-objc.h"
+#include "Inputs/system-header-simulator-objc.h"
@class NSString;
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index 7a9d881b1518..c92c966459ce 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
-#include "system-header-simulator-objc.h"
+#include "Inputs/system-header-simulator-objc.h"
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
@@ -221,4 +221,60 @@ void foo(NSPointerArray* pointerArray) {
void noCrashOnVariableArgumentSelector() {
NSMutableString *myString = [NSMutableString stringWithString:@"some text"];
[myString appendFormat:@"some text = %d", 3];
-} \ No newline at end of file
+}
+
+void test12365078_check() {
+ unichar *characters = (unichar*)malloc(12);
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string) free(characters); // no-warning
+}
+
+void test12365078_nocheck() {
+ unichar *characters = (unichar*)malloc(12);
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+}
+
+void test12365078_false_negative() {
+ unichar *characters = (unichar*)malloc(12);
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string) {;}
+}
+
+void test12365078_no_malloc(unichar *characters) {
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string) {free(characters);}
+}
+
+NSString *test12365078_no_malloc_returnValue(unichar *characters) {
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string) {
+ return 0; // no-warning
+ }
+ return string;
+}
+
+void test12365078_nocheck_nomalloc(unichar *characters) {
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ free(characters); // expected-warning {{Attempt to free non-owned memory}}
+}
+
+void test12365078_nested(unichar *characters) {
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string) {
+ NSString *string2 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string2) {
+ NSString *string3 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string3) {
+ NSString *string4 = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (!string4)
+ free(characters);
+ }
+ }
+ }
+}
+
+void test12365078_check_positive() {
+ unichar *characters = (unichar*)malloc(12);
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1];
+ if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}}
+}
diff --git a/test/Analysis/member-expr.cpp b/test/Analysis/member-expr.cpp
new file mode 100644
index 000000000000..cf437387d6a6
--- /dev/null
+++ b/test/Analysis/member-expr.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -verify
+
+void clang_analyzer_eval(int);
+
+namespace EnumsViaMemberExpr {
+ struct Foo {
+ enum E {
+ Bar = 1
+ };
+ };
+
+ void testEnumVal(Foo Baz) {
+ clang_analyzer_eval(Baz.Bar == Foo::Bar); // expected-warning{{TRUE}}
+ }
+
+ void testEnumRef(Foo &Baz) {
+ clang_analyzer_eval(Baz.Bar == Foo::Bar); // expected-warning{{TRUE}}
+ }
+
+ void testEnumPtr(Foo *Baz) {
+ clang_analyzer_eval(Baz->Bar == Foo::Bar); // expected-warning{{TRUE}}
+ }
+} \ No newline at end of file
diff --git a/test/Analysis/method-call-intra-p.cpp b/test/Analysis/method-call-intra-p.cpp
index 701479faa820..a1709428402c 100644
--- a/test/Analysis/method-call-intra-p.cpp
+++ b/test/Analysis/method-call-intra-p.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// expected-no-diagnostics
// Intra-procedural C++ tests.
diff --git a/test/Analysis/method-call-path-notes.cpp b/test/Analysis/method-call-path-notes.cpp
index 17034b9b0001..a41a7864aa09 100644
--- a/test/Analysis/method-call-path-notes.cpp
+++ b/test/Analysis/method-call-path-notes.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=plist-multi-file %s -o - | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
// Test warning about null or uninitialized pointer values used as instance member
// calls.
@@ -25,7 +26,7 @@ void test_ic_set_to_null() {
}
void test_ic_null(TestInstanceCall *p) {
- if (!p) // expected-note {{Assuming pointer value is null}} expected-note {{Taking true branch}}
+ if (!p) // expected-note {{Assuming 'p' is null}} expected-note {{Taking true branch}}
p->foo(); // expected-warning {{Called C++ object pointer is null}} expected-note{{Called C++ object pointer is null}}
}
@@ -37,713 +38,766 @@ void test_ic_member_ptr() {
}
void test_cast(const TestInstanceCall *p) {
- if (!p) // expected-note {{Assuming pointer value is null}} expected-note {{Taking true branch}}
+ if (!p) // expected-note {{Assuming 'p' is null}} expected-note {{Taking true branch}}
const_cast<TestInstanceCall *>(p)->foo(); // expected-warning {{Called C++ object pointer is null}} expected-note {{Called C++ object pointer is null}}
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: <string>{{.*}}method-call-path-notes.cpp</string>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; declared without an initial value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; declared without an initial value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is uninitialized</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is uninitialized</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is uninitialized</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is uninitialized</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_ic</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>13</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_ic_null</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_ic_set_to_null</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_ic_null</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>33</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_ic_member_ptr</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>40</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Called C++ object pointer is null</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Called C++ object pointer is null</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_cast</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>41</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>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>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>Variable &apos;p&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;p&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>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>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>14</integer>
+// CHECK-NEXT: <key>col</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>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>14</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>14</integer>
+// CHECK-NEXT: <key>col</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>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>Called C++ object pointer is uninitialized</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is uninitialized</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is uninitialized</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is uninitialized</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ic</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// 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>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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>19</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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ic_null</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>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>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>24</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>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>25</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>25</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ic_set_to_null</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
+// 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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>29</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>29</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>29</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>29</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>29</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>29</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>30</integer>
+// 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>30</integer>
+// 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>30</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>30</integer>
+// 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>30</integer>
+// 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>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ic_null</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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>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>34</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>34</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>34</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>37</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>37</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>37</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>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_ic_member_ptr</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// 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>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>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>41</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>41</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>41</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>41</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>41</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>41</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>41</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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>col</key><integer>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>42</integer>
+// 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>42</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>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_cast</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
index 912062739c34..1a2fedda33bc 100644
--- a/test/Analysis/method-call.cpp
+++ b/test/Analysis/method-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
@@ -9,29 +9,39 @@ struct A {
int getx() const { return x; }
};
+struct B{
+ int x;
+};
+
void testNullObject(A *a) {
clang_analyzer_eval(a); // expected-warning{{UNKNOWN}}
(void)a->getx(); // assume we know what we're doing
clang_analyzer_eval(a); // expected-warning{{TRUE}}
}
-
-// FIXME: These require constructor inlining to be enabled.
-
void f1() {
A x(3);
- // should be TRUE
- clang_analyzer_eval(x.getx() == 3); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x.getx() == 3); // expected-warning{{TRUE}}
}
void f2() {
const A &x = A(3);
- // should be TRUE
- clang_analyzer_eval(x.getx() == 3); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x.getx() == 3); // expected-warning{{TRUE}}
}
void f3() {
const A &x = (A)3;
- // should be TRUE
- clang_analyzer_eval(x.getx() == 3); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x.getx() == 3); // expected-warning{{TRUE}}
+}
+
+void f4() {
+ A x = 3;
+ clang_analyzer_eval(x.getx() == 3); // expected-warning{{TRUE}}
+}
+
+void checkThatCopyConstructorDoesNotInvalidateObjectBeingCopied() {
+ B t;
+ t.x = 0;
+ B t2(t);
+ clang_analyzer_eval(t.x == 0); // expected-warning{{TRUE}}
}
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
index e20a27f611e7..1fbbeefd2ae4 100644
--- a/test/Analysis/misc-ps-64.m
+++ b/test/Analysis/misc-ps-64.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// expected-no-diagnostics
// <rdar://problem/6440393> - A bunch of misc. failures involving evaluating
// these expressions and building CFGs. These tests are here to prevent
diff --git a/test/Analysis/misc-ps-arm.m b/test/Analysis/misc-ps-arm.m
index a909ef13d0f8..1ff0f17cea5f 100644
--- a/test/Analysis/misc-ps-arm.m
+++ b/test/Analysis/misc-ps-arm.m
@@ -1,4 +1,5 @@
// 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
+// expected-no-diagnostics
// <rdar://problem/11405978> - Handle casts of vectors to structs, and loading
// a value.
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index 0aff8e49b274..9fbe3d0e4ee9 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
+// expected-no-diagnostics
// Delta-reduced header stuff (needed for test cases).
typedef signed char BOOL;
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index 00337f448147..90add22677f4 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
// <rdar://problem/6776949>
// main's 'argc' argument is always > 0
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
index 3106a24c5c7f..bed6fc30d315 100644
--- a/test/Analysis/misc-ps-region-store-i386.m
+++ b/test/Analysis/misc-ps-region-store-i386.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// expected-no-diagnostics
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m
index 2c604cfdcdf7..4575ad44977b 100644
--- a/test/Analysis/misc-ps-region-store-x86_64.m
+++ b/test/Analysis/misc-ps-region-store-x86_64.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
+// expected-no-diagnostics
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index e30cedb91189..a106cf060425 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.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,experimental.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 -analyzer-store=region -verify -fblocks -analyzer-ipa=inlining -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-ipa=inlining -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
// Test basic handling of references.
char &test1_aux();
@@ -537,7 +537,8 @@ MyEnum rdar10892489_positive() {
throw MyEnumValue;
} catch (MyEnum e) {
int *p = 0;
- *p = 0xDEADBEEF; // expected-warning {{null}}
+ // FALSE NEGATIVE
+ *p = 0xDEADBEEF; // {{null}}
return e;
}
return MyEnumValue;
@@ -562,7 +563,8 @@ void PR11545_positive() {
catch (...)
{
int *p = 0;
- *p = 0xDEADBEEF; // expected-warning {{null}}
+ // FALSE NEGATIVE
+ *p = 0xDEADBEEF; // {{null}}
}
}
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 2b481c4a558b..f772894ff820 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.deadcode.IdempotentOperations,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,alpha.deadcode.IdempotentOperations,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
typedef long unsigned int size_t;
void *memcpy(void *, const void *, size_t);
@@ -1086,6 +1086,9 @@ pr8052(u_int boot_addr)
u_char *src = (u_char *) ((u_long) bootMP);
u_char *dst = (u_char *) boot_addr + ((vm_offset_t) ((((((((1 <<
12) / (sizeof(pd_entry_t))) - 1) - 1) - (260 - 2))) << 22) | ((0) << 12)));
+#ifdef TEST_64
+// expected-warning@-3 {{cast to 'u_char *' (aka 'unsigned char *') from smaller integer type 'u_int' (aka 'unsigned int')}}
+#endif
for (x = 0;
x < size;
++x)
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index 8615c6a9c7fd..c19a90f011c8 100644
--- a/test/Analysis/misc-ps-region-store.mm
+++ b/test/Analysis/misc-ps-region-store.mm
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// expected-no-diagnostics
//===------------------------------------------------------------------------------------------===//
// This files tests our path-sensitive handling of Objective-c++ files.
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
index 8ff710b12f56..ef89321fff6c 100644
--- a/test/Analysis/misc-ps.c
+++ b/test/Analysis/misc-ps.c
@@ -133,3 +133,21 @@ int isctype(char c, unsigned long f)
return (c < 1 || c > 10) ? 0 : !!(c & f);
}
+// Test that symbolic array offsets are modeled conservatively.
+// This was triggering a false "use of uninitialized value" warning.
+void rdar_12075238__aux(unsigned long y);
+int rdar_12075238_(unsigned long count) {
+ if ((count < 3) || (count > 6))
+ return 0;
+
+ unsigned long array[6];
+ unsigned long i = 0;
+ for (; i <= count - 2; i++)
+ {
+ array[i] = i;
+ }
+ array[count - 1] = i;
+ rdar_12075238__aux(array[2]); // no-warning
+ return 0;
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index bcc0472984e9..b261b103fab9 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,8 +1,6 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync,osx.AtomicCAS -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync,osx.AtomicCAS -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync,osx.AtomicCAS -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync,osx.AtomicCAS -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,alpha.deadcode.IdempotentOperations,alpha.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,alpha.deadcode.IdempotentOperations,alpha.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
#ifndef __clang_analyzer__
#error __clang_analyzer__ not defined
@@ -1152,11 +1150,11 @@ void rdar8578650(id x) {
@implementation RDar6352035
- (void)foo {
RDar6352035 *friend = 0;
- friend->c = 7; // expected-warning{{Instance variable access (via 'friend') results in a null pointer dereference}}
+ friend->c = 7; // expected-warning{{Access to instance variable 'c' results in a dereference of a null pointer (loaded from variable 'friend')}}
}
- (void)bar {
self = 0;
- c = 7; // expected-warning{{Instance variable access (via 'self') results in a null pointer dereference}}
+ c = 7; // expected-warning{{Access to instance variable 'c' results in a dereference of a null pointer (loaded from variable 'self')}}
}
@end
diff --git a/test/Analysis/new-with-exceptions.cpp b/test/Analysis/new-with-exceptions.cpp
new file mode 100644
index 000000000000..d909f1fb8b6b
--- /dev/null
+++ b/test/Analysis/new-with-exceptions.cpp
@@ -0,0 +1,71 @@
+// 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 -verify %s
+
+void clang_analyzer_eval(bool);
+
+typedef __typeof__(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+
+// This is the standard placement new.
+inline void* operator new(size_t, void* __p) throw()
+{
+ return __p;
+}
+
+struct NoThrow {
+ void *operator new(size_t) throw();
+};
+
+struct NoExcept {
+ void *operator new(size_t) noexcept;
+};
+
+struct DefaultThrow {
+ void *operator new(size_t);
+};
+
+struct ExplicitThrow {
+ void *operator new(size_t) throw(int);
+};
+
+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
+}
+
+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
+}
+
+extern void *operator new[](size_t, int) noexcept;
+
+void testNewArrayNoThrow() {
+ clang_analyzer_eval(new (1) NoThrow[2]); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(new (1) NoExcept[2]); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(new (1) DefaultThrow[2]); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(new (1) ExplicitThrow[2]); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index fb77de22f127..fdd16da3dc19 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -74,6 +74,18 @@ void testScalarInitialization() {
}
+struct PtrWrapper {
+ int *x;
+
+ PtrWrapper(int *input) : x(input) {}
+};
+
+PtrWrapper *testNewInvalidation() {
+ // Ensure that we don't consider this a leak.
+ return new PtrWrapper(static_cast<int *>(malloc(4)));
+}
+
+
//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
index c1cc076a9362..384501ac89e1 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,alpha.core -analyzer-constraints=range -analyzer-store=region -verify -Wno-objc-root-class %s
// <rdar://problem/6888289> - This test case shows that a nil instance
// variable can possibly be initialized by a method.
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index 7cf2aee35fc0..86e8911f4659 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-ios4.0 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// 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: %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: %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
@interface MyClass {}
- (void *)voidPtrM;
diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c
index 1a80a254cba9..b3c3fbcc6241 100644
--- a/test/Analysis/no-exit-cfg.c
+++ b/test/Analysis/no-exit-cfg.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// expected-no-diagnostics
// This is a test case for the issue reported in PR 2819:
// http://llvm.org/bugs/show_bug.cgi?id=2819
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
index 821f48610fc0..84f86d79bd57 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,alpha.unix,alpha.security.ArrayBound -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
// This file tests cases where we should not flag out-of-bounds warnings.
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
new file mode 100644
index 000000000000..993f63320ea1
--- /dev/null
+++ b/test/Analysis/null-deref-path-notes.m
@@ -0,0 +1,488 @@
+// 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: FileCheck --input-file=%t %s
+
+@interface Root {
+@public
+ int uniqueID;
+}
+- (id)initWithID:(int)newID;
+- (void)refreshID;
+@end
+
+int testNull(Root *obj) {
+ if (obj) return 0;
+ // expected-note@-1 {{Assuming 'obj' is nil}}
+ // expected-note@-2 {{Taking false branch}}
+
+ int *x = &obj->uniqueID; // expected-note{{Variable 'x' initialized to a null pointer value}}
+ return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} expected-note{{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+
+@interface Subclass : Root
+@end
+
+@implementation Subclass
+- (id)initWithID:(int)newID {
+ self = [super initWithID:newID]; // expected-note{{Value assigned to 'self'}}
+ if (self) return self;
+ // expected-note@-1 {{Assuming 'self' is nil}}
+ // expected-note@-2 {{Taking false branch}}
+
+ uniqueID = newID; // expected-warning{{Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'self')}} expected-note{{Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'self')}}
+ return self;
+}
+
+@end
+
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</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>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>14</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>14</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>14</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>14</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>14</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;obj&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;obj&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>14</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>14</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>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>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>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>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>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;x&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>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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>19</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>19</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>19</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>19</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>19</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;x&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;x&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;x&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>testNull</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</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>28</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>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>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>Value assigned to &apos;self&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value assigned to &apos;self&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>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>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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>29</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>29</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>29</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>29</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;self&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;self&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>29</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>29</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>33</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>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Access to instance variable &apos;uniqueID&apos; results in a dereference of a null pointer (loaded from variable &apos;self&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Access to instance variable &apos;uniqueID&apos; results in a dereference of a null pointer (loaded from variable &apos;self&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Access to instance variable &apos;uniqueID&apos; results in a dereference of a null pointer (loaded from variable &apos;self&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>initWithID:</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// 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/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 08bfac748c2b..5bb945486fbc 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -std=gnu99 -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
+// expected-no-diagnostics
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index a707970a3467..4dc8fc4ec991 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wno-error=return-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wno-error=return-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,alpha.deadcode.IdempotentOperations,alpha.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wno-error=return-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,alpha.deadcode.IdempotentOperations,alpha.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wno-error=return-type
typedef unsigned uintptr_t;
diff --git a/test/Analysis/objc-bool.m b/test/Analysis/objc-bool.m
index f95736a6df51..a2d10cc3bade 100644
--- a/test/Analysis/objc-bool.m
+++ b/test/Analysis/objc-bool.m
@@ -1,4 +1,5 @@
// RUN: %clang --analyze %s -o %t -Xclang -verify
+// expected-no-diagnostics
// Test handling of ObjC bool literals.
diff --git a/test/Analysis/objc-for.m b/test/Analysis/objc-for.m
index 52a55b07db5d..1561ef8ddf85 100644
--- a/test/Analysis/objc-for.m
+++ b/test/Analysis/objc-for.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Loops,debug.ExprInspection -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.Loops,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/objc-method-coverage.m b/test/Analysis/objc-method-coverage.m
index 056aafe51873..3088a29a0649 100644
--- a/test/Analysis/objc-method-coverage.m
+++ b/test/Analysis/objc-method-coverage.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=none -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
@interface I
diff --git a/test/Analysis/objc-properties.m b/test/Analysis/objc-properties.m
new file mode 100644
index 000000000000..87ab7f716395
--- /dev/null
+++ b/test/Analysis/objc-properties.m
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignment -fobjc-default-synthesize-properties -verify -fblocks %s
+
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+-(id)retain;
+@end
+
+@interface MyClass;
+@end
+@interface TestProperty :NSObject {
+ MyClass *_Z;
+ id _nonSynth;
+}
+
+ @property (assign, nonatomic) MyClass* A; // explicitely synthesized, not implemented, non-default ivar name
+
+ @property (assign) MyClass* X; // automatically synthesized, not implemented
+
+ @property (assign, nonatomic) MyClass* Y; // automatically synthesized, implemented
+
+ @property (assign, nonatomic) MyClass* Z; // non synthesized ivar, implemented setter
+ @property (readonly) id nonSynth; // non synthesized, explicitly implemented to return ivar with expected name
+
+ - (id) initWithPtr:(MyClass*) value;
+ - (id) myInitWithPtr:(MyClass*) value;
+ - (void) someMethod: (MyClass*)In;
+@end
+
+@implementation TestProperty
+ @synthesize A = __A;
+
+ - (id) initWithPtr: (MyClass*) value {
+ _Y = value; // no-warning
+ return self;
+ }
+
+ - (id) copyWithPtrY: (TestProperty*) value {
+ TestProperty *another = [[TestProperty alloc] init];
+ another->_Y = value->_Y; // no-warning
+ return another;
+ }
+
+ - (id) myInitWithPtr: (MyClass*) value {
+ _Y = value; // no-warning
+ return self;
+ }
+
+ - (void) setY:(MyClass*) NewValue {
+ _Y = NewValue; // no-warning
+ }
+
+ - (void) setZ:(MyClass*) NewValue {
+ _Z = NewValue; // no-warning
+ }
+
+ - (id)nonSynth {
+ return _nonSynth;
+ }
+
+ - (void) someMethod: (MyClass*)In {
+ (__A) = In; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
+ _X = In; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
+ _Y = In; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
+ _Z = In; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
+ _nonSynth = 0; // expected-warning {{Direct assignment to an instance variable backing a property; use the setter instead}}
+ }
+@end \ No newline at end of file
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
new file mode 100644
index 000000000000..357c5e8f607a
--- /dev/null
+++ b/test/Analysis/objc_invalidation.m
@@ -0,0 +1,153 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s
+
+@protocol NSObject
+@end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+-(id)description;
+@end
+@class NSString;
+
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+
+@protocol Invalidation1 <NSObject>
+- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@protocol Invalidation2 <NSObject>
+- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@protocol Invalidation3 <NSObject>
+- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@interface Invalidation2Class <Invalidation2>
+@end
+
+@interface Invalidation1Class <Invalidation1>
+@end
+
+@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> {
+ SomeInvalidationImplementingObject *ObjA; // invalidation in the parent
+}
+@end
+
+@implementation SomeInvalidationImplementingObject
+- (void)invalidate{
+ ObjA = 0;
+}
+- (void)invalidate2 {
+ [self invalidate];
+}
+@end
+
+@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject {
+ SomeInvalidationImplementingObject *Ivar1; // regular ivar
+ SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message
+ SomeInvalidationImplementingObject *_Ivar3; // no property, call -description
+ SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog()
+
+ SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax
+ SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax
+ SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter
+ Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class
+ Invalidation2Class *MultInheritance; // regular ivar belonging to a different class
+ SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method
+ SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property
+ SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method
+ SomeInvalidationImplementingObject *_Prop8;
+
+ // No warnings on these as they are not invalidatable.
+ NSObject *NIvar1;
+ NSObject *NObj2;
+ NSObject *_NProp1;
+ NSObject *_NpropIvar;
+}
+
+@property (assign) SomeInvalidationImplementingObject* Prop0;
+@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1;
+@property (assign) SomeInvalidationImplementingObject* Prop2;
+@property (assign) SomeInvalidationImplementingObject* Prop3;
+@property (assign) SomeInvalidationImplementingObject *Prop5;
+@property (assign) SomeInvalidationImplementingObject *Prop4;
+
+@property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop
+@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop
+@property (assign) SomeInvalidationImplementingObject *SynthIvarProp;
+
+@property (assign) NSObject* NProp0;
+@property (nonatomic, assign) NSObject* NProp1;
+@property (assign) NSObject* NProp2;
+
+-(void)setProp1: (SomeInvalidationImplementingObject*) InO;
+-(void)setNProp1: (NSObject*) InO;
+
+-(void)invalidate;
+
+@end
+
+@interface SomeSubclassInvalidatableObject()
+@property (assign) SomeInvalidationImplementingObject* Prop8;
+@end
+
+@implementation SomeSubclassInvalidatableObject{
+ @private
+ SomeInvalidationImplementingObject *Ivar5;
+}
+
+@synthesize Prop7 = _propIvar;
+@synthesize Prop3 = _Prop3;
+@synthesize Prop5 = _Prop5;
+@synthesize Prop4 = _Prop4;
+@synthesize Prop8 = _Prop8;
+
+
+- (void) setProp1: (SomeInvalidationImplementingObject*) InObj {
+ _Prop1 = InObj;
+}
+
+- (void) setProp2: (SomeInvalidationImplementingObject*) InObj {
+ _Prop2 = InObj;
+}
+- (SomeInvalidationImplementingObject*) Prop2 {
+ return _Prop2;
+}
+
+@synthesize NProp2 = _NpropIvar;
+
+- (void) setNProp1: (NSObject*) InObj {
+ _NProp1 = InObj;
+}
+
+- (void) invalidate {
+ [Ivar2 invalidate];
+ self.Prop0 = 0;
+ self.Prop1 = 0;
+ [self setProp2:0];
+ [self setProp3:0];
+ [[self Prop5] invalidate2];
+ [self.Prop4 invalidate];
+ [self.Prop8 invalidate];
+ self.Prop6 = 0;
+ [[self Prop7] invalidate];
+
+ [_Ivar3 description];
+ NSLog(@"%@", _Ivar4);
+ [super invalidate];
+}
+// expected-warning@-1 {{Instance variable Ivar1 needs to be invalidated}}
+ // expected-warning@-2 {{Instance variable MultipleProtocols needs to be invalidated}}
+ // expected-warning@-3 {{Instance variable MultInheritance needs to be invalidated}}
+ // expected-warning@-4 {{Property SynthIvarProp needs to be invalidated or set to nil}}
+ // expected-warning@-5 {{Instance variable _Ivar3 needs to be invalidated}}
+ // expected-warning@-6 {{Instance variable _Ivar4 needs to be invalidated}}
+ // expected-warning@-7 {{Instance variable Ivar5 needs to be invalidated or set to nil}}
+@end
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index dbc63bc4bed8..066f6a3bc67a 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
void clang_analyzer_eval(bool);
struct X0 { };
@@ -30,3 +30,22 @@ struct IntComparable {
void testMemberOperator(IntComparable B) {
clang_analyzer_eval(B == 0); // expected-warning{{TRUE}}
}
+
+
+
+namespace UserDefinedConversions {
+ class Convertible {
+ public:
+ operator int() const {
+ return 42;
+ }
+ operator bool() const {
+ return true;
+ }
+ };
+
+ void test(const Convertible &obj) {
+ clang_analyzer_eval((int)obj == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(obj); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index c1721703fb86..dd593c5f26c0 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.security.ArrayBoundV2 -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.security.ArrayBoundV2 -verify %s
// Tests doing an out-of-bounds access after the end of an array using:
// - constant integer index
diff --git a/test/Analysis/outofbound-notwork.c b/test/Analysis/outofbound-notwork.c
index c1fa2d7148e8..68b01e0f79c6 100644
--- a/test/Analysis/outofbound-notwork.c
+++ b/test/Analysis/outofbound-notwork.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.security.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region -verify %s
// XFAIL: *
// Once we better handle modeling of sizes of VLAs, we can pull this back
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 2783ac28313c..45786ec4537e 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,experimental.unix,experimental.security.ArrayBound -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.unix,alpha.security.ArrayBound -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
index d3b75f694d0b..a68ee1ed0a30 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -Werror %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -Werror %s -analyzer-store=region -verify
// This test case illustrates that using '-analyze' overrides the effect of
// -Werror. This allows basic warnings not to interfere with producing
diff --git a/test/Analysis/plist-html-macros.c b/test/Analysis/plist-html-macros.c
new file mode 100644
index 000000000000..954aab099725
--- /dev/null
+++ b/test/Analysis/plist-html-macros.c
@@ -0,0 +1,31 @@
+// REQUIRES: shell
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// (sanity check)
+
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-html -o %t.dir/index.plist %s
+// RUN: ls %t.dir | grep \\.html | count 1
+// RUN: grep \\.html %t.dir/index.plist | count 1
+
+// This tests two things: that the two calls to null_deref below are coalesced
+// into a single bug by both the plist and HTML diagnostics, and that the plist
+// diagnostics have a reference to the HTML diagnostics. (It would be nice to
+// check more carefully that the two actually match, but that's hard to write
+// in a lit RUN line.)
+
+#define CALL_FN(a) null_deref(a)
+
+void null_deref(int *a) {
+ if (a)
+ return;
+ *a = 1; // expected-warning{{null}}
+}
+
+void test1() {
+ CALL_FN(0);
+}
+
+void test2(int *p) {
+ CALL_FN(p);
+}
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index a338a79491fd..423574d7819b 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,experimental.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 -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o %t %s
// RUN: FileCheck --input-file %t %s
void test_null_init(void) {
@@ -57,923 +57,1220 @@ void rdar8331641(int x) {
(void) value;
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_init</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>6</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_assign</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>12</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>16</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>16</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>19</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_cond</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>24</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>31</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>36</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_field</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>38</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>82</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>23</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>14</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <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: <key>message</key>
-// CHECK: <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: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;value&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>rdar8331641</string>
-// CHECK: <key>issue_hash</key><integer>6</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>1</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>5</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>5</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>5</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>5</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>5</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>6</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>6</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>6</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><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>0</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>0</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>0</integer>
+// CHECK-NEXT: </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>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>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>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>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>4</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>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><integer>3</integer>
+// 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>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>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>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>19</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>19</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>19</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><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>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>7</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>23</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>23</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>23</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// 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>24</integer>
+// 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>24</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>24</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>24</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><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// 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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>29</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>29</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>29</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>29</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>29</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>29</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>30</integer>
+// 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>30</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>30</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>30</integer>
+// 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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>30</integer>
+// 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>30</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>31</integer>
+// 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>31</integer>
+// 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>31</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>31</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>31</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><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// 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>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>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>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>control</string>
+// CHECK-NEXT: <key>edges</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>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: <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>0</integer>
+// CHECK-NEXT: </dict>
+// 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: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>0</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>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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><integer>3</integer>
+// 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>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>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: <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>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>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>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>54</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>54</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>54</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>54</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>54</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>54</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>54</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>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>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>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>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>55</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>55</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>55</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>55</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>55</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>55</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>55</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>57</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>57</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>57</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>57</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>58</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>58</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>58</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><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</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: </array>
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index 769c1bc60247..cefa762c67c8 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,5 @@
-// RUN: %clang --analyze %s -o - 2>/dev/null | FileCheck %s
+// RUN: %clang --analyze %s -Xanalyzer -analyzer-checker=osx.cocoa.RetainCount -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
void test_null_init(void) {
int *p = 0;
@@ -76,1475 +77,2193 @@ int test_cond_assign() {
*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
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: <string>{{.*}}plist-output.m</string>
-// CHECK: </array>
+// 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}}
+ }
+ }
+}
+
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_init</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_assign</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_cond</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_null_field</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_assumptions</string>
-// CHECK: <key>issue_hash</key><integer>8</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;p&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>test_cond_assign</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>74</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>6</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
-// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Dereference of null pointer</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>test</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>5</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>5</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>5</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>5</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>5</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>5</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>6</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>6</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>6</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><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>0</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>0</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>0</integer>
+// CHECK-NEXT: </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>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>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>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>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>4</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>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><integer>3</integer>
+// 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>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>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>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>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>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>19</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>19</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>19</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><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>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>7</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>23</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>23</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>23</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// 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>24</integer>
+// 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>24</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>24</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>24</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><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// 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>29</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>29</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>29</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>29</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>29</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>29</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>29</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>29</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>30</integer>
+// 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>30</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>30</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>30</integer>
+// 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>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>30</integer>
+// 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>30</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>31</integer>
+// 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>31</integer>
+// 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>31</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>31</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>31</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><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// 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>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>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>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>control</string>
+// CHECK-NEXT: <key>edges</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>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: <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>0</integer>
+// CHECK-NEXT: </dict>
+// 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: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>0</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>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>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><integer>3</integer>
+// 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>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>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>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>43</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>43</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>43</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>43</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>43</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>43</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>43</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>46</integer>
+// CHECK-NEXT: <key>col</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>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>46</integer>
+// CHECK-NEXT: <key>col</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>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>46</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>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>46</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>46</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </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>46</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</integer>
+// 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>49</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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</integer>
+// 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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>50</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>50</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>50</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><integer>8</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// 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>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>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>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>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>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>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>7</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>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>56</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>56</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>56</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: <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>56</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>56</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>56</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 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>56</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>56</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>56</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: <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>56</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>56</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>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>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>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>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>58</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>58</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>58</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>58</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>58</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><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</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>75</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>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>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>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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>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>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>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>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>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><integer>3</integer>
+// 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: </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>86</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>86</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>86</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>86</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>86</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><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>86</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>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>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>86</integer>
+// 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>86</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>86</integer>
+// 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>86</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>86</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>86</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>86</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>86</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>86</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>86</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>86</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>88</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>88</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>88</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><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</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>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>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>96</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>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>96</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>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>100</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>100</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>100</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>100</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>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>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>95</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>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>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>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>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>96</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>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>96</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>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>5</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>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>97</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>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>97</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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>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>97</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>98</integer>
+// 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>98</integer>
+// 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>98</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>98</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>98</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><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>98</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/pointer-to-member.cpp b/test/Analysis/pointer-to-member.cpp
new file mode 100644
index 000000000000..cef5dc586690
--- /dev/null
+++ b/test/Analysis/pointer-to-member.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+
+void clang_analyzer_eval(bool);
+
+struct A {
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef A * (A::*MemberPointer);
+ operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; }
+
+ A *m_ptr;
+};
+
+void testConditionalUse() {
+ A obj;
+
+ obj.m_ptr = &obj;
+ clang_analyzer_eval(obj.m_ptr); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&A::m_ptr); // expected-warning{{TRUE}}
+ clang_analyzer_eval(obj); // expected-warning{{TRUE}}
+
+ obj.m_ptr = 0;
+ clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}}
+ clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}}
+ clang_analyzer_eval(obj); // expected-warning{{FALSE}}
+}
+
+// ---------------
+// FALSE NEGATIVES
+// ---------------
+
+bool testDereferencing() {
+ A obj;
+ obj.m_ptr = 0;
+
+ A::MemberPointer member = &A::m_ptr;
+
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
+
+ member = 0;
+
+ // FIXME: Should emit a null dereference.
+ return obj.*member; // no-warning
+}
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index e16d1aa0ed5b..a5e7db51dc46 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
// This test case was crashing due to how CFRefCount.cpp resolved the
// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
index 19c140d9e59a..6f1ebf962594 100644
--- a/test/Analysis/pr_2542_rdar_6793404.m
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c
index 187f4c6bca43..0d2ca41b32e1 100644
--- a/test/Analysis/pr_4164.c
+++ b/test/Analysis/pr_4164.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// expected-no-diagnostics
// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
//
diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c
index 4735d20eaa5c..b90477424511 100644
--- a/test/Analysis/pthreadlock.c
+++ b/test/Analysis/pthreadlock.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.PthreadLock -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.PthreadLock -verify %s
// Tests performing normal locking patterns and wrong locking orders
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 884ae5b9bbcd..9294c1832bdf 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.FixedAddr,experimental.core.PointerArithm,experimental.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,debug.ExprInspection -analyzer-store=region -verify -triple i686-apple-darwin9 %s
void clang_analyzer_eval(int);
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 62992d0146aa..0fb49c2a9b2f 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core %s -analyzer-store=region -verify
+// expected-no-diagnostics
typedef int bar_return_t;
typedef struct {
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index d710c475defe..7070709e57dd 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core -analyzer-checker=deadcode.DeadStores -verify %s
//
// This test exercises the live variables analysis (LiveVariables.cpp).
// The case originally identified a non-termination bug.
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
index b90d4f43ddf7..83b7605b9511 100644
--- a/test/Analysis/rdar-6541136-region.c
+++ b/test/Analysis/rdar-6541136-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,experimental.security.ArrayBound -analyzer-store=region %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,alpha.security.ArrayBound -analyzer-store=region %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m
index 3a592730a897..1c866bb03732 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-constraints=range -analyzer-store=region -verify %s
+// expected-no-diagnostics
//
// This test case mainly checks that the retain/release checker doesn't crash
// on this file.
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index 5af4776b32db..74d5484fae8b 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-constraints=range -analyzer-store=region -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
typedef struct Foo { int x; } Bar;
diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m
index 4ccc7d7a2b34..b128d32bfdea 100644
--- a/test/Analysis/rdar-7168531.m
+++ b/test/Analysis/rdar-7168531.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -analyzer-store=region %s
// Note that the target triple is important for this test case. It specifies that we use the
// fragile Objective-C ABI.
diff --git a/test/Analysis/redefined_system.c b/test/Analysis/redefined_system.c
index 3c08b5e89642..ae5bf2647f70 100644
--- a/test/Analysis/redefined_system.c
+++ b/test/Analysis/redefined_system.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=unix,core,experimental.security.taint -w -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix,core,alpha.security.taint -w -verify %s
+// expected-no-diagnostics
// Make sure we don't crash when someone redefines a system function we reason about.
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
index 1d3a9b7589e3..7a83fc198db4 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-ipa=none -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-ipa=none -analyzer-store=region -verify %s
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index 06e4a50e44cc..ce0ee8ed57d0 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s
void clang_analyzer_eval(bool);
@@ -110,6 +110,31 @@ void testRetroactiveNullReference(int *x) {
y = 5; // expected-warning{{Dereference of null pointer}}
}
+void testReferenceAddress(int &x) {
+ clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}}
+
+ struct S { int &x; };
+
+ extern S getS();
+ clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
+
+ extern S *getSP();
+ clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
+}
+
+
+void testFunctionPointerReturn(void *opaque) {
+ typedef int &(*RefFn)();
+
+ RefFn getRef = (RefFn)opaque;
+
+ // Don't crash writing to or reading from this reference.
+ int &x = getRef();
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+}
+
// ------------------------------------
// False negatives
@@ -127,5 +152,4 @@ namespace rdar11212286 {
B *x = 0;
return *x; // should warn here!
}
-
}
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index be9276609136..9edb35b78b7c 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// expected-no-diagnostics
//
// This test case simply should not crash. It evaluates the logic of not
// using MemRegion::getRValueType in incorrect places.
diff --git a/test/Analysis/region-store.c b/test/Analysis/region-store.c
index 09c3f102e3ad..d62015008572 100644
--- a/test/Analysis/region-store.c
+++ b/test/Analysis/region-store.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// expected-no-diagnostics
int printf(const char *restrict,...);
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index 0340a3c2a140..1a5ed34c9f39 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -107,9 +107,14 @@ NSFastEnumerationState;
@end @interface NSNumber : NSValue - (char)charValue;
- (id)initWithInt:(int)value;
@end @class NSString;
-@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
-@end @interface NSArray (NSArrayCreation) + (id)array;
-@end @interface NSAutoreleasePool : NSObject {
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+@end
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+ @interface NSAutoreleasePool : NSObject {
}
- (void)drain;
- (id)init;
@@ -385,3 +390,45 @@ CFDateRef returnsRetainedCFDate() {
return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}}
}
@end
+
+
+#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
+
+void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void));
+void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void));
+
+void testConsumeAndStopTracking() {
+ id retained = [@[] retain]; // +0, GC
+ consumeAndStopTracking(retained, ^{}); // no-warning
+
+ id doubleRetained = [[@[] retain] retain]; // +0, GC
+ consumeAndStopTracking(doubleRetained, ^{
+ [doubleRetained release];
+ }); // no-warning
+
+ id unretained = @[]; // +0
+ consumeAndStopTracking(unretained, ^{}); // no-warning, GC
+}
+
+void testCFConsumeAndStopTrackingMsg() {
+ id retained = [@[] retain]; // +0, GC
+ CFConsumeAndStopTracking((CFTypeRef)retained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFConsumeAndStopTracking() {
+ CFTypeRef retained = returnsRetainedCFDate(); // +1
+ CFConsumeAndStopTracking(retained, ^{}); // no-warning
+
+ CFTypeRef doubleRetained = CFRetain(returnsRetainedCFDate()); // +2
+ CFConsumeAndStopTracking(doubleRetained, ^{
+ CFRelease(doubleRetained);
+ }); // 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}}
+}
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
index 610df7f7e94a..6ff9e9a55264 100644
--- a/test/Analysis/retain-release-inline.m
+++ b/test/Analysis/retain-release-inline.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -fblocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -343,5 +343,21 @@ void test_test_return_inline_2(char *bytes) {
CFRelease(str);
}
+extern CFStringRef getString(void);
+CFStringRef testCovariantReturnType(void) __attribute__((cf_returns_retained));
+void usetestCovariantReturnType() {
+ CFStringRef S = ((void*)0);
+ S = testCovariantReturnType();
+ if (S)
+ CFRelease(S);
+}
+CFStringRef testCovariantReturnType() {
+ CFStringRef Str = ((void*)0);
+ Str = getString();
+ if (Str) {
+ CFRetain(Str);
+ }
+ return Str;
+}
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index feee525b85a3..c24bf704e45c 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -1,5 +1,6 @@
// 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 - | FileCheck %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: FileCheck --input-file=%t.plist %s
/***
This file is for testing the path-sensitive notes for retain/release errors.
@@ -72,1339 +73,1328 @@ void retainReleaseIgnored () {
}
@end
-
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: <string>{{.*}}retain-release-path-notes-gc.m</string>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>42</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of object when using garbage collection</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>creationViaCFCreate</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>43</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>47</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count incremented. The object now has a +2 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count incremented. The object now has a +2 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>48</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>In GC mode a call to &apos;CFMakeCollectable&apos; decrements an object&apos;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</string>
-// CHECK: <key>message</key>
-// CHECK: <string>In GC mode a call to &apos;CFMakeCollectable&apos; decrements an object&apos;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</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>49</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>In GC mode a call to &apos;NSMakeCollectable&apos; decrements an object&apos;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</string>
-// CHECK: <key>message</key>
-// CHECK: <string>In GC mode a call to &apos;NSMakeCollectable&apos; decrements an object&apos;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</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>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</string>
-// CHECK: <key>message</key>
-// CHECK: <string>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</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of object when using garbage collection</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>makeCollectable</string>
-// CHECK: <key>issue_hash</key><integer>6</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>In GC mode the &apos;retain&apos; message has no effect</string>
-// CHECK: <key>message</key>
-// CHECK: <string>In GC mode the &apos;retain&apos; message has no effect</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>In GC mode the &apos;release&apos; message has no effect</string>
-// CHECK: <key>message</key>
-// CHECK: <string>In GC mode the &apos;release&apos; message has no effect</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>In GC mode an &apos;autorelease&apos; has no effect</string>
-// CHECK: <key>message</key>
-// CHECK: <string>In GC mode an &apos;autorelease&apos; has no effect</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>13</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>29</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>retainReleaseIgnored</string>
-// CHECK: <key>issue_hash</key><integer>5</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>60</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;getViolation&apos; 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</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;getViolation&apos; 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</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;object&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of returned object when using garbage collection</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>getViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>66</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>36</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;copyViolation&apos; 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</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;copyViolation&apos; 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</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;object&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of returned object when using garbage collection</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>copyViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>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>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>43</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>43</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>43</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>43</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>43</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. Core Foundation objects are not automatically garbage collected</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. Core Foundation objects are not automatically garbage collected</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>43</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>43</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>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>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>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>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 leaked: object allocated and stored into &apos;leaked&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;leaked&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 (when using garbage collection) of an object stored into &apos;leaked&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of object when using garbage collection</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>creationViaCFCreate</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// 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: </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>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>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>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>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>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>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>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. Core Foundation objects are not automatically garbage collected</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. Core Foundation objects are not automatically garbage collected</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>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>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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</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>49</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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</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>49</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>49</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>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>49</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>49</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>50</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>50</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>50</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>In GC mode a call to &apos;CFMakeCollectable&apos; decrements an object&apos;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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>In GC mode a call to &apos;CFMakeCollectable&apos; decrements an object&apos;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</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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</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>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>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>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>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>51</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>51</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>In GC mode a call to &apos;NSMakeCollectable&apos; decrements an object&apos;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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>In GC mode a call to &apos;NSMakeCollectable&apos; decrements an object&apos;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</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>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>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>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>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>52</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>52</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>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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>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</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>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>Object leaked: object allocated and stored into &apos;leaked&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;leaked&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 (when using garbage collection) of an object stored into &apos;leaked&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of object when using garbage collection</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>makeCollectable</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// 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: </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>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>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>57</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>57</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>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>57</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>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>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>57</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>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>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>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>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>In GC mode the &apos;retain&apos; message has no effect</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>In GC mode the &apos;retain&apos; message has no effect</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>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>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>In GC mode the &apos;release&apos; message has no effect</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>In GC mode the &apos;release&apos; message has no effect</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>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>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>60</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>60</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>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>60</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>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>60</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>In GC mode an &apos;autorelease&apos; has no effect</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>In GC mode an &apos;autorelease&apos; has no effect</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>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>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>61</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>61</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>61</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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>retainReleaseIgnored</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <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>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>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>66</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>66</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>66</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>66</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>66</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>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</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. Core Foundation objects are not automatically garbage collected</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>66</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>66</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>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>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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>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>67</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>67</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>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>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>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;getViolation&apos; 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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;getViolation&apos; 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</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;object&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of returned object when using garbage collection</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>getViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </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>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>71</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>71</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>71</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>71</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>71</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>71</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>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected</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. Core Foundation objects are not automatically garbage collected</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>71</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>71</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>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>72</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>72</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>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>72</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>72</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>72</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>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>72</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>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>72</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>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;copyViolation&apos; 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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;object&apos; and returned from method &apos;copyViolation&apos; 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</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak (when using garbage collection) of an object stored into &apos;object&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of returned object when using garbage collection</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>copyViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: </array>
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index ebcfd6adf5d4..0daeecb39c9b 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -1,5 +1,6 @@
// 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
-// RN: %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 - | FileCheck %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: FileCheck --input-file=%t %s
/***
This file is for testing the path-sensitive notes for retain/release errors.
@@ -190,4424 +191,4414 @@ void testDictionary(id key, id value) {
}
-// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-// CHECK: <plist version="1.0">
-// CHECK: <dict>
-// CHECK: <key>files</key>
-// CHECK: <array>
-// CHECK: <string>{{.*}}retain-release-path-notes.m</string>
-// CHECK: </array>
// CHECK: <key>diagnostics</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>45</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>creationViaAlloc</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>46</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>50</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>creationViaCFCreate</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>51</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>55</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count incremented. The object now has a +2 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count incremented. The object now has a +2 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count decremented. The object now has a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count decremented. The object now has a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>58</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>acquisitionViaMethod</string>
-// CHECK: <key>issue_hash</key><integer>5</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>59</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>63</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>64</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>acquisitionViaProperty</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>65</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>69</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>12</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>17</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference count incremented. The object now has a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>70</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>acquisitionViaCFFunction</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>71</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>75</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object released by directly sending the &apos;-dealloc&apos; message</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object released by directly sending the &apos;-dealloc&apos; message</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>76</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference-counted object is used after it is released</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference-counted object is used after it is released</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Reference-counted object is used after it is released</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Use-after-release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>explicitDealloc</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>77</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>81</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object released</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object released</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>82</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Reference-counted object is used after it is released</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Reference-counted object is used after it is released</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Reference-counted object is used after it is released</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Use-after-release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>implicitDealloc</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>83</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>87</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>88</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>89</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object sent -autorelease too many times</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Object sent -autorelease too many times</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>overAutorelease</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>90</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>94</integer>
-// CHECK: <key>col</key><integer>31</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>95</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object sent -autorelease too many times</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Object sent -autorelease too many times</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>autoreleaseUnowned</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>96</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>100</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>When GC is not enabled a call to &apos;CFMakeCollectable&apos; has no effect on its argument</string>
-// CHECK: <key>message</key>
-// CHECK: <string>When GC is not enabled a call to &apos;CFMakeCollectable&apos; has no effect on its argument</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>101</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>21</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>26</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>When GC is not enabled a call to &apos;NSMakeCollectable&apos; has no effect on its argument</string>
-// CHECK: <key>message</key>
-// CHECK: <string>When GC is not enabled a call to &apos;NSMakeCollectable&apos; has no effect on its argument</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>102</integer>
-// CHECK: <key>col</key><integer>19</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;leaked&apos; is not referenced later in this execution path and has a retain count of +1</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;leaked&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>makeCollectableIgnored</string>
-// CHECK: <key>issue_hash</key><integer>4</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>103</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>37</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFGetSomething&apos; returns a Core Foundation object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>107</integer>
-// CHECK: <key>col</key><integer>35</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Method should return an owned object</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>CFCopyRuleViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>108</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>11</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>40</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFCreateSomething&apos; returns a Core Foundation object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>112</integer>
-// CHECK: <key>col</key><integer>38</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; is returned from a function whose name (&apos;CFGetRuleViolation&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;object&apos; is returned from a function whose name (&apos;CFGetRuleViolation&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;object&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of returned object</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>CFGetRuleViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>113</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>32</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>32</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Property returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>118</integer>
-// CHECK: <key>col</key><integer>32</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Method should return an owned object</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>copyViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>119</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Subscript returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Subscript returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>123</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Method should return an owned object</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>copyViolationIndexedSubscript</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>124</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Subscript returns an Objective-C object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Subscript returns an Objective-C object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>128</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Method should return an owned object</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>copyViolationKeyedSubscript</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>129</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>32</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>133</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;result&apos; is returned from a method whose name (&apos;getViolation&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object leaked: object allocated and stored into &apos;result&apos; is returned from a method whose name (&apos;getViolation&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;result&apos;</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Leak of returned object</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>getViolation</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>134</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>32</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Method returns an Objective-C object with a +1 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>138</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>22</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object sent -autorelease message</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>139</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>10</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object returned to caller with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Method should return an owned object</string>
-// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK: <key>issue_context</key><string>copyAutorelease</string>
-// CHECK: <key>issue_hash</key><integer>3</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>140</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>16</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>NSNumber literal is an object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>NSNumber literal is an object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>168</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testNumericLiteral</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>169</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>18</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>NSNumber boxed expression produces an object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>NSNumber boxed expression produces an object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>173</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testBoxedInt</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>174</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>NSString boxed expression produces an object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>NSString boxed expression produces an object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>178</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testBoxedString</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>179</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>20</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>NSArray literal is an object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>NSArray literal is an object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>183</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testArray</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>184</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>path</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>27</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>NSDictionary literal is an object with a +0 retain count</string>
-// CHECK: <key>message</key>
-// CHECK: <string>NSDictionary literal is an object with a +0 retain count</string>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>control</string>
-// CHECK: <key>edges</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>start</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>188</integer>
-// CHECK: <key>col</key><integer>15</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>end</key>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>4</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>9</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>depth</key><integer>0</integer>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
-// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
-// CHECK: <key>type</key><string>Bad release</string>
-// CHECK: <key>issue_context_kind</key><string>function</string>
-// CHECK: <key>issue_context</key><string>testDictionary</string>
-// CHECK: <key>issue_hash</key><integer>2</integer>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>189</integer>
-// CHECK: <key>col</key><integer>3</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </dict>
-// CHECK: </plist>
+// 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>46</integer>
+// CHECK-NEXT: <key>col</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>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>46</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>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>46</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>46</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>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>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>46</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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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: </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;leaked&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;leaked&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;leaked&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>creationViaAlloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>51</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>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>51</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>51</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>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>51</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>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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>Object leaked: object allocated and stored into &apos;leaked&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;leaked&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;leaked&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>creationViaCFCreate</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// 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: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>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>56</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>56</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>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>56</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>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>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>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>57</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>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>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>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>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 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>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>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>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>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>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>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 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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>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>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>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>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>60</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>60</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>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>60</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 leaked: object allocated and stored into &apos;leaked&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;leaked&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;leaked&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>acquisitionViaMethod</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>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>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>64</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>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>64</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>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Property returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Property 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>64</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>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>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>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>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>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>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>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 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>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>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>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>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>66</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>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>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 leaked: object allocated and stored into &apos;leaked&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;leaked&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;leaked&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>acquisitionViaProperty</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>70</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>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>70</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>70</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>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>70</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>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>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>71</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>71</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>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>71</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>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>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>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>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>71</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>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>72</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>72</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>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>72</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 leaked: object allocated and stored into &apos;leaked&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;leaked&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;leaked&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>acquisitionViaCFFunction</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>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>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>76</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>76</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>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>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>76</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>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>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>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>77</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>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>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>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>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>Object released by directly sending the &apos;-dealloc&apos; message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released by directly sending the &apos;-dealloc&apos; message</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>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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>explicitDealloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>82</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>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>82</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>82</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>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>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>82</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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>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>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>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>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>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>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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>implicitDealloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// 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: </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>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>88</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>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>88</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>88</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>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>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>88</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>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>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>89</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>89</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>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>89</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>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>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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>89</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>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>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>90</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>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>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>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>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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>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>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>91</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>91</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>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>91</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 over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>overAutorelease</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>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>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>95</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>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// 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>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>95</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>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Property returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Property 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>95</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>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>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>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>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>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>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>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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>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>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>97</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>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>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 over-autoreleased: object was sent -autorelease but the object has a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>autoreleaseUnowned</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>101</integer>
+// CHECK-NEXT: <key>col</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>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>101</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>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>101</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>101</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>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>101</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>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>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>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>102</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>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>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>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>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>When GC is not enabled a call to &apos;CFMakeCollectable&apos; has no effect on its argument</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>When GC is not enabled a call to &apos;CFMakeCollectable&apos; has no effect on its argument</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>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>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>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>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>103</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>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>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>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>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>When GC is not enabled a call to &apos;NSMakeCollectable&apos; has no effect on its argument</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>When GC is not enabled a call to &apos;NSMakeCollectable&apos; has no effect on its argument</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>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>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>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>104</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>104</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>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>104</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 leaked: object allocated and stored into &apos;leaked&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;leaked&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;leaked&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>makeCollectableIgnored</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>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>108</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>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>108</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>108</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>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>108</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>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>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>109</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>109</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>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>109</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>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>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>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>109</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>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>109</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>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>CFCopyRuleViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>113</integer>
+// CHECK-NEXT: <key>col</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>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>113</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>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>113</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>113</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>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>113</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>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>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>114</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>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>114</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>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>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>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>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>114</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>Object leaked: object allocated and stored into &apos;object&apos; is returned from a function whose name (&apos;CFGetRuleViolation&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;object&apos; is returned from a function whose name (&apos;CFGetRuleViolation&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;object&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>CFGetRuleViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>119</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>col</key><integer>32</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>119</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>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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Property returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Property 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>119</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>col</key><integer>32</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>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>120</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>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>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>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>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>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>120</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>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>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>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>copyViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>124</integer>
+// CHECK-NEXT: <key>col</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>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>124</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>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>124</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>124</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>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>Subscript returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Subscript 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>124</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>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>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>125</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>125</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>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>125</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>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>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>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>125</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>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>125</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>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>copyViolationIndexedSubscript</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>129</integer>
+// CHECK-NEXT: <key>col</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>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>129</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>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>129</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>129</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>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>Subscript returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Subscript 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>129</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>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>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>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>130</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>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>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>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>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>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>130</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>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>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>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>copyViolationKeyedSubscript</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>134</integer>
+// CHECK-NEXT: <key>col</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>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>134</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>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>134</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>134</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>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>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>134</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>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>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>135</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>135</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>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>135</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>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>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>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>135</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>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>135</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>Object leaked: object allocated and stored into &apos;result&apos; is returned from a method whose name (&apos;getViolation&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;result&apos; is returned from a method whose name (&apos;getViolation&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;result&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>getViolation</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>139</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>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>139</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>139</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>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>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>139</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>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>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>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>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>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>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>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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>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>141</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>141</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>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>141</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>141</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>141</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>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>141</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>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>141</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>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>copyAutorelease</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>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>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>169</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>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>169</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>169</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>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>NSNumber literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSNumber literal is an 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>169</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>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>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>170</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>170</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>170</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>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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testNumericLiteral</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>174</integer>
+// CHECK-NEXT: <key>col</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>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>174</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>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>174</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>174</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>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>NSNumber boxed expression produces an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSNumber boxed expression produces an 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>174</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>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>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>175</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>175</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>175</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>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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testBoxedInt</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>179</integer>
+// CHECK-NEXT: <key>col</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>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>179</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>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>179</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>179</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>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>NSString boxed expression produces an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSString boxed expression produces an 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>179</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>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>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>180</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>180</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>180</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>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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testBoxedString</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: <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>184</integer>
+// CHECK-NEXT: <key>col</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>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>184</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>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>184</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>184</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>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>NSArray literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSArray literal is an 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>184</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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// 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>
+// 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: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testArray</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>189</integer>
+// CHECK-NEXT: <key>col</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>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>189</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>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>189</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>189</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>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>NSDictionary literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSDictionary literal is an 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>189</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>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>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>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>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>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>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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testDictionary</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: </array>
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index ba492b7b19a7..eb2554f8897d 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -Wno-objc-root-class %s
+// RUN: rm -f %t.objc.plist %t.objcpp.plist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s -analyzer-output=plist -o %t.objc.plist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -std=gnu++98 -Wno-objc-root-class %s -analyzer-output=plist -o %t.objcpp.plist
+// FIXLATER: cat %t.objc.plist ; FileCheck --input-file=%t.objc.plist %s
+// FIXLATER: cat %t.objcpp.plist ; FileCheck --input-file=%t.objcpp.plist %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
@@ -59,6 +62,7 @@ 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;
@@ -303,6 +307,10 @@ extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
// 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.
@@ -501,31 +509,39 @@ void f15() {
CFRelease(*B); // no-warning
}
-// Test when we pass NULL to CFRetain/CFRelease.
+// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
void f16(int x, CFTypeRef p) {
if (p)
return;
- if (x) {
+ if (x > 0) {
CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
}
- else {
+ 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) {
+ if (x > 0) {
CFRelease(p);
if (!p)
CFRelease(0); // no-warning
}
- else {
+ 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
@@ -828,8 +844,8 @@ int RDar6320065_test() {
@end
void test_RDar6859457(RDar6859457 *x, void *bytes, NSUInteger dataLength) {
- [x NoCopyString]; // no-warning
- [x noCopyString]; // no-warning
+ [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
}
@@ -1341,6 +1357,15 @@ void testattr4() {
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;
@@ -1748,7 +1773,7 @@ extern id NSApp;
@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.
@@ -1855,3 +1880,22797 @@ id makeCollectableNonLeak() {
[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
+}
+
+// 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>319</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>319</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>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>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>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>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>320</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>320</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>320</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>320</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>320</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>320</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>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>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>321</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>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>16</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>321</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>321</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>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>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>322</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>322</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>322</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>322</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>322</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>322</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>322</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>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>322</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>322</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>324</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>324</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>324</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>324</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>324</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>324</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>324</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>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>324</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>324</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>325</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>325</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>325</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>325</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>325</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>325</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>325</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>325</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>325</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f1</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>325</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>330</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>330</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>331</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>331</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>331</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>331</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>331</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>331</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>331</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>331</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>331</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>331</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>331</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>332</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>332</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>332</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>332</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>332</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>332</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>332</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: </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>332</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>332</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>333</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>333</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>333</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>333</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>333</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>333</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>333</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>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>333</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>333</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>335</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>335</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>335</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>335</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>335</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>335</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>335</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>335</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>335</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>336</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>336</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>336</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>336</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>336</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>336</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>336</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>336</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>336</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>336</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>366</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>366</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>367</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>367</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>367</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>367</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>367</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>367</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>367</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>367</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>367</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>367</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>367</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>369</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>369</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>369</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>369</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>369</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>369</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>369</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>369</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>369</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>369</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>369</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>372</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>372</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>372</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>372</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>372</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>372</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>372</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>372</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>372</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 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>f5</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>372</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>378</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>378</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>378</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>378</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>378</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>378</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>378</integer>
+// CHECK-NEXT: <key>col</key><integer>62</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>378</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>378</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>379</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>379</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>379</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>379</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>379</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>379</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>379</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>379</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>379</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>380</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>380</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>380</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>380</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>380</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>380</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>380</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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>380</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>380</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>381</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>381</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>381</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>f6</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>381</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>386</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>386</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>386</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>386</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>386</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>386</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>386</integer>
+// CHECK-NEXT: <key>col</key><integer>62</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>386</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>386</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>387</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>387</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>387</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>387</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>387</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>387</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>387</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>387</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>387</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>389</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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>389</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>389</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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 leaked: object allocated and stored into &apos;date&apos; is not referenced later in this execution path and has a retain count of +2</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 +2</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>f7</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</integer>
+// 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>386</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>386</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>388</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>388</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>388</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>388</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>388</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>388</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>388</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>388</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>388</integer>
+// CHECK-NEXT: <key>col</key><integer>52</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>388</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>388</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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>389</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>389</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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>389</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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>389</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>389</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</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 leaked: object allocated and stored into &apos;date&apos; is returned from a function whose name (&apos;f7&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;date&apos; is returned from a function whose name (&apos;f7&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f7</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>389</integer>
+// 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>397</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>397</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>397</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>397</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>397</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>397</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>397</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>Call to function &apos;MyDateCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;MyDateCreate&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>397</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>397</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>398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>398</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>398</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>398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>398</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>398</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>398</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>398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>398</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>399</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>399</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>399</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>399</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>399</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>399</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>399</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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>399</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>399</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>400</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>400</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>400</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>f8</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>400</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>403</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>403</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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>404</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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>404</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>406</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>406</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>406</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>406</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>406</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>406</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>406</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>406</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>406</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;date&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;date&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>406</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>406</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>406</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>406</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>406</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>406</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>406</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>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>f9</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>415</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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>415</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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>75</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;DADiskCreateFromBSDName&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADiskCreateFromBSDName&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>415</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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>416</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>416</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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>48</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>48</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>48</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>48</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>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;disk&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;disk&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;disk&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>col</key><integer>48</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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</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>421</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>421</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>421</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>49</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;DADiskCopyDescription&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADiskCopyDescription&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>421</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>421</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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</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>422</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>422</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>422</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>422</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;dict&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dict&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>422</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>422</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>422</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>422</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>422</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>422</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>422</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>422</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>422</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>422</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>422</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>Object leaked: object allocated and stored into &apos;dict&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;dict&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;dict&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>422</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: <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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</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>422</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>422</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>422</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>422</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;dict&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dict&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>422</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>422</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>424</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>424</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>424</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>424</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>424</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADiskCopyWholeDisk&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADiskCopyWholeDisk&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>424</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>424</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</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>425</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>425</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>425</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>425</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;disk&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>425</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>425</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>425</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>425</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>425</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>425</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>425</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>425</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>425</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>425</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>425</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>Object leaked: object allocated and stored into &apos;disk&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;disk&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;disk&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>11</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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: <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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</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>418</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>63</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;DADiskCreateFromIOMedia&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADiskCreateFromIOMedia&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>418</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>418</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>419</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>419</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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</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>422</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>422</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>422</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>422</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;dict&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dict&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>422</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>422</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</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>425</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>425</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>425</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>425</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>425</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>425</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>428</integer>
+// CHECK-NEXT: <key>col</key><integer>67</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>428</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>col</key><integer>67</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>col</key><integer>67</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>428</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>Object leaked: object allocated and stored into &apos;disk&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;disk&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;disk&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>14</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>col</key><integer>67</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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</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>422</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>422</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>422</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>422</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;dict&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dict&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>422</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>422</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</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>425</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>425</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>425</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>425</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>425</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>425</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>427</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>427</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>428</integer>
+// CHECK-NEXT: <key>col</key><integer>68</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;DADissenterCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DADissenterCreate&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>427</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>427</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>429</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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>429</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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>429</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>429</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>429</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>429</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>429</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;dissenter&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dissenter&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>429</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>429</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>429</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>429</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>429</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>429</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>429</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>429</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>429</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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>429</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>Object leaked: object allocated and stored into &apos;dissenter&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;dissenter&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;dissenter&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>15</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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: <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>415</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>415</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>416</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>416</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>416</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>416</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>416</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>416</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>416</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>416</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>418</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>419</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>419</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>419</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>419</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>419</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>419</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>419</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>419</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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>421</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>422</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>422</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>422</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>422</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>422</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;dict&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dict&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>422</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>422</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>424</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>424</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>425</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>425</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>425</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>425</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>425</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>425</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;disk&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;disk&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>425</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>425</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>427</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>427</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>429</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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>429</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>429</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>429</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>429</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>429</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>429</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>429</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;dissenter&apos; is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;dissenter&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>429</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>429</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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>431</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>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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>431</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>431</integer>
+// CHECK-NEXT: <key>col</key><integer>61</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;DASessionCreate&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;DASessionCreate&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>431</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>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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>432</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>432</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>432</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>432</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>432</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>432</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>432</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>432</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>Assuming &apos;session&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;session&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>432</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>432</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>432</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>432</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>432</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>432</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>432</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>432</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>432</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>432</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>432</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>Object leaked: object allocated and stored into &apos;session&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;session&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;session&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>f10</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>18</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>432</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: <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>438</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>438</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>451</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>451</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>451</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>451</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>451</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>451</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>451</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>451</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>451</integer>
+// CHECK-NEXT: <key>col</key><integer>49</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CFArrayGetValueAtIndex&apos; returns a Core Foundation object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayGetValueAtIndex&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>451</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>451</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>3</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>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>457</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>457</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>457</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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f11</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>21</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>457</integer>
+// 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>465</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>465</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>465</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>465</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>465</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>465</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>465</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>Call to function &apos;MyCreateFun&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;MyCreateFun&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>465</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>465</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>466</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>466</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>466</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>f12</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>466</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>474</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>474</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>474</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>474</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>474</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>474</integer>
+// CHECK-NEXT: <key>col</key><integer>75</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>474</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>474</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>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>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>475</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>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>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>475</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>475</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>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>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>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>476</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>476</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>476</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>477</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>477</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>477</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>476</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 over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_b</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>477</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>480</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>480</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>480</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>480</integer>
+// CHECK-NEXT: <key>col</key><integer>75</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>480</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>480</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <key>ranges</key>
+// CHECK-NEXT: <array>
+// 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>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>481</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>481</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>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>482</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>482</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>482</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>482</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>482</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>482</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>482</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>482</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>482</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>483</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>483</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>483</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>483</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>483</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 over-autoreleased: object was sent -autorelease 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_c</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>483</integer>
+// 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>487</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>487</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>487</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>487</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>487</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>487</integer>
+// CHECK-NEXT: <key>col</key><integer>75</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>487</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>487</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>488</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>488</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>488</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>488</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>488</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>488</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>488</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>488</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>488</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>489</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>489</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>489</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>489</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>489</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>489</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>489</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>489</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>489</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>490</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>490</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>490</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>490</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>490</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>490</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>490</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>490</integer>
+// CHECK-NEXT: <key>col</key><integer>75</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_d</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>490</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: <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>498</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>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>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>Call to function &apos;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>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>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>499</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>499</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>499</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>f14_leakimmediately</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>499</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>513</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>513</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>513</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>513</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>513</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>513</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>513</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 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>513</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>513</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>513</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 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>513</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>513</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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>516</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>516</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>516</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>516</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>516</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 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>516</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>516</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>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>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>517</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>517</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>517</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>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f16</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>513</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>513</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>513</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>513</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>513</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>513</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>513</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 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>513</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>513</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>513</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 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>513</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>513</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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>516</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>516</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>516</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>516</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>516</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>516</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>516</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>516</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>520</integer>
+// 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>520</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>520</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>520</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>520</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>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f16</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>520</integer>
+// 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>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>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>561</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>561</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>561</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>561</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>561</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>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>561</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>561</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>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>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>562</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>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>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>562</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>562</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 returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>562</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>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>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 with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>newString</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>575</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>575</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>575</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>575</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>575</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>575</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>575</integer>
+// CHECK-NEXT: <key>col</key><integer>63</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>575</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>575</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</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>582</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>582</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>582</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>582</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;name&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;name&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>582</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>582</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>583</integer>
+// 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>583</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>583</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>583</integer>
+// 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>583</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 leaked: object allocated and stored into &apos;kind&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;kind&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;kind&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>rdar_6659160</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>13</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>583</integer>
+// 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>575</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>575</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</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>582</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>582</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>582</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>582</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;name&apos; is non-nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;name&apos; is non-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>582</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>582</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>585</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>585</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>585</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;kindC&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;kindC&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>585</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>593</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>593</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>593</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>593</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>593</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>593</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>593</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>593</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>593</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;kind&apos; is nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;kind&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>593</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>593</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>595</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>595</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>595</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>595</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>596</integer>
+// 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>596</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>596</integer>
+// 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>596</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>597</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>597</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>597</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>597</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>597</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>597</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>Array access (from variable &apos;kindC&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Array access (from variable &apos;kindC&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Array access (from variable &apos;kindC&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar_6659160</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>27</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>575</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>581</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>581</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>581</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>581</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>581</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>581</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>581</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>581</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>581</integer>
+// CHECK-NEXT: <key>col</key><integer>57</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>581</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>581</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>582</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>582</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>582</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>582</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>582</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>582</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;name&apos; is non-nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;name&apos; is non-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>582</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>582</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>585</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>585</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>593</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>593</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>593</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>593</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>593</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>593</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>593</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>593</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>593</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;kind&apos; is non-nil</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;kind&apos; is non-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>593</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>593</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>594</integer>
+// 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>594</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>594</integer>
+// 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>594</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>595</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>595</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>595</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>595</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>596</integer>
+// 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>596</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>596</integer>
+// 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>596</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>597</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>597</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>597</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>599</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>599</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>599</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>599</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>602</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>602</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>602</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>602</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>603</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>603</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>603</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>603</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>603</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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar_6659160</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>33</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>603</integer>
+// 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>625</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>625</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>625</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>625</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>625</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>625</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>625</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>625</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>625</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>626</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>626</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>626</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>626</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>626</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>626</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>626</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 released by directly sending the &apos;-dealloc&apos; message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released by directly sending the &apos;-dealloc&apos; message</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>626</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>626</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>627</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>627</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>627</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>627</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>627</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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>pr3820_ReleaseAfterDealloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>627</integer>
+// 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>633</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>633</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>634</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>634</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>634</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>634</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>634</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>634</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>634</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>634</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>634</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>634</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>634</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>635</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>635</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>635</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>635</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>635</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>635</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>635</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 released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>635</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>635</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>636</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>636</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>636</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>636</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>636</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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>pr3820_DeallocAfterRelease</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>636</integer>
+// 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>688</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>688</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>688</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>688</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>688</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>688</integer>
+// CHECK-NEXT: <key>col</key><integer>76</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>688</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>688</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>688</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>688</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>688</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>688</integer>
+// CHECK-NEXT: <key>col</key><integer>84</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>688</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>688</integer>
+// CHECK-NEXT: <key>col</key><integer>76</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>688</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>688</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>693</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>693</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>693</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;dict&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;dict&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;dict&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>applicationDidFinishLaunching:</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>693</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>700</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>700</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>700</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>700</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>700</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>700</integer>
+// CHECK-NEXT: <key>col</key><integer>76</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>700</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>700</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>700</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>700</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>700</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>700</integer>
+// CHECK-NEXT: <key>col</key><integer>84</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>700</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>700</integer>
+// CHECK-NEXT: <key>col</key><integer>76</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>700</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>700</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>701</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>701</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>701</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>701</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>703</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>703</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>703</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;dict&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;dict&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;dict&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>radar10102244</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>703</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>711</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>711</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>712</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>712</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>712</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>712</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>712</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>712</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>712</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>712</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>712</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 +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>712</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>712</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>713</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>713</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>713</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>713</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>713</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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar_6257780_Case1</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
+// 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>788</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>788</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>789</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>789</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>789</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>789</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>789</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: </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>789</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>789</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>791</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>791</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>791</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>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>_initReturningNewClassBad</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>791</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>793</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>793</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>794</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>794</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>794</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>794</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>794</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>794</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>794</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>794</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>794</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>794</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>794</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>795</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</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>795</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</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>795</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>795</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>795</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>795</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>795</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>795</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>795</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>795</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>795</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>795</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</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>795</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>795</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</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>795</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>795</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>795</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>795</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>initReturningNewClassBad2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>795</integer>
+// 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>833</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>833</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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>833</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>59</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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>833</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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: allocated object is returned from a method whose name (&apos;NoCopyString&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;NoCopyString&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>NoCopyString</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>0</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>833</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: <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>834</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>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>59</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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: allocated object is returned from a method whose name (&apos;noCopyString&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;noCopyString&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>noCopyString</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>0</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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: <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>838</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>838</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>839</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>839</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>839</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>839</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>839</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;noCopyString&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;noCopyString&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>834</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_RDar6859457&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_RDar6859457&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>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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>834</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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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>834</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>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>col</key><integer>59</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>839</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>839</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>839</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>Returning from &apos;noCopyString&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;noCopyString&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>839</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>839</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>842</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>842</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>842</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_RDar6859457</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>842</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>866</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</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>866</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>866</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>866</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>866</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>866</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>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>866</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>866</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>866</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</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>866</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>866</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</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>866</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>866</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>866</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;:&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;:&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>:</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>866</integer>
+// 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>896</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>896</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>896</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>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>896</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>896</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>900</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>900</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>900</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>rdar6902710</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>900</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>908</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>908</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>908</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>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method 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>908</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>908</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>909</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>909</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>909</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>rdar6945561</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>909</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>917</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>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>49</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;IOBSDNameMatching&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;IOBSDNameMatching&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>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</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>918</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>918</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>918</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>IOBSDNameMatching_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</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>921</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>921</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>921</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>Call to function &apos;IOServiceMatching&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;IOServiceMatching&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>921</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>921</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>922</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>922</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>922</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>IOServiceMatching_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>922</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>925</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>925</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>925</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>Call to function &apos;IOServiceNameMatching&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;IOServiceNameMatching&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>925</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>925</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>926</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>926</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>926</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>IOServiceNameMatching_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>926</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>933</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>933</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>933</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>933</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>933</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>933</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>Call to function &apos;CreateDict&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateDict&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>933</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>933</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>934</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>934</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>934</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>934</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>934</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>934</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>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>934</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>934</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>935</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>935</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>935</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>935</integer>
+// CHECK-NEXT: <key>col</key><integer>58</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>col</key><integer>65</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>IOServiceAddNotification_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>935</integer>
+// 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>940</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>940</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>940</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;IORegistryEntryIDMatching&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;IORegistryEntryIDMatching&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>940</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>940</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>941</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>941</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>941</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>IORegistryEntryIDMatching_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>941</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>945</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>945</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>945</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>Call to function &apos;IOOpenFirmwarePathMatching&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;IOOpenFirmwarePathMatching&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>945</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>945</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>946</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>946</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>946</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>IOOpenFirmwarePathMatching_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>946</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>949</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>949</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>949</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>949</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>949</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>949</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>Call to function &apos;CreateDict&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateDict&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>949</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>949</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</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>950</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</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: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>col</key><integer>50</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>950</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>950</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>951</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>951</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>951</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>951</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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>IOServiceGetMatchingService_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>951</integer>
+// 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>955</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>955</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>955</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>955</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>955</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>955</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>Call to function &apos;CreateDict&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateDict&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>955</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>955</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</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>956</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>col</key><integer>62</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>956</integer>
+// CHECK-NEXT: <key>col</key><integer>44</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>956</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>956</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>957</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>957</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>957</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>957</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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>IOServiceGetMatchingServices_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>957</integer>
+// 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>963</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>963</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>963</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>963</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>963</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>963</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>Call to function &apos;CreateDict&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateDict&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>963</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>963</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</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>964</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>col</key><integer>106</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>964</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>col</key><integer>73</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>964</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>964</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>965</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>965</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>965</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>965</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-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>IOServiceAddMatchingNotification_wrapper</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
+// 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>1003</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1003</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1006</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>1006</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1006</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>1006</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>1006</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>1006</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>1006</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>1006</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>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>1006</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>1006</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>1007</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>1007</integer>
+// CHECK-NEXT: <key>col</key><integer>56</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1007</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>1007</integer>
+// CHECK-NEXT: <key>col</key><integer>56</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1008</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>1008</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>1008</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1008</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>1008</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>1008</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</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count decremented</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>1008</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1008</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>1009</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1009</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>1009</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>1009</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1009</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>1009</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>1009</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 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>1009</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1009</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>1010</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1010</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>1010</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>1010</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1010</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>Object leaked: object allocated and stored into &apos;number&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;number&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;number&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>rdar_7152619</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// 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>1019</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1019</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>1030</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</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>1030</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</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>1031</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>1031</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>col</key><integer>41</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1031</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>1031</integer>
+// CHECK-NEXT: <key>col</key><integer>69</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CGColorSpaceCreateDeviceRGB&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CGColorSpaceCreateDeviceRGB&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>1031</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>1031</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</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>1030</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>1030</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</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>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>rdar_7184450</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// 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>1041</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1041</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>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>1053</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>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1053</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>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>68</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CGColorSpaceCreateDeviceRGB&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CGColorSpaceCreateDeviceRGB&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>1053</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>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>1052</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>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>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>rdar_7184450_pos</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// 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>1041</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1041</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>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>1052</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1052</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>1053</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>1053</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>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1053</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>1053</integer>
+// CHECK-NEXT: <key>col</key><integer>107</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CGGradientCreateWithColorComponents&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CGGradientCreateWithColorComponents&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>1053</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>1053</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>1057</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>1057</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>1057</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;myGradient&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;myGradient&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;myGradient&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>rdar_7184450_pos</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>17</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1057</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>1091</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1091</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>1091</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>1091</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>1091</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>1091</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>1091</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>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>1091</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>1091</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>1092</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>1092</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>1092</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;number&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;number&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;number&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>rdar_7299394_positive</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1092</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>1224</integer>
+// 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>1224</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>1226</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1226</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1226</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>1226</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1227</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CGBitmapContextCreateWithData&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CGBitmapContextCreateWithData&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>1226</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1226</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>1228</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>1228</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>1228</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>rdar_7358899</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>9</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1228</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>1244</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1244</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>1244</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>1244</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>1244</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>1244</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>1244</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>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>1244</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>1244</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>1245</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>1245</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>1245</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;y&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;y&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;y&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>rdar7265711_a</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1245</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>1264</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1264</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>1265</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1265</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>1265</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1265</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>1265</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>1265</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>1265</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>1265</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>1265</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>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>1265</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>1265</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>1266</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>1266</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>1266</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;number&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;number&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;number&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>rdar7306898</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1266</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>1275</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>1275</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1275</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>The &apos;release&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The &apos;release&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The &apos;release&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// 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>1275</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1275</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>1276</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1276</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>1276</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>1276</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1276</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>The &apos;retain&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The &apos;retain&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The &apos;retain&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// 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>1275</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1275</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>1277</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1277</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>1277</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>1277</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1277</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The &apos;autorelease&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The &apos;autorelease&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The &apos;autorelease&apos; message should be sent to instances of class &apos;RDar7252064&apos; and not the class directly</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// 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>1275</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1275</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>1278</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1278</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>1278</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>1278</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1278</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The &apos;drain&apos; message should be sent to instances of class &apos;NSAutoreleasePool&apos; and not the class directly</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The &apos;drain&apos; message should be sent to instances of class &apos;NSAutoreleasePool&apos; and not the class directly</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The &apos;drain&apos; message should be sent to instances of class &apos;NSAutoreleasePool&apos; and not the class directly</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// 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>1304</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1304</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>1304</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>1304</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>1304</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>1304</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>1304</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1304</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>1304</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>1305</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>1305</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>1305</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;str&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;str&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;str&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_attr_1</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1305</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>1308</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1308</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>1308</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>1308</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>1308</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>1308</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>1308</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>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method 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>1308</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>1308</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>1309</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>1309</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>1309</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;str&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;str&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;str&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_attr_1b</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1309</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>1312</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1312</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>1313</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1313</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>1313</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1313</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>1313</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>1313</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>1313</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>1313</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>1313</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>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>1313</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>1313</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>1314</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>1314</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>1314</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;str2&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;str2&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;str2&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_attr1c</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1314</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>1317</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1317</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>1317</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>1317</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>1317</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>1317</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>1317</integer>
+// CHECK-NEXT: <key>col</key><integer>50</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1317</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>1317</integer>
+// CHECK-NEXT: <key>col</key><integer>26</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1318</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>1318</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>1318</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;x&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;x&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;x&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>testattr2_a</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1318</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>1321</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1321</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>1321</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>1321</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>1321</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>1321</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>1321</integer>
+// CHECK-NEXT: <key>col</key><integer>63</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1321</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>1321</integer>
+// CHECK-NEXT: <key>col</key><integer>26</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1322</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>1322</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>1322</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;x&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;x&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;x&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>testattr2_b</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1322</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>1325</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1325</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>1325</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>1325</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>1325</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>1325</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>1325</integer>
+// CHECK-NEXT: <key>col</key><integer>63</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1325</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>1325</integer>
+// CHECK-NEXT: <key>col</key><integer>26</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1327</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>1327</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>1327</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;x&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;x&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;x&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>testattr2_b_11358224_self_assign_looses_the_leak</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1327</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>1357</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</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>1357</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>1357</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>1357</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>1357</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>1357</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>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>1357</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>1357</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>1357</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</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>1357</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>1357</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</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>1357</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>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1357</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>1357</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</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>Object leaked: allocated object is returned from a method that is annotated as NS_RETURNS_NOT_RETAINED</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method that is annotated as NS_RETURNS_NOT_RETAINED</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>newString</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// 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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</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>1390</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>1390</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>1390</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>1390</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>Calling &apos;returnsCFRetainedAsCF&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;returnsCFRetainedAsCF&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>1381</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;newCFRetainedAsCFNoAttr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;newCFRetainedAsCFNoAttr&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>1381</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>1381</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1382</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>1382</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1382</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>1382</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>1382</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1382</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>1382</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>1382</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;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;returnsRetainedCFDate&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>1371</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;returnsCFRetainedAsCF&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;returnsCFRetainedAsCF&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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>52</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1382</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>1382</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>1382</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsRetainedCFDate&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>1390</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>1390</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>1390</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsCFRetainedAsCF&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsCFRetainedAsCF&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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</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>1390</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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>26</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>66</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>1390</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>1390</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>Object sent -autorelease message</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object sent -autorelease message</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>1390</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>1390</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</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>1390</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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>66</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>1390</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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 returned to caller with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</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>1390</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>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>newCFRetainedAsCFNoAttr</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// 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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</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>1394</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>1394</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;returnsRetainedCFDate&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>1371</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;alsoReturnsRetained&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;alsoReturnsRetained&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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>52</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>42</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 from &apos;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsRetainedCFDate&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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</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>1394</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>1394</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>1394</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>42</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1394</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>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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: allocated object is returned from a method whose name (&apos;alsoReturnsRetained&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;alsoReturnsRetained&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>alsoReturnsRetained</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// 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>1398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>1398</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>1398</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;returnsRetainedCFDate&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>1371</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;alsoReturnsRetainedAsCF&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;alsoReturnsRetainedAsCF&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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1373</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>1373</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>1373</integer>
+// CHECK-NEXT: <key>col</key><integer>52</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>1398</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>Returning from &apos;returnsRetainedCFDate&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;returnsRetainedCFDate&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>1398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>1398</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>1398</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>1398</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>1398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>1398</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1398</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>1398</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;alsoReturnsRetainedAsCF&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a method whose name (&apos;alsoReturnsRetainedAsCF&apos;) does not start with &apos;copy&apos;, &apos;mutableCopy&apos;, &apos;alloc&apos; or &apos;new&apos;. This violates the naming convention rules given in the Memory Management Guide for Cocoa</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>alsoReturnsRetainedAsCF</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// 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>1418</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1418</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>1419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1419</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>1419</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1419</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>1419</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>1419</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1419</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>1419</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>1419</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>1419</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>1419</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>1420</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>1420</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>1420</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>test_panic_negative</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1420</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>1429</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1429</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>1430</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1430</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>1430</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1430</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>1430</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>1430</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1430</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>1430</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>1430</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>1430</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>1430</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>1431</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1431</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>1431</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1431</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>1431</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>1431</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>1431</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>1431</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>1431</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>1431</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>1431</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>1433</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>1433</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>1433</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>test_panic_neg_2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1433</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>1453</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1453</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>1453</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>1453</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>1453</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>1453</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>1453</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>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>1453</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>1453</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>1454</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1454</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>1454</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>1454</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1454</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>Object leaked: object allocated and stored into &apos;number&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;number&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;number&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_blocks_1_pos</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// 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>1474</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1474</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>1474</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>1474</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>1474</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>1474</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>1474</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>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>1474</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>1474</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>1475</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1475</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>1475</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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_blocks_1_indirect_retain_via_call&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_blocks_1_indirect_retain_via_call&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>1475</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1475</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>1475</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>1475</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>1475</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>1475</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1475</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>1</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>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1475</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning to caller</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>1475</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1475</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>1476</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>1476</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>1476</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;number&apos; is not referenced later in this execution path and has a retain count of +2</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;number&apos; is not referenced later in this execution path and has a retain count of +2</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;number&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_blocks_1_indirect_retain_via_call</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1476</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>1526</integer>
+// 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>1526</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>1529</integer>
+// 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>1529</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>1529</integer>
+// 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>1529</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>1530</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>1530</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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1530</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>1530</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1532</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>1532</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>1532</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>1532</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>1532</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>1532</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1532</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>1532</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>1532</integer>
+// CHECK-NEXT: <key>col</key><integer>49</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;CFErrorCopyUserInfo&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFErrorCopyUserInfo&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>1532</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>1532</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1534</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>1534</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>1534</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>1534</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>1534</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>1534</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>1534</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>1534</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>1534</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>Assuming &apos;info&apos; is not equal to null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;info&apos; is not 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>1534</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>1534</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>1537</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>1537</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1537</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>1537</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>1537</integer>
+// CHECK-NEXT: <key>col</key><integer>91</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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;info&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;info&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;info&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>rdar_8724287</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1537</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>1582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</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>1582</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>1582</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</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>1582</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>1582</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>1582</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>1582</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</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>1582</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>1582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</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>1582</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>1582</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1582</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>1582</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camelcase_createno&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camelcase_createno&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>camelcase_createno</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// 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>1590</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</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>1590</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>1590</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</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>1590</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>1590</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>1590</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>1590</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</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>1590</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>1590</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</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>1590</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>1590</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1590</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>1590</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camelcase_copying&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camelcase_copying&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>camelcase_copying</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// 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>1611</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</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>1611</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>1611</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</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>1611</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>1611</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>1611</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>1611</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</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>1611</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>1611</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</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>1611</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>1611</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1611</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>1611</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camel_creat&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camel_creat&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>camel_creat</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// 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>1623</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</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>1623</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>1623</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</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>1623</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>1623</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CFArrayCreateMutable&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>1623</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>1623</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</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>1623</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>1623</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</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>1623</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>1623</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object returned to caller as an owning reference (single retain count transferred to caller)</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>1623</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>1623</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camel_copymachine&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is returned from a function whose name (&apos;camel_copymachine&apos;) does not contain &apos;Copy&apos; or &apos;Create&apos;. This violates the naming convention rules given in the Memory Management Guide for Core Foundation</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 of returned object</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>camel_copymachine</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// 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>1643</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1643</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>1644</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1644</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>1644</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1644</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>1644</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>1644</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>1644</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>1644</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>1644</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>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>1644</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>1644</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>1645</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>1645</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>1645</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;vals&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;vals&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;vals&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>rdar6582778</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1645</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>1669</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1669</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>1671</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1671</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>1671</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1671</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>1671</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>1671</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>1671</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>1671</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>1671</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>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>1671</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>1671</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>1672</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1672</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>1672</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>1672</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1672</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>1672</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>1672</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>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>1672</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1672</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>1674</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</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>1674</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</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>1674</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</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>1674</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>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar10232019_positive</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>col</key><integer>27</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>1793</integer>
+// 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>1793</integer>
+// 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>1794</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>1794</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>1794</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>1794</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>1795</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>1795</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>1795</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>1795</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>1795</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>1795</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>1795</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>1795</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>1795</integer>
+// CHECK-NEXT: <key>col</key><integer>66</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1795</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>1795</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>1798</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>1798</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>1798</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>1798</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>1798</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>Object leaked: object allocated and stored into &apos;a&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;a&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;a&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_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1798</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>1793</integer>
+// 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>1793</integer>
+// 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>1794</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>1794</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>1794</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>1794</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>1804</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>1804</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>1804</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>1804</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>1804</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>1804</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>1804</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>1804</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>1804</integer>
+// CHECK-NEXT: <key>col</key><integer>56</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1804</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>1804</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1807</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>1807</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>1807</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>1807</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>1807</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>Object leaked: object allocated and stored into &apos;a2&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;a2&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;a2&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_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>15</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1807</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>1793</integer>
+// 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>1793</integer>
+// 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>1794</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>1794</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>1794</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>1794</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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>NSArray literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSArray literal is an 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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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>1812</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: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1812</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>1812</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: <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>1812</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>1812</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1815</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>1815</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>1815</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>1815</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>1815</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>Object leaked: object allocated and stored into &apos;a3&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;a3&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;a3&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_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>23</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1815</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>1793</integer>
+// 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>1793</integer>
+// 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>1794</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>1794</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>1794</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>1794</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>1820</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>1820</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>1820</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>1820</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>1820</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>1820</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>1820</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>1820</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>1820</integer>
+// CHECK-NEXT: <key>col</key><integer>57</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1820</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>1820</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>1824</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>1824</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>1824</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>1824</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>1824</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>Object leaked: object allocated and stored into &apos;a&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;a&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;a&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_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>32</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1824</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>1793</integer>
+// 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>1793</integer>
+// 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>1794</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>1794</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>1794</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>1794</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>1829</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>1829</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>1829</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>1829</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>1829</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>1829</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>1829</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>1829</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>1829</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>NSDictionary literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSDictionary literal is an 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>1829</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>1829</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>col</key><integer>43</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>1829</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>1829</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: </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>1829</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1829</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1833</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>1833</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>1833</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>1833</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>1833</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>Object leaked: object allocated and stored into &apos;a&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;a&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;a&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_arrays</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>41</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1833</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>1838</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1838</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>1838</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>1838</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>1838</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>1838</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>1838</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>NSNumber literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSNumber literal is an 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>1838</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>1838</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>1838</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>1838</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>1838</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>1838</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>1838</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>1838</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>1838</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>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>1838</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>1838</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>1840</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>1840</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>1840</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>test_objc_integer_literals</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1840</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>1843</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1843</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>1843</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>1843</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>1843</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>1843</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>1843</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>NSNumber boxed expression produces an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSNumber boxed expression produces an 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>1843</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>1843</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>1843</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>1843</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>1843</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>1843</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>1843</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>1843</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>1843</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 +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>1843</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>1843</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>1847</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1847</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>1847</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>1847</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1847</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>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>test_objc_boxed_expressions</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// 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>1843</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1843</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>1846</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1846</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>1846</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1846</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>1846</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>1846</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>1846</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>1846</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>1846</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>NSString boxed expression produces an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSString boxed expression produces an 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>1846</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>1846</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>1846</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>1846</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>1846</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>1846</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>1846</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>1846</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>1846</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 +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>1846</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>1846</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>1848</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>1848</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>1848</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>test_objc_boxed_expressions</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1848</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>1853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1853</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>1854</integer>
+// 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>1854</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>1854</integer>
+// 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>1854</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>1855</integer>
+// 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>1855</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>1855</integer>
+// 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>1855</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>1855</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>1855</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>1855</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>1855</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>1855</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;y&apos; is &lt;= 2</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is &lt;= 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>1855</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>1855</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>1858</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>1858</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>1858</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>1858</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>1858</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>1858</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1858</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>1858</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>1858</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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>1858</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>1858</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1859</integer>
+// 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>1859</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>1859</integer>
+// 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>1859</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>1860</integer>
+// 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>1860</integer>
+// 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>1860</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>1860</integer>
+// 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>1860</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: <dict>
+// CHECK-NEXT: <key>line</key><integer>1860</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>1860</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>Object released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object released</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>1860</integer>
+// 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>1860</integer>
+// 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>1861</integer>
+// 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>1861</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>1861</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>1861</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>1861</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Reference-counted object is used after it is released</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar11400885</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>9</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// 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>1880</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1880</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>1888</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1888</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>1888</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1888</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>1888</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>1888</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>1888</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>1888</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>1888</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>NSArray literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSArray literal is an 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>1888</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>1888</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>1889</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1889</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>1889</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>1889</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>1889</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testConsumeAndStopTracking</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>10</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// 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>1893</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1893</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>1901</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1901</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>1901</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1901</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>1901</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>1901</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>1901</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>1901</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>1901</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>NSArray literal is an object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>NSArray literal is an 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>1901</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>1901</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>1902</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1902</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>1902</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>1902</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>1902</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>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Incorrect decrement of the reference count of an object that is not owned at this point by the caller</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Bad release</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testCFConsumeAndStopTracking</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>10</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// 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>1914</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1914</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>1914</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>1914</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1914</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>1914</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>1914</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: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateMyCFType&apos; returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to function &apos;CreateMyCFType&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>1914</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>1914</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1915</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>1915</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>1915</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;x&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;x&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;x&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_custom_cf</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1915</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: </array>
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index 01727ea64434..d92237b185a2 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -366,3 +366,22 @@ NSString * radar11152419(NSString *string1, NSString *key1, NSMapTable *map) {
return string;
}
+//===----------------------------------------------------------------------===//
+// Don't crash on non-member functions with "callbacks" but without names.
+//===----------------------------------------------------------------------===//
+
+struct IntWrapper {
+ int arg;
+};
+
+int operator>> (const IntWrapper &W, int (*f)(int)) {
+ return f(W.arg);
+}
+
+void testCallback() {
+ IntWrapper val = { 42 };
+
+ extern int process(int);
+ val >> process;
+}
+
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index c2869cabae99..7759aa73b33b 100644
--- a/test/Analysis/security-syntax-checks-no-emit.c
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// expected-no-diagnostics
// This file complements 'security-syntax-checks.m', but tests that we omit
// specific checks on platforms where they don't make sense.
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
new file mode 100644
index 000000000000..2f09e5dd20e4
--- /dev/null
+++ b/test/Analysis/simple-stream-checks.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix.SimpleStream -verify %s
+
+#include "Inputs/system-header-simulator-for-simple-stream.h"
+
+void checkDoubleFClose(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ if (F != 0) {
+ fputs ("fopen example", F);
+ if (!Data)
+ fclose(F);
+ else
+ fputc(*Data, F);
+ fclose(F); // expected-warning {{Closing a previously closed file stream}}
+ }
+}
+
+int checkLeak(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ if (F != 0) {
+ fputs ("fopen example", F);
+ }
+
+ if (Data) // expected-warning {{Opened file is never closed; potential resource leak}}
+ return *Data;
+ else
+ return 0;
+}
+
+void checkLeakFollowedByAssert(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ if (F != 0) {
+ fputs ("fopen example", F);
+ if (!Data)
+ exit(0);
+ fclose(F);
+ }
+}
+
+void CloseOnlyOnValidFileHandle() {
+ FILE *F = fopen("myfile.txt", "w");
+ if (F)
+ fclose(F);
+ int x = 0; // no warning
+}
+
+void leakOnEnfOfPath1(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");// expected-warning {{Opened file is never closed; potential resource leak}}
+}
+
+void leakOnEnfOfPath2(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ return; // expected-warning {{Opened file is never closed; potential resource leak}}
+}
+
+FILE *leakOnEnfOfPath3(int *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ return F;
+}
+
+void myfclose(FILE *F);
+void SymbolEscapedThroughFunctionCall() {
+ FILE *F = fopen("myfile.txt", "w");
+ myfclose(F);
+ return; // no warning
+}
+
+FILE *GlobalF;
+void SymbolEscapedThroughAssignmentToGloabl() {
+ FILE *F = fopen("myfile.txt", "w");
+ GlobalF = F;
+ return; // no warning
+}
+
+void SymbolDoesNotEscapeThoughStringAPIs(char *Data) {
+ FILE *F = fopen("myfile.txt", "w");
+ fputc(*Data, F);
+ return; // expected-warning {{Opened file is never closed; potential resource leak}}
+}
diff --git a/test/Analysis/sizeofpointer.c b/test/Analysis/sizeofpointer.c
index aa85fc002aa1..a9e045b4af53 100644
--- a/test/Analysis/sizeofpointer.c
+++ b/test/Analysis/sizeofpointer.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core.SizeofPtr -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.SizeofPtr -verify %s
struct s {
};
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
index cbdb143c1857..a27bef793c47 100644
--- a/test/Analysis/stack-addr-ps.cpp
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -87,6 +87,6 @@ struct TS {
// rdar://11345441
int* f5() {
- int& i = i; // expected-warning {{Assigned value is garbage or undefined}} expected-note {{binding reference variable 'i' here}} expected-warning{{variable 'i' is uninitialized when used within its own initialization}}
+ int& i = i; // expected-warning {{Assigned value is garbage or undefined}} expected-note {{binding reference variable 'i' here}} expected-warning{{reference 'i' is not yet bound to a value when used within its own initialization}}
return &i; // expected-warning {{address of stack memory associated with local variable 'i' returned}}
}
diff --git a/test/Analysis/static_local.m b/test/Analysis/static_local.m
new file mode 100644
index 000000000000..dcd49e11a16c
--- /dev/null
+++ b/test/Analysis/static_local.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+// Test reasoning about static locals in ObjCMethods.
+int *getValidPtr();
+@interface Radar11275803
+- (int) useStaticInMethod;
+@end
+@implementation Radar11275803
+
+- (int) useStaticInMethod
+{
+ static int *explInit = 0;
+ static int implInit;
+ if (!implInit)
+ explInit = getValidPtr();
+ return *explInit; //no-warning
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c
index 4a095cffd028..329a7823f2e5 100644
--- a/test/Analysis/stream.c
+++ b/test/Analysis/stream.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.Stream -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.unix.Stream -analyzer-store region -verify %s
typedef __typeof__(sizeof(int)) size_t;
typedef struct _IO_FILE FILE;
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index 32f5db3a9a43..fd836c471bd4 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=experimental.security.taint,core,unix.cstring,experimental.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=alpha.security.taint,core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/svalbuilder-logic.c b/test/Analysis/svalbuilder-logic.c
index bc79f859053c..41d4fe21c2f0 100644
--- a/test/Analysis/svalbuilder-logic.c
+++ b/test/Analysis/svalbuilder-logic.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// expected-no-diagnostics
// Testing core functionality of the SValBuilder.
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
index 8ee1896e96e9..696db67713ae 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,core,experimental.security.ArrayBoundV2 -Wno-format-security -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -Wno-format-security -verify %s
int scanf(const char *restrict format, ...);
int getchar(void);
diff --git a/test/Analysis/taint-tester.c b/test/Analysis/taint-tester.c
index a83ee32baca8..7b0ab2a5fd34 100644
--- a/test/Analysis/taint-tester.c
+++ b/test/Analysis/taint-tester.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
#include <stdarg.h>
diff --git a/test/Analysis/taint-tester.cpp b/test/Analysis/taint-tester.cpp
index 679fbc2bf41a..f97eefb950e3 100644
--- a/test/Analysis/taint-tester.cpp
+++ b/test/Analysis/taint-tester.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// expected-no-diagnostics
typedef struct _FILE FILE;
typedef __typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/taint-tester.m b/test/Analysis/taint-tester.m
index ae55c6618dab..b5663ca02777 100644
--- a/test/Analysis/taint-tester.m
+++ b/test/Analysis/taint-tester.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,debug.TaintTest %s -verify
+// expected-no-diagnostics
#import <stdarg.h>
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 6dbbc821bbbb..c8844754bef8 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
// XPASS: *
diff --git a/test/Analysis/templates.cpp b/test/Analysis/templates.cpp
index 671aa7858204..faa5c1a76209 100644
--- a/test/Analysis/templates.cpp
+++ b/test/Analysis/templates.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -analyzer-config c++-template-inlining=false -DNO_INLINE -verify %s
void clang_analyzer_eval(bool);
@@ -39,6 +40,11 @@ inline unsigned array_lengthof(T (&)[N]) {
void testNonTypeTemplateInstantiation() {
const char *S[] = { "a", "b" };
- clang_analyzer_eval(array_lengthof(S) == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(array_lengthof(S) == 2);
+#ifndef NO_INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
}
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
new file mode 100644
index 000000000000..df1ab5a30bea
--- /dev/null
+++ b/test/Analysis/temporaries.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify -w %s
+
+struct Trivial {
+ Trivial(int x) : value(x) {}
+ int value;
+};
+
+struct NonTrivial : public Trivial {
+ NonTrivial(int x) : Trivial(x) {}
+ ~NonTrivial();
+};
+
+
+Trivial getTrivial() {
+ return Trivial(42); // no-warning
+}
+
+const Trivial &getTrivialRef() {
+ return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct Trivial' returned to caller}}
+}
+
+
+NonTrivial getNonTrivial() {
+ return NonTrivial(42); // no-warning
+}
+
+const NonTrivial &getNonTrivialRef() {
+ return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct NonTrivial' returned to caller}}
+}
+
diff --git a/test/Analysis/test-objc-non-nil-return-value-checker.m b/test/Analysis/test-objc-non-nil-return-value-checker.m
new file mode 100644
index 000000000000..8b1e6a5054a5
--- /dev/null
+++ b/test/Analysis/test-objc-non-nil-return-value-checker.m
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.NonNilReturnValue,debug.ExprInspection -verify %s
+
+typedef unsigned int NSUInteger;
+typedef signed char BOOL;
+
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSArray (NSExtendedArray)
+- (id)objectAtIndexedSubscript:(NSUInteger)idx;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
+@end
+
+@interface NSOrderedSet : NSObject
+@end
+@interface NSOrderedSet (NSOrderedSetCreation)
+- (id)objectAtIndexedSubscript:(NSUInteger)idx;
+@end
+
+void clang_analyzer_eval(id);
+
+void assumeThatNSArrayObjectAtIndexIsNeverNull(NSArray *A, NSUInteger i) {
+ clang_analyzer_eval([A objectAtIndex: i]); // expected-warning {{TRUE}}
+ id subscriptObj = A[1];
+ clang_analyzer_eval(subscriptObj); // expected-warning {{TRUE}}
+}
+
+void assumeThatNSMutableArrayObjectAtIndexIsNeverNull(NSMutableArray *A, NSUInteger i) {
+ clang_analyzer_eval([A objectAtIndex: i]); // expected-warning {{TRUE}}
+}
+
+void assumeThatNSArrayObjectAtIndexedSubscriptIsNeverNull(NSOrderedSet *A, NSUInteger i) {
+ clang_analyzer_eval(A[i]); // expected-warning {{TRUE}}
+} \ No newline at end of file
diff --git a/test/Analysis/traversal-path-unification.c b/test/Analysis/traversal-path-unification.c
new file mode 100644
index 000000000000..f53d2ff9fec1
--- /dev/null
+++ b/test/Analysis/traversal-path-unification.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.DumpTraversal -DUSE_EXPR %s | FileCheck %s
+
+int a();
+int b();
+int c();
+
+#ifdef USE_EXPR
+#define CHECK(x) ((x) & 1)
+#else
+#define CHECK(x) (x)
+#endif
+
+void testRemoveDeadBindings() {
+ int i = a();
+ if (CHECK(i))
+ a();
+ else
+ b();
+
+ // At this point the symbol bound to 'i' is dead.
+ // The effects of a() and b() are identical (they both invalidate globals).
+ // We should unify the two paths here and only get one end-of-path node.
+ c();
+}
+
+// CHECK: --END PATH--
+// CHECK-NOT: --END PATH-- \ No newline at end of file
diff --git a/test/Analysis/undef-buffers.c b/test/Analysis/undef-buffers.c
index cfdd7f4e1a83..f18d6e59a4eb 100644
--- a/test/Analysis/undef-buffers.c
+++ b/test/Analysis/undef-buffers.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix,core.uninitialized -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix,core.uninitialized -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index d613c7174f1a..614ce2fc3354 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,alpha.deadcode.IdempotentOperations -verify %s
struct s {
int data;
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index f3011570a85a..09736ef1e35e 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -122,3 +122,15 @@ int pr4631_f1_b(void)
return x; // no-warning
}
+void foo_radar12278788() { return; }
+void test_radar12278788() {
+ return foo_radar12278788(); // no-warning
+}
+
+void foo_radar12278788_fp() { return; }
+typedef int (*RetIntFuncType)();
+typedef void (*RetVoidFuncType)();
+int test_radar12278788_FP() {
+ RetVoidFuncType f = foo_radar12278788_fp;
+ return ((RetIntFuncType)f)(); //expected-warning {{Undefined or garbage value returned to caller}}
+}
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 4ba26f59b720..1cd57590df05 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// expected-no-diagnostics
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m
index 1a716847186f..3a9fb93bf8ad 100644
--- a/test/Analysis/unions-region.m
+++ b/test/Analysis/unions-region.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range %s -verify
+// expected-no-diagnostics
//===-- unions-region.m ---------------------------------------------------===//
//
diff --git a/test/Analysis/unions.cpp b/test/Analysis/unions.cpp
new file mode 100644
index 000000000000..2bffe78b41c2
--- /dev/null
+++ b/test/Analysis/unions.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core %s -verify
+// expected-no-diagnostics
+
+namespace PR14054_reduced {
+ struct Definition;
+ struct ParseNode {
+ union {
+ Definition *lexdef;
+ ParseNode *data;
+ } pn_u;
+ };
+ struct Definition : public ParseNode { };
+
+ void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
+ // This used to cause an assertion failure because:
+ // 1. The implicit operator= for unions assigns all members of the union,
+ // not just the active one (b/c there's no way to know which is active).
+ // 2. RegionStore dutifully stored all the variants at the same offset;
+ // the last one won.
+ // 3. We asked for the value of the first variant but got back a conjured
+ // symbol for the second variant.
+ // 4. We ended up trying to add a base cast to a region of the wrong type.
+ //
+ // Now (at the time this test was added), we instead treat all variants of
+ // a union as different offsets, but only allow one to be active at a time.
+ *pn = *opn;
+ x = pn->pn_u.lexdef->pn_u.lexdef;
+ }
+}
+
+namespace PR14054_original {
+ struct Definition;
+ struct ParseNode {
+ union {
+ struct {
+ union {};
+ Definition *lexdef;
+ } name;
+ class {
+ int *target;
+ ParseNode *data;
+ } xmlpi;
+ } pn_u;
+ };
+ struct Definition : public ParseNode { };
+
+ void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
+ pn->pn_u = opn->pn_u;
+ x = pn->pn_u.name.lexdef->pn_u.name.lexdef;
+ }
+}
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index ec620985d95a..edab5e162778 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=region -fblocks -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-ipa=inlining -analyzer-eagerly-assume -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
struct _opaque_pthread_once_t {
long __sig;
@@ -12,12 +13,31 @@ typedef __darwin_size_t size_t;
void *calloc(size_t, size_t);
void *malloc(size_t);
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;
+ struct dispatch_continuation_s *_dc;
+ struct dispatch_queue_s *_dq;
+ struct dispatch_queue_attr_s *_dqa;
+ struct dispatch_group_s *_dg;
+ struct dispatch_source_s *_ds;
+ struct dispatch_source_attr_s *_dsa;
+ struct dispatch_semaphore_s *_dsema;
+ struct dispatch_data_s *_ddata;
+ struct dispatch_io_s *_dchannel;
+ 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;
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
+void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
#ifndef O_CREAT
#define O_CREAT 0x0200
@@ -94,12 +114,24 @@ void test_realloc(char *ptr) {
foo[i] = 0;
}
}
+void test_reallocf(char *ptr) {
+ char *foo = reallocf(ptr, 0); // expected-warning{{Call to 'reallocf' has an allocation size of 0 bytes}}
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
void test_realloc_nowarn(char *ptr, size_t size) {
char *foo = realloc(ptr, size); // no-warning
for (unsigned i = 0; i < 100; i++) {
foo[i] = 0;
}
}
+void test_reallocf_nowarn(char *ptr, size_t size) {
+ char *foo = reallocf(ptr, size); // no-warning
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
void test_alloca() {
char *foo = alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}}
for(unsigned i = 0; i < 100; i++) {
@@ -136,3 +168,1826 @@ void test_valloc_nowarn(size_t sz) {
foo[i] = 0;
}
}
+
+// Test dispatch_once being a macro that wraps a call to _dispatch_once, which in turn
+// calls the real dispatch_once.
+
+static inline void _dispatch_once(dispatch_once_t *predicate, dispatch_block_t block)
+{
+ dispatch_once(predicate, block);
+}
+
+#define dispatch_once _dispatch_once
+
+void test_dispatch_once_in_macro() {
+ dispatch_once_t pred = 0;
+ dispatch_once(&pred, ^(){}); // expected-warning {{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}}
+}
+
+// Test inlining of dispatch_sync.
+void test_dispatch_sync(dispatch_queue_t queue, int *q) {
+ int *p = 0;
+ dispatch_sync(queue, ^(void){
+ if (q) {
+ *p = 1; // expected-warning {{null pointer}}
+ }
+ });
+}
+
+// Test inlining if dispatch_once.
+void test_inline_dispatch_once() {
+ static dispatch_once_t pred;
+ int *p = 0;
+ dispatch_once(&pred, ^(void) {
+ *p = 1; // expected-warning {{null}}
+ });
+}
+
+// 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>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// 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>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>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>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>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>52</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>52</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>52</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>52</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>52</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;fd&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;fd&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>52</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>52</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>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>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>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>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>55</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>55</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>55</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>55</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>55</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>Call to &apos;open&apos; requires a third argument when the &apos;O_CREAT&apos; flag is set</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;open&apos; requires a third argument when the &apos;O_CREAT&apos; flag is set</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;open&apos; requires a third argument when the &apos;O_CREAT&apos; flag is set</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Improper use of &apos;open&apos;</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_open</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>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>62</integer>
+// CHECK-NEXT: <key>col</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>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>62</integer>
+// CHECK-NEXT: <key>col</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>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>62</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>62</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>62</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>62</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>62</integer>
+// CHECK-NEXT: <key>col</key><integer>52</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>64</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>52</integer>
+// CHECK-NEXT: <key>file</key><integer>0</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>66</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>72</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </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 &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>category</key><string>Mac OS X API</string>
+// CHECK-NEXT: <key>type</key><string>Improper use of &apos;dispatch_once&apos;</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_dispatch_once</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>52</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>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>72</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>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>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>73</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>73</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>73</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>Call to &apos;pthread_once&apos; uses the local variable &apos;pred&apos; for the &quot;control&quot; value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;pthread_once&apos; uses the local variable &apos;pred&apos; for the &quot;control&quot; value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;pthread_once&apos; uses the local variable &apos;pred&apos; for the &quot;control&quot; value. Using such transient memory for the control value is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Improper use of &apos;pthread_once&apos;</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_pthread_once</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>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>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>82</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>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>82</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>82</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>82</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 &apos;malloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;malloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;malloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>pr2899</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>82</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>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>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>94</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>94</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>94</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>94</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>94</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 &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_calloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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>
+// 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>100</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>100</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>100</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>100</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>100</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>100</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>100</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>Call to &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;calloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_calloc2</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>100</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>112</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</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>112</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>112</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</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>112</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>112</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>Call to &apos;realloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;realloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;realloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_realloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</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>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>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>118</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>118</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>118</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>118</integer>
+// CHECK-NEXT: <key>col</key><integer>29</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>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>Call to &apos;reallocf&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;reallocf&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;reallocf&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_reallocf</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</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>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>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>136</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>136</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>136</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>136</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>136</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 &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_alloca</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// 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: </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>148</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</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>148</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: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-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>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>148</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>148</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>Call to &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;alloca&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_builtin_alloca</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>148</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>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>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>160</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>160</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>160</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>160</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>160</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 &apos;valloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;valloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;valloc&apos; has an allocation size of 0 bytes</string>
+// CHECK-NEXT: <key>category</key><string>Unix API</string>
+// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_valloc</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>location</key>
+// 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: </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>183</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>184</integer>
+// CHECK-NEXT: <key>col</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>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>184</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>184</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>184</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>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
+// CHECK-NEXT: <key>category</key><string>Mac OS X API</string>
+// CHECK-NEXT: <key>type</key><string>Improper use of &apos;dispatch_once&apos;</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_dispatch_once_in_macro</string>
+// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// 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>189</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>189</integer>
+// CHECK-NEXT: <key>col</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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &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>189</integer>
+// CHECK-NEXT: <key>col</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>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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;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>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>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>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>24</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_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;dispatch_sync&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>190</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>190</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>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>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>control</string>
+// CHECK-NEXT: <key>edges</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>4</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>8</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>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>191</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>191</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>191</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>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;q&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;q&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>191</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>191</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>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>event</string>
+// CHECK-NEXT: <key>location</key>
+// 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: <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>2</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>location</key>
+// 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: <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>199</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>199</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>200</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>200</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</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>201</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>201</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</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>Calling &apos;_dispatch_once&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &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>175</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_inline_dispatch_once&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_inline_dispatch_once&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>175</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>175</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>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>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>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>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_once&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &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>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>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>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>3</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>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</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>201</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>202</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>202</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>202</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>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: </array>
+// CHECK-NEXT: <key>depth</key><integer>3</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>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>202</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index 48a3462ca1e5..61a4fd490e94 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,alpha.deadcode.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
extern void foo(int a);
diff --git a/test/Analysis/viewcontroller.m b/test/Analysis/viewcontroller.m
new file mode 100644
index 000000000000..a8c45806db15
--- /dev/null
+++ b/test/Analysis/viewcontroller.m
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=alpha.osx.cocoa.MissingSuperCall -verify -Wno-objc-root-class %s
+
+@protocol NSObject
+- (id)retain;
+- (oneway void)release;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+
+typedef char BOOL;
+typedef double NSTimeInterval;
+typedef enum UIViewAnimationOptions {
+ UIViewAnimationOptionLayoutSubviews = 1 << 0
+} UIViewAnimationOptions;
+
+@interface UIViewController : NSObject {}
+- (void)addChildViewController:(UIViewController *)childController;
+- (void)viewDidAppear:(BOOL)animated;
+- (void)viewDidDisappear:(BOOL)animated;
+- (void)viewDidUnload;
+- (void)viewDidLoad;
+- (void)viewWillUnload;
+- (void)viewWillAppear:(BOOL)animated;
+- (void)viewWillDisappear:(BOOL)animated;
+- (void)didReceiveMemoryWarning;
+- (void)removeFromParentViewController;
+- (void)transitionFromViewController:(UIViewController *)fromViewController
+ toViewController:(UIViewController *)toViewController
+ duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options
+ animations:(void (^)(void))animations
+ completion:(void (^)(BOOL finished))completion;
+@end
+
+// Do not warn if UIViewController isn't our superclass
+@interface TestA
+@end
+@implementation TestA
+
+- (void)addChildViewController:(UIViewController *)childController {}
+- (void)viewDidAppear:(BOOL)animated {}
+- (void)viewDidDisappear:(BOOL)animated {}
+- (void)viewDidUnload {}
+- (void)viewDidLoad {}
+- (void)viewWillUnload {}
+- (void)viewWillAppear:(BOOL)animated {}
+- (void)viewWillDisappear:(BOOL)animated {}
+- (void)didReceiveMemoryWarning {}
+- (void)removeFromParentViewController {}
+
+@end
+
+// Warn if UIViewController is our superclass and we do not call super
+@interface TestB : UIViewController {}
+@end
+@implementation TestB
+
+- (void)addChildViewController:(UIViewController *)childController {
+ int addChildViewController = 5;
+ for (int i = 0; i < addChildViewController; i++)
+ [self viewDidAppear:i];
+} // expected-warning {{The 'addChildViewController:' instance method in UIViewController subclass 'TestB' is missing a [super addChildViewController:] call}}
+- (void)viewDidAppear:(BOOL)animated {} // expected-warning {{The 'viewDidAppear:' instance method in UIViewController subclass 'TestB' is missing a [super viewDidAppear:] call}}
+- (void)viewDidDisappear:(BOOL)animated {} // expected-warning {{The 'viewDidDisappear:' instance method in UIViewController subclass 'TestB' is missing a [super viewDidDisappear:] call}}
+- (void)viewDidUnload {} // expected-warning {{The 'viewDidUnload' instance method in UIViewController subclass 'TestB' is missing a [super viewDidUnload] call}}
+- (void)viewDidLoad {} // expected-warning {{The 'viewDidLoad' instance method in UIViewController subclass 'TestB' is missing a [super viewDidLoad] call}}
+- (void)viewWillUnload {} // expected-warning {{The 'viewWillUnload' instance method in UIViewController subclass 'TestB' is missing a [super viewWillUnload] call}}
+- (void)viewWillAppear:(BOOL)animated {} // expected-warning {{The 'viewWillAppear:' instance method in UIViewController subclass 'TestB' is missing a [super viewWillAppear:] call}}
+- (void)viewWillDisappear:(BOOL)animated {} // expected-warning {{The 'viewWillDisappear:' instance method in UIViewController subclass 'TestB' is missing a [super viewWillDisappear:] call}}
+- (void)didReceiveMemoryWarning {} // expected-warning {{The 'didReceiveMemoryWarning' instance method in UIViewController subclass 'TestB' is missing a [super didReceiveMemoryWarning] call}}
+- (void)removeFromParentViewController {} // expected-warning {{The 'removeFromParentViewController' instance method in UIViewController subclass 'TestB' is missing a [super removeFromParentViewController] call}}
+
+// Do not warn for methods were it shouldn't
+- (void)shouldAutorotate {};
+@end
+
+// Do not warn if UIViewController is our superclass but we did call super
+@interface TestC : UIViewController {}
+@end
+@implementation TestC
+
+- (BOOL)methodReturningStuff {
+ return 1;
+}
+
+- (void)methodDoingStuff {
+ [super removeFromParentViewController];
+}
+
+- (void)addChildViewController:(UIViewController *)childController {
+ [super addChildViewController:childController];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+ [super viewDidAppear:animated];
+}
+
+- (void)viewDidDisappear:(BOOL)animated {
+ [super viewDidDisappear:animated];
+}
+
+- (void)viewDidUnload {
+ [super viewDidUnload];
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+}
+
+- (void)viewWillUnload {
+ [super viewWillUnload];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+ int i = 0; // Also don't start warning just because we do additional stuff
+ i++;
+ [self viewDidDisappear:i];
+ [super viewWillAppear:animated];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+ [super viewWillDisappear:[self methodReturningStuff]];
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+}
+
+// We expect a warning here because at the moment the super-call can't be
+// done from another method.
+- (void)removeFromParentViewController {
+ [self methodDoingStuff];
+} // expected-warning {{The 'removeFromParentViewController' instance method in UIViewController subclass 'TestC' is missing a [super removeFromParentViewController] call}}
+@end
diff --git a/test/Analysis/virtualcall.cpp b/test/Analysis/virtualcall.cpp
index 127d04f58ae7..c3319b0ac54f 100644
--- a/test/Analysis/virtualcall.cpp
+++ b/test/Analysis/virtualcall.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.cplusplus.VirtualCall -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify %s
class A {
public:
@@ -51,3 +51,9 @@ int main() {
B *b;
C *c;
}
+
+#include "virtualcall.h"
+
+#define AS_SYSTEM
+#include "virtualcall.h"
+#undef AS_SYSTEM
diff --git a/test/Analysis/virtualcall.h b/test/Analysis/virtualcall.h
new file mode 100644
index 000000000000..9f7094dc63e9
--- /dev/null
+++ b/test/Analysis/virtualcall.h
@@ -0,0 +1,28 @@
+#ifdef AS_SYSTEM
+#pragma clang system_header
+
+namespace system {
+ class A {
+ public:
+ A() {
+ foo(); // no-warning
+ }
+
+ virtual int foo();
+ };
+}
+
+#else
+
+namespace header {
+ class A {
+ public:
+ A() {
+ foo(); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
+ }
+
+ virtual int foo();
+ };
+}
+
+#endif
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
index f650ad517a19..eda869b9934d 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace N1 {
struct X { };
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 f5ad68b75bdf..df9a2cd14cd4 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -108,3 +108,27 @@ namespace test6 {
test6_function(args);
}
}
+
+// PR13682: we might need to instantiate class temploids.
+namespace test7 {
+ namespace inner {
+ class A {};
+ void test7_function(A &);
+ }
+ template <class T> class B : public inner::A {};
+
+ void test(B<int> &ref) {
+ test7_function(ref);
+ }
+}
+
+// Like test7, but ensure we don't complain if the type is properly
+// incomplete.
+namespace test8 {
+ template <class T> class B;
+ void test8_function(B<int> &);
+
+ void test(B<int> &ref) {
+ test8_function(ref);
+ }
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
index cd7e669527bc..ef4243e28e89 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// C++0x [basic.lookup.classref]p3:
// If the unqualified-id is ~type-name, the type-name is looked up in the
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p4-cxx11.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p4-cxx11.cpp
index 792545453e73..a4721d61a871 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.classref/p4-cxx11.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p4-cxx11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
struct A { void f(); };
struct C { void f(); };
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
index dc0f8b4af23c..1060f6159911 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// This is basically paraphrased from the standard.
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
index 38eccfa2248b..7c292d58f500 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace A {
int a;
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.udir/p1.cpp b/test/CXX/basic/basic.lookup/basic.lookup.udir/p1.cpp
index ab0dc248f3dc..91f5a54eb9ce 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.udir/p1.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.udir/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// When looking up a namespace-name in a using-directive or
// namespace-alias-definition, only namespace names are considered.
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p12.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p12.cpp
index 878ff078bc26..6bf74c1da131 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p12.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p12.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct S {};
S E0;
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp
index 58d7ff4d16af..ba34571d7b6c 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p13.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct S {
static const int f0 = 0;
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
index 0fa4f650b0bb..4ffe538bebb0 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// C++0x [basic.lookup.unqual]p14:
// If a variable member of a namespace is defined outside of the
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
index 20a7ae05a12a..abcc6eee94a7 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef int f;
diff --git a/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp
new file mode 100644
index 000000000000..91e96b6b2622
--- /dev/null
+++ b/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -fexceptions -verify %s
+
+void func1(int i) { // expected-note{{previous definition is here}}
+ int i; // expected-error{{redefinition of 'i'}}
+}
+
+void func2(int i) try { // expected-note{{previous definition is here}}
+ int i; // expected-error{{redefinition of 'i'}}
+} catch (...) {
+}
+
+void func3(int i) try { // FIXME: note {{previous definition is here}}
+} catch (int i) { // FIXME: error {{redefinition of 'i'}}
+}
+
+void func4(int i) try { // expected-note{{previous definition is here}}
+} catch (...) {
+ int i; // expected-error{{redefinition of 'i'}}
+}
+
+void func5() try {
+ int i;
+} catch (...) {
+ int j = i; // expected-error{{use of undeclared identifier 'i'}}
+}
+
+void func6() try {
+} catch (int i) { // expected-note{{previous definition is here}}
+ int i; // expected-error{{redefinition of 'i'}}
+}
+
+void func7() {
+ try {
+ } catch (int i) { // expected-note{{previous definition is here}}
+ int i; // expected-error{{redefinition of 'i'}}
+ }
+}
diff --git a/test/CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp b/test/CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp
index e64b6752f082..c62753538040 100644
--- a/test/CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp
+++ b/test/CXX/basic/basic.scope/basic.scope.pdecl/p9.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Template type parameters.
typedef unsigned char T;
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2a.cpp b/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
index b8dfbe78b6cc..b27d492afc44 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef int Int;
typedef char Char;
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2b.cpp b/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
index 785382cd077b..65cd2027109e 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef int Int;
typedef char Char;
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2c.cpp b/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
index 81b08b98758d..2b082ec604e6 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int main() {
}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2g.cpp b/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
index e3209fd3ce94..45f643fd9a39 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int main(int argc, const char* const* argv) {
}
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
index 6cd587c4de40..9a740df5cebe 100644
--- a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-nodef.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int *use_new(int N) {
return new int [N];
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp
index 4567c469e817..9819ea0293f6 100644
--- a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace std {
class bad_alloc { };
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 7cb192b5a1f3..19d94cfdd5f6 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -20,7 +20,7 @@ void test1() {
g()->f();
S::f();
X::g(); // expected-error{{no member named 'g' in 'X'}}
- X::S x_s; // expected-error{{no member named 'S' in 'X'}}
+ X::S x_s; // expected-error{{no type named 'S' in 'X'}}
X x;
x.g(); // expected-error{{no member named 'g' in 'X'}}
}
@@ -44,16 +44,16 @@ namespace N {
S s;
S::f();
X::g(); // expected-error{{no member named 'g' in 'N::X'}}
- X::S x_s; // expected-error{{no member named 'S' in 'N::X'}}
+ X::S x_s; // expected-error{{no type named 'S' in 'N::X'}}
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 member named 'S2' 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 member named 'S2' in 'N::X'}}
+ X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'}}
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
}
}
@@ -356,3 +356,19 @@ namespace PR9103 {
}
};
}
+
+// PR13642. When computing the effective context, we were walking up
+// the DC chain for the canonical decl, which is unfortunate if that's
+// (e.g.) a friend declaration.
+namespace test14 {
+ class A {
+ class B { // expected-note {{implicitly declared private here}}
+ static int i;
+ friend void c();
+ };
+ };
+
+ void c() {
+ A::B::i = 5; // expected-error {{'B' is a private member of 'test14::A'}}
+ }
+}
diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index 00fc0a33bef2..e4d5fd55b0b6 100644
--- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -27,3 +27,29 @@ struct Y3 {
X1<Y2> x1a;
X1<Y3> x1b;
X1<Y1> x1c; // expected-note{{in instantiation of template class 'X1<Y1>' requested here}}
+
+template<typename T>
+class A {
+ T x;
+public:
+ class foo {};
+ static int y;
+};
+
+struct {
+ // Ill-formed
+ int friend; // expected-error {{'friend' must appear first in a non-function declaration}}
+ unsigned friend int; // expected-error {{'friend' must appear first in a non-function declaration}}
+ const volatile friend int; // expected-error {{'friend' must appear first in a non-function declaration}}
+ int
+ friend; // expected-error {{'friend' must appear first in a non-function declaration}}
+
+ // OK
+ int friend foo(void);
+ friend int;
+ friend const volatile int;
+ friend
+
+ float;
+ template<typename T> friend class A<T>::foo;
+} a;
diff --git a/test/CXX/class.access/class.protected/p1-cxx11.cpp b/test/CXX/class.access/class.protected/p1-cxx11.cpp
index dc9b20d17c0e..c1cf047aadb4 100644
--- a/test/CXX/class.access/class.protected/p1-cxx11.cpp
+++ b/test/CXX/class.access/class.protected/p1-cxx11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR12497
namespace test0 {
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
index c9491e1196f9..132ff6176c01 100644
--- a/test/CXX/class.access/class.protected/p1.cpp
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -423,7 +423,7 @@ namespace test12 {
// This friendship is not considered because a public member of A is
// inaccessible in C.
namespace test13 {
- class A { protected: int foo(); }; // expected-note {{can only access this member on an object of type}}
+ class A { protected: int foo(); }; // expected-note {{declared protected here}}
class B : private virtual A {};
class C : private B { friend void test(); };
class D : public virtual A {};
diff --git a/test/CXX/class.derived/class.abstract/p16.cpp b/test/CXX/class.derived/class.abstract/p16.cpp
new file mode 100644
index 000000000000..93f905cd33be
--- /dev/null
+++ b/test/CXX/class.derived/class.abstract/p16.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+struct A {
+ virtual void a(); // expected-note{{overridden virtual function is here}}
+ virtual void b() = delete; // expected-note{{overridden virtual function is here}}
+};
+
+struct B: A {
+ virtual void a() = delete; // expected-error{{deleted function 'a' cannot override a non-deleted function}}
+ virtual void b(); // expected-error{{non-deleted function 'b' cannot override a deleted function}}
+};
+
+struct C: A {
+ virtual void a();
+ virtual void b() = delete;
+};
diff --git a/test/CXX/class.derived/p2.cpp b/test/CXX/class.derived/p2.cpp
index 7ef53d36ab7b..87e0f7486154 100644
--- a/test/CXX/class.derived/p2.cpp
+++ b/test/CXX/class.derived/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// "During the lookup for a base class name, non-type names are ignored"
namespace PR5840 {
diff --git a/test/CXX/class/class.friend/p1-ambiguous.cpp b/test/CXX/class/class.friend/p1-ambiguous.cpp
index a9dca4fa8ec8..3bb32718361d 100644
--- a/test/CXX/class/class.friend/p1-ambiguous.cpp
+++ b/test/CXX/class/class.friend/p1-ambiguous.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Make sure that friend declarations don't introduce ambiguous
// declarations.
diff --git a/test/CXX/class/class.friend/p1-cxx11.cpp b/test/CXX/class/class.friend/p1-cxx11.cpp
index 235f295d1277..6e3d85001fa8 100644
--- a/test/CXX/class/class.friend/p1-cxx11.cpp
+++ b/test/CXX/class/class.friend/p1-cxx11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
class A {
class AInner {
diff --git a/test/CXX/class/class.nest/p3.cpp b/test/CXX/class/class.nest/p3.cpp
index c4c4ca7e094f..677411fe3c8a 100644
--- a/test/CXX/class/class.nest/p3.cpp
+++ b/test/CXX/class/class.nest/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// C++0x [class.nest] p3:
// If class X is defined in a namespace scope, a nested class Y may be
diff --git a/test/CXX/class/p1-0x.cpp b/test/CXX/class/p1-0x.cpp
index be5fdffb43f4..5c327880e4b7 100644
--- a/test/CXX/class/p1-0x.cpp
+++ b/test/CXX/class/p1-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
namespace Test1 {
class A final { };
diff --git a/test/CXX/class/p2-0x.cpp b/test/CXX/class/p2-0x.cpp
index dbb01e5ad528..5b39e0ada7e2 100644
--- a/test/CXX/class/p2-0x.cpp
+++ b/test/CXX/class/p2-0x.cpp
@@ -26,3 +26,11 @@ struct C : A<int> { }; // expected-error {{base 'A' is marked 'final'}}
}
+namespace Test4 {
+
+struct A final { virtual void func() = 0; }; // expected-warning {{abstract class is marked 'final'}} expected-note {{unimplemented pure virtual method 'func' in 'A'}}
+struct B { virtual void func() = 0; }; // expected-note {{unimplemented pure virtual method 'func' in 'C'}}
+
+struct C final : B { }; // expected-warning {{abstract class is marked 'final'}}
+
+}
diff --git a/test/CXX/class/p6-0x.cpp b/test/CXX/class/p6-0x.cpp
index e153b4daaf3c..cf628a6343ae 100644
--- a/test/CXX/class/p6-0x.cpp
+++ b/test/CXX/class/p6-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
class Trivial { int n; void f(); };
class NonTrivial1 { NonTrivial1(const NonTrivial1 &); };
diff --git a/test/CXX/conv/conv.prom/p2.cpp b/test/CXX/conv/conv.prom/p2.cpp
index 8d75419878ad..ca64cfa8d0ec 100644
--- a/test/CXX/conv/conv.prom/p2.cpp
+++ b/test/CXX/conv/conv.prom/p2.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -ffreestanding %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fshort-wchar -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -triple x86_64-pc-linux-gnu -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -triple x86_64-pc-linux-gnu -ffreestanding -fshort-wchar %s
+// expected-no-diagnostics
#include <stdint.h>
diff --git a/test/CXX/conv/conv.prom/p4.cpp b/test/CXX/conv/conv.prom/p4.cpp
index 02a91cd521b4..8c86d2a1838d 100644
--- a/test/CXX/conv/conv.prom/p4.cpp
+++ b/test/CXX/conv/conv.prom/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// expected-no-diagnostics
enum X : short { A, B };
extern decltype(+A) x;
@@ -7,3 +8,21 @@ extern int x;
enum Y : long { C, D };
extern decltype(+C) y;
extern long y;
+
+// An enum with a fixed underlying type has an integral promotion to that type,
+// and to its promoted type.
+enum B : bool { false_, true_ };
+template<bool> struct T {};
+T<false_> f;
+T<true_> t;
+// FIXME: DR1407 will make this ill-formed
+T<+true_> q; // desired-error {{conversion from 'int' to 'bool'}}
+
+enum B2 : bool {
+ a = false,
+ b = true,
+ c = false_,
+ d = true_,
+ // FIXME: DR1407 will make this ill-formed
+ e = +false_ // desired-error {{conversion from 'int' to 'bool'}}
+};
diff --git a/test/CXX/conv/conv.ptr/p2.cpp b/test/CXX/conv/conv.ptr/p2.cpp
index 8808d203fd91..b7617696e6fb 100644
--- a/test/CXX/conv/conv.ptr/p2.cpp
+++ b/test/CXX/conv/conv.ptr/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace pr7801 {
extern void* x[];
diff --git a/test/CXX/conv/conv.qual/pr6089.cpp b/test/CXX/conv/conv.qual/pr6089.cpp
index ae75ec41bd8f..bfadc6cac48e 100644
--- a/test/CXX/conv/conv.qual/pr6089.cpp
+++ b/test/CXX/conv/conv.qual/pr6089.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
bool is_char_ptr( const char* );
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p2.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p2.cpp
index 411c16cd8dfb..943e05322d25 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p2.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR8430
namespace N {
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
index 98d12f99a598..f92362380a1c 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
@@ -3,11 +3,11 @@
namespace NIL {} // expected-note {{previous definition}}
inline namespace NIL {} // expected-error {{cannot be reopened as inline}}
inline namespace IL {} // expected-note {{previous definition}}
-namespace IL {} // expected-warning{{inline namespace cannot be re-opened as a non-inline namespace}}
+namespace IL {} // expected-warning{{inline namespace cannot be reopened as a non-inline namespace}}
namespace {} // expected-note {{previous definition}}
inline namespace {} // expected-error {{cannot be reopened as inline}}
namespace X {
inline namespace {} // expected-note {{previous definition}}
- namespace {} // expected-error {{cannot be reopened as non-inline}}
+ namespace {} // expected-warning {{cannot be reopened as a non-inline namespace}}
}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp
index 546c4a477f7b..ae40062fe14c 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace test0 {
namespace ns0 {
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp
index dd44bfc914b2..699d80ae7c7f 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p13.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// C++03 [namespace.udecl]p3:
// For the purpose of overload resolution, the functions which are
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p6.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p6.cpp
index 4cb91cdf0021..2bcbe269e122 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p6.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udir/p6.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/8296180>
typedef int pid_t;
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
index f9702ba7ccb0..416aeb49a760 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
@@ -6,7 +6,8 @@ int p[10];
void f() {
int x = 42, y[5];
// FIXME: Produce a better diagnostic for this case.
- int(p[[x] { return x; }()]); // expected-error {{expected ']'}}
+ int(p[[x] { return x; }()]); // expected-error {{expected ']'}} \
+ // expected-warning {{unknown attribute 'x' ignored}}
y[[] { return 2; }()] = 2; // expected-error {{consecutive left square brackets}}
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
index fd17d35677dc..3c1152c631b8 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s
namespace StdExample {
@@ -80,7 +80,7 @@ constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; } // exp
// __builtin_constant_p ? : is magical, and is always a potential constant.
constexpr bool BcpCall(int n) {
- return __builtin_constant_p((int*)n != &n) ? (int*)n != &n : (int*)n != &n;
+ return __builtin_constant_p((int*)n != &n) ? (int*)n != &n : (int*)n != &n; // expected-warning 3 {{cast to 'int *' from smaller integer type 'int'}}
}
static_assert(BcpCall(0), "");
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
index f732255a8a4f..e91cacf10466 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -86,3 +86,6 @@ namespace PR13293 {
template void h<double>();
}
#endif
+
+auto fail((unknown)); // expected-error{{use of undeclared identifier 'unknown'}}
+int& crash = fail;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index 0b518bb08573..02cc973018b8 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -34,7 +34,7 @@ void f() {
void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}}
}
-int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a type specifier}}
+alignas(struct Aa {}) int x; // expected-error {{'Aa' can not be defined in a type specifier}}
int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}}
int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
index 104157115335..2342807692e6 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p4.cpp
@@ -16,3 +16,9 @@ void tf() {
// Allowed by GNU extension
int a4[] = {}; // expected-error {{zero size arrays}}
+
+struct Incomplete; // expected-note {{forward declaration of 'Incomplete'}}
+struct A {
+ Incomplete i; // expected-error {{field has incomplete type 'Incomplete'}}
+};
+A a[] = { 0 }; // PR13971: don't hang.
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp
index 885d11b9c24a..2c9cd88e40bf 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/basic.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5787
class C {
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
index 20c059eab6f3..76053f028e2b 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
int g(int);
void f() {
int i;
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
index 3631af1b7fd2..878d2c68ec33 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
char x1[]("hello");
extern char x1[6];
diff --git a/test/CXX/dcl.decl/dcl.init/p7.cpp b/test/CXX/dcl.decl/dcl.init/p7.cpp
new file mode 100644
index 000000000000..03216f4c28ac
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/p7.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+struct NotAggregateBase {};
+
+struct A : NotAggregateBase {
+private:
+ A() = default; // expected-note {{here}}
+};
+A a = {}; // expected-error {{calling a private constructor}}
+
+struct B : NotAggregateBase {
+ explicit B() = default; // expected-note {{here}}
+};
+B b = {}; // expected-error {{chosen constructor is explicit}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
index 0a107eb2b139..68aabca71eac 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
void point(int = 3, int = 4);
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
index e9c5e0ca7b69..5467a9222c07 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-void nondecl(int (*f)(int x = 5)) // {expected-error {{default arguments can only be specified}}}
+void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only be specified}}
{
- void (*f2)(int = 17) // {expected-error {{default arguments can only be specified}}}
- = (void (*)(int = 42))f; // {expected-error {{default arguments can only be specified}}}
+ void (*f2)(int = 17) // expected-error {{default arguments can only be specified}}
+ = (void (*)(int = 42))f; // expected-error {{default arguments can only be specified}}
}
struct X0 {
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
index 0e69521fbdfc..bc249b5a087b 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> struct identity;
template<typename ...Types> struct tuple;
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
index 4ce80bc35ac9..cd623df71e81 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p6-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T, typename U>
struct is_same {
diff --git a/test/CXX/dcl.decl/dcl.meaning/p1.cpp b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
index 3672ea0ea086..ec9a2611872c 100644
--- a/test/CXX/dcl.decl/dcl.meaning/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
@@ -7,7 +7,7 @@ namespace PR8019 {
struct PR8019::x { int x; }; // expected-error{{non-friend class member 'x' cannot have a qualified name}}
struct inner;
- struct y::inner { }; // expected-warning{{extra qualification on member 'inner'}}
+ struct y::inner { }; // expected-error{{extra qualification on member 'inner'}}
template<typename T>
struct PR8019::x2 { }; // expected-error{{non-friend class member 'x2' cannot have a qualified name}}
@@ -16,7 +16,7 @@ namespace PR8019 {
struct inner_template;
template<typename T>
- struct y::inner_template { }; // expected-warning{{extra qualification on member 'inner_template'}}
+ struct y::inner_template { }; // expected-error{{extra qualification on member 'inner_template'}}
};
}
@@ -29,9 +29,9 @@ namespace NS {
template<typename T> void wibble(T);
}
namespace NS {
- void NS::foo() {} // expected-warning{{extra qualification on member 'foo'}}
- int NS::bar; // expected-warning{{extra qualification on member 'bar'}}
- struct NS::X { }; // expected-warning{{extra qualification on member 'X'}}
- template<typename T> struct NS::Y; // expected-warning{{extra qualification on member 'Y'}}
- template<typename T> void NS::wibble(T) { } // expected-warning{{extra qualification on member 'wibble'}}
+ void NS::foo() {} // expected-error{{extra qualification on member 'foo'}}
+ int NS::bar; // expected-error{{extra qualification on member 'bar'}}
+ struct NS::X { }; // expected-error{{extra qualification on member 'X'}}
+ template<typename T> struct NS::Y; // expected-error{{extra qualification on member 'Y'}}
+ template<typename T> void NS::wibble(T) { } // expected-error{{extra qualification on member 'wibble'}}
}
diff --git a/test/CXX/dcl.decl/dcl.name/p1.cpp b/test/CXX/dcl.decl/dcl.name/p1.cpp
index 9838b4f4737d..e032a7f92a5c 100644
--- a/test/CXX/dcl.decl/dcl.name/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.name/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace pr6200 {
struct v {};
diff --git a/test/CXX/dcl.decl/p4-0x.cpp b/test/CXX/dcl.decl/p4-0x.cpp
index 98c33b25f4d2..35177a038697 100644
--- a/test/CXX/dcl.decl/p4-0x.cpp
+++ b/test/CXX/dcl.decl/p4-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct X {
void f() &;
diff --git a/test/CXX/except/except.spec/canonical.cpp b/test/CXX/except/except.spec/canonical.cpp
index 81ca2ae0a20e..b6d3e9c7aba1 100644
--- a/test/CXX/except/except.spec/canonical.cpp
+++ b/test/CXX/except/except.spec/canonical.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
// PR10087: Make sure that we don't conflate exception specifications
// from different functions in the canonical type system.
diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp
index 0e4fad53e350..1f6bf2131cd6 100644
--- a/test/CXX/except/except.spec/p11.cpp
+++ b/test/CXX/except/except.spec/p11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+// expected-no-diagnostics
// This is the "let the user shoot himself in the foot" clause.
void f() noexcept {
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index 4f50afb54887..ff21ab8e56b9 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -63,3 +63,41 @@ namespace PR13381 {
static_assert(!noexcept(X(X::val())), "");
static_assert(!noexcept(X::ref() = X::val()), "");
}
+
+namespace PR14141 {
+ // Part of DR1351: the implicit exception-specification is noexcept(false) if
+ // the set of potential exceptions of the special member function contains
+ // "any". Hence it is compatible with noexcept(false).
+ struct ThrowingBase {
+ ThrowingBase() noexcept(false);
+ ThrowingBase(const ThrowingBase&) noexcept(false);
+ ThrowingBase(ThrowingBase&&) noexcept(false);
+ ThrowingBase &operator=(const ThrowingBase&) noexcept(false);
+ ThrowingBase &operator=(ThrowingBase&&) noexcept(false);
+ ~ThrowingBase() noexcept(false);
+ };
+ struct Derived : ThrowingBase {
+ Derived() noexcept(false) = default;
+ Derived(const Derived&) noexcept(false) = default;
+ Derived(Derived&&) noexcept(false) = default;
+ Derived &operator=(const Derived&) noexcept(false) = default;
+ Derived &operator=(Derived&&) noexcept(false) = default;
+ ~Derived() noexcept(false) = default;
+ };
+ struct Derived2 : ThrowingBase {
+ Derived2() = default;
+ Derived2(const Derived2&) = default;
+ Derived2(Derived2&&) = default;
+ Derived2 &operator=(const Derived2&) = default;
+ Derived2 &operator=(Derived2&&) = default;
+ ~Derived2() = default;
+ };
+ struct Derived3 : ThrowingBase {
+ Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3 &operator=(const Derived3&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ Derived3 &operator=(Derived3&&) noexcept(true) = default; // expected-error {{does not match the calculated}}
+ ~Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
+ };
+}
diff --git a/test/CXX/except/except.spec/p15.cpp b/test/CXX/except/except.spec/p15.cpp
index 110ec3fa0300..fcf12357f916 100644
--- a/test/CXX/except/except.spec/p15.cpp
+++ b/test/CXX/except/except.spec/p15.cpp
@@ -9,16 +9,20 @@ void f() {
delete[] new int[1];
}
-void operator delete(void*) noexcept;
-void operator delete[](void*) noexcept;
+void operator delete(void*);
+void operator delete[](void*);
+
+static_assert(noexcept(operator delete(0)), "");
+static_assert(noexcept(operator delete[](0)), "");
// Same goes for explicit declarations.
void operator delete(void*, float);
-void operator delete(void*, float) noexcept;
-
void operator delete[](void*, float);
-void operator delete[](void*, float) noexcept;
+
+static_assert(noexcept(operator delete(0, 0.f)), "");
+static_assert(noexcept(operator delete[](0, 0.f)), "");
// But explicit specs stay.
void operator delete(void*, double) throw(int); // expected-note {{previous}}
+static_assert(!noexcept(operator delete(0, 0.)), "");
void operator delete(void*, double) noexcept; // expected-error {{does not match}}
diff --git a/test/CXX/except/except.spec/p4.cpp b/test/CXX/except/except.spec/p4.cpp
new file mode 100644
index 000000000000..1bf70188031f
--- /dev/null
+++ b/test/CXX/except/except.spec/p4.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify -fcxx-exceptions
+
+// We permit overriding an implicit exception specification with an explicit one
+// as an extension, for compatibility with existing code.
+
+struct S {
+ void a(); // expected-note {{here}}
+ ~S(); // expected-note {{here}}
+ void operator delete(void*); // expected-note {{here}}
+};
+
+void S::a() noexcept {} // expected-error {{does not match previous}}
+S::~S() noexcept {} // expected-warning {{function previously declared with an implicit exception specification redeclared with an explicit exception specification}}
+void S::operator delete(void*) noexcept {} // expected-warning {{function previously declared with an implicit exception specification redeclared with an explicit exception specification}}
+
+struct T {
+ void a() noexcept; // expected-note {{here}}
+ ~T() noexcept; // expected-note {{here}}
+ void operator delete(void*) noexcept; // expected-note {{here}}
+};
+
+void T::a() {} // expected-warning {{missing exception specification 'noexcept'}}
+T::~T() {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}}
+void T::operator delete(void*) {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}}
+
+
+// The extension does not extend to function templates.
+
+template<typename T> struct U {
+ T t;
+ ~U(); // expected-note {{here}}
+ void operator delete(void*); // expected-note {{here}}
+};
+
+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}}
diff --git a/test/CXX/expr/expr.cast/p4-0x.cpp b/test/CXX/expr/expr.cast/p4-0x.cpp
index 96bf5f91196b..76ac31801730 100644
--- a/test/CXX/expr/expr.cast/p4-0x.cpp
+++ b/test/CXX/expr/expr.cast/p4-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct X { };
struct Y : X { };
diff --git a/test/CXX/expr/expr.const/p3-0x-nowarn.cpp b/test/CXX/expr/expr.const/p3-0x-nowarn.cpp
index c891374519fb..7d12cedeacf0 100644
--- a/test/CXX/expr/expr.const/p3-0x-nowarn.cpp
+++ b/test/CXX/expr/expr.const/p3-0x-nowarn.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-c++11-narrowing -verify %s
+// expected-no-diagnostics
// <rdar://problem/11121178>
void f(int x) {
diff --git a/test/CXX/expr/expr.const/p5-0x.cpp b/test/CXX/expr/expr.const/p5-0x.cpp
index 60fabe37e2bb..bdb2b23ec792 100644
--- a/test/CXX/expr/expr.const/p5-0x.cpp
+++ b/test/CXX/expr/expr.const/p5-0x.cpp
@@ -61,10 +61,10 @@ enum NotFixed {
// [dcl.align]p2: When the alignment-specifier is of the form
// alignas(assignment-expression), the assignment-expression shall be an
// integral constant expression
-int alignas(ok) alignas1;
-int alignas(incomplete) alignas2; // expected-error {{incomplete}}
-int alignas(expl) alignas3; // expected-error {{explicit conversion}}
-int alignas(ambig) alignas4; // expected-error {{ambiguous conversion}}
+alignas(ok) int alignas1;
+alignas(incomplete) int alignas2; // expected-error {{incomplete}}
+alignas(expl) int alignas3; // expected-error {{explicit conversion}}
+alignas(ambig) int alignas4; // expected-error {{ambiguous conversion}}
// [dcl.array]p1: If the constant-expression is present, it shall be an integral
// constant expression
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 6ba8d519346e..be898761fafa 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
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// The result of the expression const_cast<T>(v) is of type T. If T is
// an lvalue reference to object type, the result is an lvalue; if T
diff --git a/test/CXX/expr/expr.post/expr.ref/p3.cpp b/test/CXX/expr/expr.post/expr.ref/p3.cpp
index 98771d34b63d..db33c014eeb7 100644
--- a/test/CXX/expr/expr.post/expr.ref/p3.cpp
+++ b/test/CXX/expr/expr.post/expr.ref/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -fsyntax-only %s
+// expected-no-diagnostics
template<typename T> struct Node {
int lhs;
diff --git a/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp b/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
index 9ef15e6642b1..830ccda245ba 100644
--- a/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3).
diff --git a/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp b/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
index 731c50844428..c624c7e3f2f9 100644
--- a/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.static.cast/p9-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
enum class EC { ec1 };
diff --git a/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp b/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp
index 253744e23f57..568c61b95fb9 100644
--- a/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
struct foo {
foo();
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 030c90c525c0..b84cec61c313 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
@@ -91,11 +91,11 @@ namespace Static {
namespace PR12564 {
struct Base {
- void bar(Base&) {} // unexpected-note {{here}}
+ void bar(Base&) {} // FIXME: expected-note {{here}}
};
struct Derived : Base {
// FIXME: This should be accepted.
- void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // unexpected-error {{cannot bind to a value of unrelated type}}
+ void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}}
};
}
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 678fa4b964d4..6358215a5559 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
@@ -73,3 +73,18 @@ struct ExpectedThisLayout {
static_assert(sizeof(x) == sizeof(ExpectedThisLayout), "Layout mismatch!");
}
};
+
+struct CaptureArrayAndThis {
+ int value;
+
+ void f() {
+ int array[3];
+ [=]() -> int {
+ int result = value;
+ for (unsigned i = 0; i < 3; ++i)
+ result += array[i];
+ return result;
+ }();
+ }
+};
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
index c4deba9c9743..b4b1605ab002 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// expected-no-diagnostics
class NonCopyable {
NonCopyable(const NonCopyable&);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
index 930a4b32fa06..93c2805497f3 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// expected-no-diagnostics
template<typename T, typename U>
struct is_same {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp
index 4487cfc4ba28..17eb841fc3fc 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+// expected-no-diagnostics
template<typename T>
void destroy(T* ptr) {
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp
index 7139058cd089..bc2c9997379a 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// expected-no-diagnostics
struct DirectInitOnly {
explicit DirectInitOnly(DirectInitOnly&);
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 b5de1a7f8fee..1f5969d49327 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,5 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -fms-extensions %s
+// expected-no-diagnostics
#define P(e) static_assert(noexcept(e), "expected nothrow")
#define N(e) static_assert(!noexcept(e), "expected throw")
diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
index 2dd6b23fa024..08ab0ca56fb6 100644
--- a/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify
+// expected-no-diagnostics
namespace rdar10544564 {
// Check that we don't attempt to use an overloaded operator& when
diff --git a/test/CXX/expr/p8.cpp b/test/CXX/expr/p8.cpp
index 2f6c094301ee..471d1c5a3020 100644
--- a/test/CXX/expr/p8.cpp
+++ b/test/CXX/expr/p8.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int a0;
const volatile int a1 = 2;
diff --git a/test/CXX/expr/p9.cpp b/test/CXX/expr/p9.cpp
index 803b0cc459b2..4c60b8ba62e4 100644
--- a/test/CXX/expr/p9.cpp
+++ b/test/CXX/expr/p9.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// floating-point overloads
diff --git a/test/CXX/lex/lex.literal/lex.ccon/p1.cpp b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
index 5342153b63ba..f84f5fba3e0a 100644
--- a/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
+++ b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Check types of char literals
extern char a;
diff --git a/test/CXX/lex/lex.trigraph/p3.cpp b/test/CXX/lex/lex.trigraph/p3.cpp
index 2be03285fe65..c74d8f358d02 100644
--- a/test/CXX/lex/lex.trigraph/p3.cpp
+++ b/test/CXX/lex/lex.trigraph/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -trigraphs -Wtrigraphs -verify %s
+// expected-no-diagnostics
char a[] =
"?? ??\"??#??$??%??&??*??+??,??.??0??1??2??3??4??5??6"
diff --git a/test/CXX/over/over.built/p1.cpp b/test/CXX/over/over.built/p1.cpp
deleted file mode 100644
index 6000f5b01ca4..000000000000
--- a/test/CXX/over/over.built/p1.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-enum E1 { one };
-enum E2 { two };
-
-bool operator >= (E1, E1) {
- return false;
-}
-
-bool operator >= (E1, const E2) {
- return false;
-}
-
-bool test(E1 a, E1 b, E2 c) {
- return a >= b || a >= c;
-}
diff --git a/test/CXX/over/over.built/p23.cpp b/test/CXX/over/over.built/p23.cpp
index 41255214ec6a..a1c0d4f3f612 100644
--- a/test/CXX/over/over.built/p23.cpp
+++ b/test/CXX/over/over.built/p23.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// expected-no-diagnostics
struct Variant {
template <typename T> operator T();
diff --git a/test/CXX/over/over.built/p25.cpp b/test/CXX/over/over.built/p25.cpp
index aea3854a420e..09e550ddc0ec 100644
--- a/test/CXX/over/over.built/p25.cpp
+++ b/test/CXX/over/over.built/p25.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
enum class Color { Red, Green, Blue };
diff --git a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
index 3971acc58169..f813305b4a19 100644
--- a/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
+++ b/test/CXX/over/over.match/over.match.best/over.ics.rank/p3-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace std_example {
int i;
int f1();
diff --git a/test/CXX/over/over.match/over.match.best/p1.cpp b/test/CXX/over/over.match/over.match.best/p1.cpp
index 5c315a736052..59e3dac74283 100644
--- a/test/CXX/over/over.match/over.match.best/p1.cpp
+++ b/test/CXX/over/over.match/over.match.best/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> int &f0(T*, int);
float &f0(void*, int);
diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
new file mode 100644
index 000000000000..35f8808fff88
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
+
+// This is specifically testing the bullet:
+// "do not have the same parameter-type-list as any non-template
+// non-member candidate."
+// The rest is sort of hard to test separately.
+
+enum E1 { one };
+enum E2 { two };
+
+struct A;
+
+A operator >= (E1, E1);
+A operator >= (E1, const E2);
+
+E1 a;
+E2 b;
+
+extern A test1;
+extern decltype(a >= a) test1;
+extern decltype(a >= b) test1;
+
+template <typename T> A operator <= (E1, T);
+extern bool test2;
+extern decltype(a <= a) test2;
+
+extern A test3;
+extern decltype(a <= b) test3; \ No newline at end of file
diff --git a/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp b/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
index 3845af09d14c..68c79900b951 100644
--- a/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
+++ b/test/CXX/over/over.match/over.match.funcs/p4-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> T &lvalue();
template<typename T> T &&xvalue();
diff --git a/test/CXX/over/over.oper/over.literal/p7.cpp b/test/CXX/over/over.oper/over.literal/p7.cpp
index 72411b954e14..74e9457bb55c 100644
--- a/test/CXX/over/over.oper/over.literal/p7.cpp
+++ b/test/CXX/over/over.oper/over.literal/p7.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
constexpr int operator "" _a(const char *c) {
return c[0];
diff --git a/test/CXX/over/over.oper/over.literal/p8.cpp b/test/CXX/over/over.oper/over.literal/p8.cpp
index 3f76082d10a9..6f636104e45d 100644
--- a/test/CXX/over/over.oper/over.literal/p8.cpp
+++ b/test/CXX/over/over.oper/over.literal/p8.cpp
@@ -9,11 +9,10 @@ void operator "" _km(long double); // ok
string operator "" _i18n(const char*, std::size_t); // ok
// FIXME: This should be accepted once we support UCNs
template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-error {{expected identifier}}
-float operator ""E(const char *); // expected-error {{C++11 requires a space between literal and identifier}} expected-warning {{reserved}}
+float operator ""E(const char *); // expected-error {{invalid suffix on literal}} expected-warning {{reserved}}
float operator " " B(const char *); // expected-error {{must be '""'}} expected-warning {{reserved}}
string operator "" 5X(const char *, std::size_t); // expected-error {{expected identifier}}
double operator "" _miles(double); // expected-error {{parameter}}
template<char...> int operator "" j(const char*); // expected-error {{parameter}}
-// FIXME: Accept this as an extension, with a fix-it to add the space
-float operator ""_E(const char *); // expected-error {{C++11 requires a space between the "" and the user-defined suffix in a literal operator}}
+float operator ""_E(const char *);
diff --git a/test/CXX/special/class.conv/class.conv.ctor/p1.cpp b/test/CXX/special/class.conv/class.conv.ctor/p1.cpp
index d2add82f420f..5a45f7c358a3 100644
--- a/test/CXX/special/class.conv/class.conv.ctor/p1.cpp
+++ b/test/CXX/special/class.conv/class.conv.ctor/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
namespace PR13003 {
struct void_type
diff --git a/test/CXX/special/class.copy/p15-0x.cpp b/test/CXX/special/class.copy/p15-0x.cpp
index fff88442555c..9d03a55423db 100644
--- a/test/CXX/special/class.copy/p15-0x.cpp
+++ b/test/CXX/special/class.copy/p15-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// expected-no-diagnostics
namespace PR10622 {
struct foo {
diff --git a/test/CXX/special/class.copy/p8-cxx11.cpp b/test/CXX/special/class.copy/p8-cxx11.cpp
index a2613f461298..4a9f3f2113df 100644
--- a/test/CXX/special/class.copy/p8-cxx11.cpp
+++ b/test/CXX/special/class.copy/p8-cxx11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
// C++98 [class.copy]p5 / C++11 [class.copy]p8.
diff --git a/test/CXX/special/class.ctor/p1.cpp b/test/CXX/special/class.ctor/p1.cpp
index 9500a7d2346d..4d821841e47f 100644
--- a/test/CXX/special/class.ctor/p1.cpp
+++ b/test/CXX/special/class.ctor/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct X0 {
struct type { };
diff --git a/test/CXX/special/class.dtor/p2.cpp b/test/CXX/special/class.dtor/p2.cpp
index b05c992f4115..4a10eb9e0d0b 100644
--- a/test/CXX/special/class.dtor/p2.cpp
+++ b/test/CXX/special/class.dtor/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5548
struct A {~A();};
diff --git a/test/CXX/special/class.dtor/p3-0x.cpp b/test/CXX/special/class.dtor/p3-0x.cpp
index 44bf5aa01978..291353a8237e 100644
--- a/test/CXX/special/class.dtor/p3-0x.cpp
+++ b/test/CXX/special/class.dtor/p3-0x.cpp
@@ -45,7 +45,7 @@ G::~G() {}
struct H {
B b;
- ~H();
+ ~H() throw(int);
};
H::~H() throw(int) {}
diff --git a/test/CXX/special/class.dtor/p3.cpp b/test/CXX/special/class.dtor/p3.cpp
new file mode 100644
index 000000000000..6f4d5c7f3184
--- /dev/null
+++ b/test/CXX/special/class.dtor/p3.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -verify %s
+
+// The exception specification of a destructor declaration is matched *before*
+// the exception specification adjustment occurs.
+namespace DR1492 {
+ struct A { ~A(); }; // expected-note {{here}}
+ A::~A() noexcept {} // expected-warning {{previously declared with an implicit exception specification}}
+
+ struct B { ~B() noexcept; }; // expected-note {{here}}
+ B::~B() {} // expected-warning {{previously declared with an explicit exception specification}}
+
+ template<typename T> struct C {
+ T t;
+ ~C(); // expected-note {{here}}
+ };
+ template<typename T> C<T>::~C() noexcept {} // expected-error {{does not match previous}}
+}
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 96bb47212274..3952afdeff11 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -3,20 +3,24 @@
struct pr12960 {
int begin;
void foo(int x) {
- for (int& it : x) { // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type 'int'}}
+ for (int& it : x) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
}
}
};
-namespace std {
+struct null_t {
+ operator int*();
+};
+
+namespace X {
template<typename T>
- auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 4{{ignored: substitution failure}}
+ auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 2{{ignored: substitution failure}}
template<typename T>
auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
template<typename T>
auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \
- expected-note 4{{candidate template ignored: substitution failure [with T = }}
+ expected-note 2{{candidate template ignored: substitution failure [with T = }}
template<typename T>
auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
@@ -27,19 +31,28 @@ namespace std {
}
using namespace inner;
-}
-struct A { // expected-note 2 {{candidate constructor}}
- A();
- int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
- int *end();
-};
+ struct A { // expected-note 2 {{candidate constructor}}
+ A();
+ int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
+ int *end();
+ };
-struct B {
- B();
- int *alt_begin();
- int *alt_end();
-};
+ struct B {
+ B();
+ int *alt_begin();
+ int *alt_end();
+ };
+
+ struct NoBeginADL {
+ null_t alt_end();
+ };
+ struct NoEndADL {
+ null_t alt_begin();
+ };
+}
+
+using X::A;
void f();
void f(int);
@@ -49,19 +62,19 @@ void g() {
A __begin;
for (char *a : A()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
}
- for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+ for (char *a : X::B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
}
// FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
for (double a : f) { // expected-error {{cannot use type '<overloaded function type>' as a range}}
}
for (auto a : A()) {
}
- for (auto a : B()) {
+ for (auto a : X::B()) {
}
for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}}
}
// : is not a typo for :: here.
- for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}}
+ for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'X::A'}}
}
for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}}
}
@@ -92,9 +105,6 @@ void g() {
for (auto a : VoidBegin()) // expected-error {{cannot use type 'void' as an iterator}}
;
- struct null_t {
- operator int*();
- };
struct Differ {
int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
@@ -110,15 +120,9 @@ void g() {
for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
for (constexpr int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'constexpr'}}
- struct NoBeginADL {
- null_t alt_end();
- };
- struct NoEndADL {
- null_t alt_begin();
- };
- for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
+ for (auto u : X::NoBeginADL()) { // expected-error {{invalid range expression of type 'X::NoBeginADL'; no viable 'begin' function available}}
}
- for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
+ for (auto u : X::NoEndADL()) { // expected-error {{invalid range expression of type 'X::NoEndADL'; no viable 'end' function available}}
}
struct NoBegin {
@@ -129,14 +133,15 @@ void g() {
};
for (auto u : NoBegin()) { // expected-error {{range type 'NoBegin' has 'end' member but no 'begin' member}}
}
- for (auto u : NoEnd()) { // expected-error {{range type 'NoEnd' has 'begin' member but no 'end' member}}
+ for (auto u : NoEnd()) { // expected-error {{range type 'NoEnd' has 'begin' member but no 'end' member}}
}
struct NoIncr {
void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
void *end();
};
- for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}
+ for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
+ expected-note {{in implicit call to 'operator++' for iterator of type 'NoIncr'}}
}
struct NoNotEq {
@@ -144,7 +149,19 @@ void g() {
NoNotEq end();
void operator++();
};
- for (auto u : NoNotEq()) { // expected-error {{invalid operands to binary expression}}
+ for (auto u : NoNotEq()) { // expected-error {{invalid operands to binary expression}}\
+ expected-note {{in implicit call to 'operator!=' for iterator of type 'NoNotEq'}}
+ }
+
+ struct NoDeref {
+ NoDeref begin(); // expected-note {{selected 'begin' function}}
+ NoDeref end();
+ void operator++();
+ bool operator!=(NoDeref &);
+ };
+
+ for (auto u : NoDeref()) { // expected-error {{indirection requires pointer operand}} \
+ expected-note {{in implicit call to 'operator*' for iterator of type 'NoDeref'}}
}
struct NoCopy {
@@ -156,8 +173,7 @@ void g() {
for (int n : NoCopy()) { // ok
}
- for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
- expected-note {{range has type 'int'}}
+ for (int n : 42) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
}
for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
@@ -166,7 +182,7 @@ void g() {
template<typename T, typename U>
void h(T t) {
- for (U u : t) { // expected-error {{no viable conversion from 'A' to 'int'}}
+ for (U u : t) { // expected-error {{no viable conversion from 'X::A' to 'int'}}
}
for (auto u : t) {
}
@@ -179,14 +195,24 @@ template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
template<typename T>
void i(T t) {
- for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
+ for (auto u : t) { // expected-error {{invalid range expression of type 'X::A *'; no viable 'begin' function available}} \
expected-error {{member function 'begin' not viable}} \
- expected-note {{range has type}}
+ expected-note {{when looking up 'begin' function}}
+
}
}
template void i<A[13]>(A*); // expected-note {{requested here}}
template void i<const A>(const A); // expected-note {{requested here}}
+struct StdBeginEnd {};
+namespace std {
+ int *begin(StdBeginEnd);
+ int *end(StdBeginEnd);
+}
+void DR1442() {
+ for (auto a : StdBeginEnd()) {} // expected-error {{invalid range expression of type 'StdBeginEnd'; no viable 'begin'}}
+}
+
namespace NS {
class ADL {};
int *begin(ADL); // expected-note {{no known conversion from 'NS::NoADL' to 'NS::ADL'}}
@@ -204,9 +230,10 @@ void end(VoidBeginADL);
void j() {
for (auto u : NS::ADL()) {
}
- for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (auto u : NS::NoADL()) { // expected-error {{invalid range expression of type 'NS::NoADL'; no viable 'begin' function available}}
}
for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
+
}
}
@@ -215,4 +242,3 @@ void example() {
for (int &x : array)
x *= 2;
}
-
diff --git a/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
index 000c870d5901..d0f15d4d3df2 100644
--- a/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
+++ b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
struct Value {
constexpr Value(int n) : n(n) {}
diff --git a/test/CXX/temp/p3.cpp b/test/CXX/temp/p3.cpp
index c146bc4faade..11f72de918cb 100644
--- a/test/CXX/temp/p3.cpp
+++ b/test/CXX/temp/p3.cpp
@@ -8,7 +8,7 @@ template<typename T> int S<T>::a, S<T>::b; // expected-error {{can only declare
template<typename T> struct A { static A a; } A<T>::a; // expected-error {{expected ';' after struct}} \
expected-error {{use of undeclared identifier 'T'}} \
- expected-warning{{extra qualification}}
+ expected-error{{extra qualification}}
template<typename T> struct B { } f(); // expected-error {{expected ';' after struct}} \
expected-error {{requires a type specifier}}
diff --git a/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp b/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
index b03ed46e92f0..67f317b01807 100644
--- a/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.type/p2-cxx0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// expected-no-diagnostics
// C++03 imposed restrictions in this paragraph that were lifted with 0x, so we
// just test that the example given now parses cleanly.
diff --git a/test/CXX/temp/temp.decls/temp.alias/p1.cpp b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
index 966e3c10e5de..aafe4808bb18 100644
--- a/test/CXX/temp/temp.decls/temp.alias/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> using U = T;
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp
index 2a3e9142169c..df0e68d29b6f 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p9.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR8905
template<char C1, char C2>
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
index 97457ea213bb..64cc5923f008 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<int I, int J, class T> struct X {
static const int value = 0;
};
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
index 87e21e4af845..184160ac78d1 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T, int N>
struct A;
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
index 4c05c622926d..213f0c60d5b3 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> struct X1 { };
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
index 70c9c70a41c0..fcbb724a7af0 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern "C" void * malloc(int);
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 63909fb7cdbd..6d22f8809365 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
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
// Core DR 532.
namespace PR8130 {
@@ -15,3 +16,30 @@ namespace PR8130 {
int &ir = b * a;
}
}
+
+namespace OperatorWithRefQualifier {
+ struct A { };
+ template<class T> struct B {
+ template<class R> int &operator*(R&) &&;
+ };
+
+ template<class T, class R> float &operator*(T&&, R&);
+ void test() {
+ A a;
+ B<A> b;
+ float &ir = b * a;
+ int &ir2 = B<A>() * a;
+ }
+}
+
+namespace OrderWithStaticMember {
+ struct A {
+ template<class T> int g(T**, int=0) { return 0; }
+ template<class T> static int g(T*) { return 1; }
+ };
+ void f() {
+ A a;
+ int **p;
+ a.g(p);
+ }
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
index 2ffdd9579ecd..8212a125be60 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace DeduceVsMember {
template<typename T>
@@ -14,3 +15,15 @@ namespace DeduceVsMember {
float& ir = (xi == xf);
}
}
+
+namespace OrderWithStaticMember {
+ struct A {
+ template<class T> int g(T**, int=0) { return 0; }
+ template<class T> static int g(T*) { return 1; }
+ };
+ void f() {
+ A a;
+ int **p;
+ a.g(p);
+ }
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
index 4d34968d32aa..5f2dbb6018ce 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<class T> int &f(T);
template<class T> float &f(T*, int=1);
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp
index f42b94a727d2..d24a3fb71d5d 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// All of these function templates are distinct.
template<typename T> void f0(T) { }
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
index 63fd3df26900..4b899e4e5211 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace test0 {
template <class T> class A {
diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
index f5f12055c19e..01eab24757f0 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template <class T> struct A {
static T cond;
diff --git a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
index fec8060955e3..2e24fc00dc1a 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/deduction.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace DeductionForInstantiation {
template<unsigned I, typename ...Types>
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
index db28eea98a54..83e03bcc0ddb 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Example bind implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
index e15203abc615..4cbacf830266 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-function.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Example function implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp b/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
index 9de5fa84b48a..f5800471ac2d 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Example tuple implementation from the variadic templates proposal,
// ISO C++ committee document number N2080.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp b/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
index b5786acf82a2..c09c0b243a92 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/injected-class-name.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Check for declaration matching with out-of-line declarations and
// variadic templates, which involves proper computation of the
diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 485068e6486a..e0ffef5007a1 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -187,6 +187,30 @@ namespace PacksAtDifferentLevels {
add_pointer<float>,
add_const<double>>>::value == 0? 1 : -1];
+ namespace PR13811 {
+ constexpr int g(int n, int m) { return n * 10 + m; }
+
+ template<typename...A>
+ struct X6 {
+ template<typename...B>
+ constexpr auto f1(A ...a) -> decltype(g(A(a + B())...)) { return g(A(a + B())...); }
+
+ template<typename...B>
+ constexpr auto f2(A ...a, B ...b) -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}}
+
+ template<typename...B> struct Inner {
+ template<typename...C>
+ constexpr auto f(A ...a, B ...b, C ...c) -> decltype(g(a+b+c...)) { return g(a+b+c...); }
+ };
+ };
+ struct A { constexpr operator int() { return 2; } };
+ struct B { constexpr operator int() { return 1; } };
+
+ static_assert(X6<unsigned char, int>().f1<A, B>(255, 1) == 12, "");
+ static_assert(X6<int, int>().f2(3, 4, 0, 0) == 34, "");
+ static_assert(X6<int, int>().f2(3, 4, 0, 1) == 34, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ static_assert(X6<int, int>::Inner<int, int>().f(1, 2, 3, 4, 5, 6) == 102, "");
+ }
}
namespace ExpandingNonTypeTemplateParameters {
diff --git a/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp b/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
index 71bd6aa8eb52..36535e3f90ed 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/partial-ordering.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Various tests related to partial ordering of variadic templates.
template<typename ...Types> struct tuple;
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
index 4d29b740d803..36b07002cf3d 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace ParameterPacksWithFunctions {
template<typename ...> struct count;
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
index 81addfe4bdcd..a9bda621e98f 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Metafunction to extract the Nth type from a set of types.
template<unsigned N, typename ...Types> struct get_nth_type;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
index c14b063ab746..47184ec03455 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
#if !__has_feature(cxx_access_control_sfinae)
# error No support for access control as part of SFINAE?
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp
index 6481485b2a08..1907bd77998f 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/sfinae-1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
typedef char one_byte;
struct two_bytes { char data[2]; };
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp
index c165c4530668..4be81d882588 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> struct A { };
// bullet 1
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
index 83b5f2314011..132d61814227 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace PR8598 {
template<class T> struct identity { typedef T type; };
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
index 5a9ea084fd61..badd5a8c6a2c 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// FIXME: [temp.deduct.conv]p2 bullets 1 and 2 can't actually happen without
// references?
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
index e23e98abe64d..a5916ba65377 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct AnyPtr {
template<typename T>
operator T*() const;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
index b96530056b2c..ec7e8970b1b5 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p12.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Note: Partial ordering of function templates containing template
// parameter packs is independent of the number of deduced arguments
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
index f204caf57abd..cc129c0a9b2e 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p9-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> int &f0(T&);
template<typename T> float &f0(T&&);
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
index 8183061a8ab4..b38ade39edf2 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p10-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> void f(T&&);
template<> void f(int&) { }
void (*fp)(int&) = &f;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
index 5b031c24ed71..e3a9f5798dbf 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// If type deduction cannot be done for any P/A pair, or if for any
// pair the deduction leads to more than one possible set of deduced
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
index 4e98a6d15e1a..20e6ea2d7127 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p21.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Note: Template argument deduction involving parameter packs
// (14.5.3) can deduce zero or more arguments for each parameter pack.
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
index fcc6cf7ec732..09b1648e68e7 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p22.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// If the original function parameter associated with A is a function
// parameter pack and the function parameter associated with P is not
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
index c819d973a941..d239a5e17200 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p5-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// FIXME: More bullets to go!
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
index a6b1172afccc..6ef8e2fd5ecd 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p8-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Deductions specific to C++0x.
diff --git a/test/CXX/temp/temp.names/p2.cpp b/test/CXX/temp/temp.names/p2.cpp
index 93e45dd7e3b0..532dd84ecb43 100644
--- a/test/CXX/temp/temp.names/p2.cpp
+++ b/test/CXX/temp/temp.names/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Ensure that when enforcing access control an unqualified template name with
// explicit template arguments, we don't lose the context of the name lookup
diff --git a/test/CXX/temp/temp.names/p4.cpp b/test/CXX/temp/temp.names/p4.cpp
index 103a1bd537f8..64ca80517b8c 100644
--- a/test/CXX/temp/temp.names/p4.cpp
+++ b/test/CXX/temp/temp.names/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct meta {
template<typename U>
diff --git a/test/CXX/temp/temp.param/p10-0x.cpp b/test/CXX/temp/temp.param/p10-0x.cpp
index 37bb284a36eb..21a96bf613e6 100644
--- a/test/CXX/temp/temp.param/p10-0x.cpp
+++ b/test/CXX/temp/temp.param/p10-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
template<typename> struct Y1;
template<typename, int> struct Y2;
diff --git a/test/CXX/temp/temp.param/p10.cpp b/test/CXX/temp/temp.param/p10.cpp
index b9dac75beb91..4feea828466e 100644
--- a/test/CXX/temp/temp.param/p10.cpp
+++ b/test/CXX/temp/temp.param/p10.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename> struct Y1;
template<typename, int> struct Y2;
diff --git a/test/CXX/temp/temp.param/p13.cpp b/test/CXX/temp/temp.param/p13.cpp
index 7e7dbe58a7b5..257b36f4f96f 100644
--- a/test/CXX/temp/temp.param/p13.cpp
+++ b/test/CXX/temp/temp.param/p13.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// The scope of atemplate-parameterextends from its point of
// declaration until the end of its template. In particular, a
diff --git a/test/CXX/temp/temp.param/p15-cxx0x.cpp b/test/CXX/temp/temp.param/p15-cxx0x.cpp
index 5fc57a43f541..59618d263683 100644
--- a/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -22,3 +22,157 @@ void f(const X<int> x) {
template<typename T = void> struct X1 { };
X1<X1<>> x1a;
+
+
+namespace ParameterPackExpansions {
+
+// A template parameter pack that [contains an unexpanded parameter pack] is a
+// pack expansion.
+
+template<typename...Ts> struct Outer {
+ // From [temp.variadic]p4:
+ // In a template parameter pack that is a pack expansion, the pattern is
+ // [...the template-parameter...] without the ellipsis.
+ // Therefore the resulting sequence of parameters is not a parameter pack,
+ // so is not required to be the last template parameter.
+ template<Ts ...As, template<Ts> class ...Bs, typename ...Cs> struct Inner {
+ struct Check : Bs<As>... {
+ Check(Cs...);
+ };
+ };
+};
+
+template<int> struct TemplateInt {};
+template<char> struct TemplateChar {};
+template<int*> struct TemplateIntPtr {};
+int x;
+
+Outer<int, char, int*>::
+Inner<12345, 'x', &x,
+ TemplateInt, TemplateChar, TemplateIntPtr,
+ int*>::
+Check check(&x);
+
+
+template<typename...Ts> struct types;
+
+enum place { _ };
+template<place...> struct places {};
+
+template<typename P1, typename P2> struct append_places;
+template<place...X1, place...X2>
+struct append_places<places<X1...>, places<X2...>> {
+ typedef places<X1...,X2...> type;
+};
+
+template<unsigned N>
+struct make_places : append_places<typename make_places<N/2>::type,
+ typename make_places<N-N/2>::type> {};
+template<> struct make_places<0> { typedef places<> type; };
+template<> struct make_places<1> { typedef places<_> type; };
+
+template<typename T> struct wrap {
+ template<place> struct inner { typedef T type; };
+};
+
+template<typename T> struct takedrop_impl;
+template<place...X> struct takedrop_impl<places<X...>> {
+ template<template<decltype(X)> class ...Take,
+ template<place > class ...Drop>
+ struct inner { // expected-note 2{{declared}}
+ typedef types<typename Take<_>::type...> take;
+ typedef types<typename Drop<_>::type...> drop;
+ };
+};
+
+template<unsigned N, typename...Ts> struct take {
+ using type = typename takedrop_impl<typename make_places<N>::type>::
+ template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}}
+};
+template<unsigned N, typename...Ts> struct drop {
+ using type = typename takedrop_impl<typename make_places<N>::type>::
+ template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}}
+};
+
+using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}}
+// FIXME: Desguar the types on the RHS in this diagnostic.
+// desired-error {{'types<void, void, void, void>' vs 'types<int, char, double, (no argument)>'}}
+using T1 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename inner<_>::type, typename inner<_>::type, typename inner<_>::type, (no argument)>'}}
+using D1 = drop<3, int, char, double, long>::type;
+using D1 = types<long>;
+
+using T2 = take<4, int, char, double, long>::type; // expected-note {{previous}}
+using T2 = types<int, char, double, long>;
+// FIXME: Desguar the types on the RHS in this diagnostic.
+// desired-error {{'types<void, void, void, void>' vs 'types<int, char, double, long>'}}
+using T2 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename inner<_>::type, typename inner<_>::type, typename inner<_>::type, typename inner<_>::type>'}}
+using D2 = drop<4, int, char, double, long>::type;
+using D2 = types<>;
+
+using T3 = take<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
+using D3 = drop<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
+
+
+// FIXME: We should accept this code. A parameter pack within a default argument
+// in a template template parameter pack is expanded, because the pack is
+// implicitly a pack expansion.
+template<typename ...Default> struct DefArg {
+ template<template<typename T = Default> class ...Classes> struct Inner { // expected-error {{default argument contains unexpanded parameter pack}} expected-note {{here}}
+ Inner(Classes<>...); // expected-error {{too few}}
+ };
+};
+template<typename T> struct vector {};
+template<typename T> struct list {};
+vector<int> vi;
+list<char> lc;
+DefArg<int, char>::Inner<vector, list> defarg(vi, lc);
+
+
+// FIXME:
+// A template parameter pack that is a pack expansion shall not expand a
+// parameter pack declared in the same template-parameter-list.
+template<typename...Ts, Ts...Vs> void error(); // desired-error
+
+// This case should not produce an error, because in A's instantiation, Cs is
+// not a parameter pack.
+template<typename...Ts> void consume(Ts...);
+template<typename...Ts> struct A {
+ template<template<typename, Ts = 0> class ...Cs, Cs<Ts> ...Vs> struct B { // ok
+ B() {
+ consume([]{
+ int arr[Vs]; // expected-error {{negative size}}
+ }...);
+ }
+ };
+};
+template<typename, int> using Int = int;
+template<typename, short> using Char = char;
+A<int, short>::B<Int, Char, -1, 'x'> b; // expected-note {{here}}
+
+}
+
+namespace PR9023 {
+ template<typename ...T> struct A {
+ template<template<T> class ...> struct B {
+ };
+ };
+
+ template<int> struct C { };
+ template<long> struct D { };
+
+ int main() {
+ A<int, long>::B<C, D> e;
+ }
+}
+
+namespace std_examples {
+ template <class... Types> class Tuple;
+ template <class T, int... Dims> struct multi_array;
+ template <class... T> struct value_holder {
+ template<T... Values> struct apply { };
+ };
+ template <class... T, T... Values> struct static_array; // expected-error {{must be the last}}
+
+ int n;
+ value_holder<int, char, int*>::apply<12345, 'x', &n> test;
+}
diff --git a/test/CXX/temp/temp.param/p2.cpp b/test/CXX/temp/temp.param/p2.cpp
index fed6e9c266be..4eca05774ab5 100644
--- a/test/CXX/temp/temp.param/p2.cpp
+++ b/test/CXX/temp/temp.param/p2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// There is no semantic difference between class and typename in a
// template-parameter. typename followed by an unqualified-id names a
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
index 3cbb3b7c0103..67efc4e48162 100644
--- a/test/CXX/temp/temp.param/p5.cpp
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s -std=c++11
+// expected-no-diagnostics
template<const int I> struct S {
decltype(I) n;
diff --git a/test/CXX/temp/temp.param/p8.cpp b/test/CXX/temp/temp.param/p8.cpp
index fed048cad8b6..592e41ec408e 100644
--- a/test/CXX/temp/temp.param/p8.cpp
+++ b/test/CXX/temp/temp.param/p8.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<int X[10]> struct A;
template<int *X> struct A;
template<int f(float, double)> struct B;
diff --git a/test/CXX/temp/temp.res/temp.dep/p3.cpp b/test/CXX/temp/temp.res/temp.dep/p3.cpp
index c41a4c60ee74..88b4752e6b76 100644
--- a/test/CXX/temp/temp.res/temp.dep/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct A0 {
struct K { };
};
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
index 0aba4028b769..8f2a599ab28a 100644
--- a/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
+// expected-no-diagnostics
template<int n> struct S;
diff --git a/test/CXX/temp/temp.res/temp.local/p1.cpp b/test/CXX/temp/temp.res/temp.local/p1.cpp
index 1ad4464c975c..f6ef636daa56 100644
--- a/test/CXX/temp/temp.res/temp.local/p1.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// C++0x [temp.local]p1:
// Like normal (non-template) classes, class templates have an
diff --git a/test/CXX/temp/temp.res/temp.local/p7.cpp b/test/CXX/temp/temp.res/temp.local/p7.cpp
index bd05e756a19e..3fa9c9952609 100644
--- a/test/CXX/temp/temp.res/temp.local/p7.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p7.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<class T> struct A {
int B;
diff --git a/test/CXX/temp/temp.res/temp.local/p8.cpp b/test/CXX/temp/temp.res/temp.local/p8.cpp
index 5d9d50913f36..fecfed06f109 100644
--- a/test/CXX/temp/temp.res/temp.local/p8.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p8.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace N {
enum { C };
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
index 3843c0d2c880..263356e949a3 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// This test creates cases where implicit instantiations of various entities
// would cause a diagnostic, but provides expliict specializations for those
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
index 5fa2f627b009..f03811f35e60 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v);
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
index d4ce01fd6501..10ec66d53994 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace N {
template<class T> class X { /* ... */ };
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p11.cpp b/test/CXX/temp/temp.spec/temp.explicit/p11.cpp
index 4ca54283157b..5363cbe0aedf 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p11.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
class X {
template <typename T> class Y {};
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
index 1028830abe75..146b6b5da80b 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
+// expected-no-diagnostics
// If the name declared in the explicit instantiation is an
// unqualified name, the explicit instantiation shall appear in the
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p6.cpp b/test/CXX/temp/temp.spec/temp.explicit/p6.cpp
index 13822725b5bd..0f5db2119052 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p6.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p6.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { }
diff --git a/test/CodeCompletion/Inputs/macros.h b/test/CodeCompletion/Inputs/macros.h
index 98b5ac6510a1..5f15dfc2be35 100644
--- a/test/CodeCompletion/Inputs/macros.h
+++ b/test/CodeCompletion/Inputs/macros.h
@@ -2,3 +2,10 @@
#define BAR(X, Y) X, Y
#define IDENTITY(X) X
#define WIBBLE(...)
+#define DEAD_MACRO
+#undef DEAD_MACRO
+#define MACRO_WITH_HISTORY a
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY b, c
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY(X, Y) X->Y
diff --git a/test/CodeCompletion/macros.c b/test/CodeCompletion/macros.c
index 0758bbf76887..28f69b2e1b1f 100644
--- a/test/CodeCompletion/macros.c
+++ b/test/CodeCompletion/macros.c
@@ -13,11 +13,15 @@ void test(struct Point *p) {
// RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s
case
}
+ // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:17:7 %s -o - | FileCheck -check-prefix=CC3 %s
+#ifdef Q
+#endif
// Run the same tests, this time with macros loaded from the PCH file.
// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/macros.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s
+ // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:17:7 %s -o - | FileCheck -check-prefix=CC3 %s
// CC1: color
// CC1: x
@@ -29,6 +33,14 @@ void test(struct Point *p) {
// CC2: FOO
// CC2: Green
// CC2: IDENTITY(<#X#>)
+ // CC2: MACRO_WITH_HISTORY(<#X#>, <#Y#>)
// CC2: Red
// CC2: WIBBLE
+
+ // CC3: BAR
+ // CC3: DEAD_MACRO
+ // CC3: FOO
+ // CC3: IDENTITY
+ // CC3: MACRO_WITH_HISTORY
+ // CC3: WIBBLE
}
diff --git a/test/CodeCompletion/preamble.c b/test/CodeCompletion/preamble.c
index f322e09f12e0..90ed5656d176 100644
--- a/test/CodeCompletion/preamble.c
+++ b/test/CodeCompletion/preamble.c
@@ -4,4 +4,4 @@ void foo() {
x.
// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:4:5 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: FieldDecl:{ResultType int}{TypedText m} (35) (parent: StructDecl 'X')
+// CHECK-CC1: FieldDecl:{ResultType int}{TypedText m} (35)
diff --git a/test/CodeGen/2004-03-16-AsmRegisterCrash.c b/test/CodeGen/2004-03-16-AsmRegisterCrash.c
index 515d2436b1a8..492e24853dec 100644
--- a/test/CodeGen/2004-03-16-AsmRegisterCrash.c
+++ b/test/CodeGen/2004-03-16-AsmRegisterCrash.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
-// XFAIL: *
-// XTARGET: arm, i386, i686, x86_64
+// RUN: %clang_cc1 -triple armv7-unknown-unknown %s -o /dev/null
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -o /dev/null
int foo() {
#ifdef __arm__
diff --git a/test/CodeGen/2008-01-25-ByValReadNone.c b/test/CodeGen/2008-01-25-ByValReadNone.c
index d977139b2120..ca21f6c443a0 100644
--- a/test/CodeGen/2008-01-25-ByValReadNone.c
+++ b/test/CodeGen/2008-01-25-ByValReadNone.c
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | not grep readonly
-// RUN: %clang_cc1 -emit-llvm -o - %s | not grep readnone
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-// XFAIL: arm,mips
+// XFAIL: mips
+
+// CHECK-NOT: readonly
+// CHECK-NOT: readnone
// The struct being passed byval means that we cannot mark the
// function readnone. Readnone would allow stores to the arg to
diff --git a/test/CodeGen/2008-01-25-ZeroSizedAggregate.c b/test/CodeGen/2008-01-25-ZeroSizedAggregate.c
index d9059856254f..3ffcc7b0c578 100644
--- a/test/CodeGen/2008-01-25-ZeroSizedAggregate.c
+++ b/test/CodeGen/2008-01-25-ZeroSizedAggregate.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o -
+// REQUIRES: LP64
// Aggregates of size zero should be dropped from argument list.
typedef long int Tlong;
diff --git a/test/CodeGen/2008-12-23-AsmIntPointerTie.c b/test/CodeGen/2008-12-23-AsmIntPointerTie.c
index df646b7801f7..04b285e6866c 100644
--- a/test/CodeGen/2008-12-23-AsmIntPointerTie.c
+++ b/test/CodeGen/2008-12-23-AsmIntPointerTie.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -O1 -o -
+// REQUIRES: LP64
typedef long intptr_t;
int test(void *b) {
diff --git a/test/CodeGen/2009-06-01-addrofknr.c b/test/CodeGen/2009-06-01-addrofknr.c
index 17d6fdf5d89f..f987e3270c87 100644
--- a/test/CodeGen/2009-06-01-addrofknr.c
+++ b/test/CodeGen/2009-06-01-addrofknr.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -o %t -emit-llvm -verify
+// expected-no-diagnostics
// PR4289
struct funcptr {
diff --git a/test/CodeGen/2010-06-17-asmcrash.c b/test/CodeGen/2010-06-17-asmcrash.c
index 8e9485bba9b8..1b5efd3cfeb1 100644
--- a/test/CodeGen/2010-06-17-asmcrash.c
+++ b/test/CodeGen/2010-06-17-asmcrash.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | llc -mtriple=x86_64-apple-darwin | FileCheck %s
-// XFAIL: *
-// XTARGET: x86,i386,i686
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O1 -S -o - %s | FileCheck %s
typedef long long int64_t;
typedef unsigned char uint8_t;
diff --git a/test/CodeGen/PR3589-freestanding-libcalls.c b/test/CodeGen/PR3589-freestanding-libcalls.c
index 8b8282fb80b9..40e5fb11214b 100644
--- a/test/CodeGen/PR3589-freestanding-libcalls.c
+++ b/test/CodeGen/PR3589-freestanding-libcalls.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep 'declare i32 @printf' | count 1
-// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 1
-// RUN: %clang_cc1 -ffreestanding -O2 -emit-llvm %s -o - | grep 'declare i32 @puts' | count 0
+// 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
int printf(const char *, ...);
diff --git a/test/CodeGen/a15.c b/test/CodeGen/a15.c
new file mode 100644
index 000000000000..e4986d885391
--- /dev/null
+++ b/test/CodeGen/a15.c
@@ -0,0 +1,5 @@
+// RUN: %clang -target armv7-none-linux-gnueabi -mcpu=cortex-a15 -emit-llvm -S %s -o /dev/null
+
+int main() {
+ return 0;
+}
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
index da68b1d703fa..5c9862d85b5e 100644
--- a/test/CodeGen/address-safety-attr.cpp
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -faddress-sanitizer | FileCheck -check-prefix ASAN %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix ASAN %s
// The address_safety attribute should be attached to functions
// when AddressSanitizer is enabled, unless no_address_safety_analysis attribute
diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
index f2e87a5dafbc..0ccbca645157 100644
--- a/test/CodeGen/alias.c
+++ b/test/CodeGen/alias.c
@@ -1,32 +1,46 @@
-// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o %t %s
-// RUN: grep '@g0 = common global i32 0' %t
-// RUN: grep '@f1 = alias void ()\* @f0' %t
-// RUN: grep '@g1 = alias i32\* @g0' %t
-// RUN: grep 'define void @f0() nounwind {' %t
-
-void f0(void) { }
-extern void f1(void);
-extern void f1(void) __attribute((alias("f0")));
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECKBASIC %s
+// RUN: %clang_cc1 -triple armv7a-eabi -mfloat-abi hard -emit-llvm -o - %s | FileCheck -check-prefix=CHECKCC %s
int g0;
+// CHECKBASIC: @g0 = common global i32 0
+static int bar1 = 42;
+// CHECKBASIC: @bar1 = internal global i32 42
+
extern int g1;
extern int g1 __attribute((alias("g0")));
+// CHECKBASIC: @g1 = alias i32* @g0
+
+void f0(void) { }
+extern void f1(void);
+extern void f1(void) __attribute((alias("f0")));
+// CHECKBASIC: @f1 = alias void ()* @f0
+// CHECKBASIC: define void @f0() nounwind {
// Make sure that aliases cause referenced values to be emitted.
// PR3200
-// RUN: grep 'define internal i32 @foo1()' %t
static inline int foo1() { return 0; }
+// CHECKBASIC: define internal i32 @foo1()
int foo() __attribute__((alias("foo1")));
-
-
-// RUN: grep '@bar1 = internal global i32 42' %t
-static int bar1 = 42;
int bar() __attribute__((alias("bar1")));
-
extern int test6();
void test7() { test6(); } // test6 is emitted as extern.
// test6 changes to alias.
int test6() __attribute__((alias("test7")));
+static int inner(int a) { return 0; }
+static int inner_weak(int a) { return 0; }
+extern __typeof(inner) inner_a __attribute__((alias("inner")));
+static __typeof(inner_weak) inner_weak_a __attribute__((weakref, alias("inner_weak")));
+// CHECKCC: @inner_a = alias i32 (i32)* @inner
+// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner(i32 %a) nounwind {
+
+int outer(int a) { return inner(a); }
+// CHECKCC: define arm_aapcs_vfpcc i32 @outer(i32 %a) nounwind {
+// CHECKCC: call arm_aapcs_vfpcc i32 @inner(i32 %{{.*}})
+
+int outer_weak(int a) { return inner_weak_a(a); }
+// CHECKCC: define arm_aapcs_vfpcc i32 @outer_weak(i32 %a) nounwind {
+// CHECKCC: call arm_aapcs_vfpcc i32 @inner_weak(i32 %{{.*}})
+// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner_weak(i32 %a) nounwind {
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index 614b52dad576..7210229f377b 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -6,6 +6,12 @@
// RUN: -ffreestanding \
// RUN: -emit-llvm -w -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-unknown-nacl-gnueabi \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -mfloat-abi hard \
+// RUN: -ffreestanding \
+// RUN: -emit-llvm -w -o - %s | FileCheck %s
+
#include <arm_neon.h>
struct homogeneous_struct {
diff --git a/test/CodeGen/arm-aapcs-zerolength-bitfield.c b/test/CodeGen/arm-aapcs-zerolength-bitfield.c
index 140ff6c42436..2855045c1e78 100644
--- a/test/CodeGen/arm-aapcs-zerolength-bitfield.c
+++ b/test/CodeGen/arm-aapcs-zerolength-bitfield.c
@@ -1,5 +1,6 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -target-abi aapcs -triple armv7-apple-darwin10 %s -verify
+// expected-no-diagnostics
#include <stddef.h>
diff --git a/test/CodeGen/arm-abi-vector.c b/test/CodeGen/arm-abi-vector.c
new file mode 100644
index 000000000000..12e38ba43419
--- /dev/null
+++ b/test/CodeGen/arm-abi-vector.c
@@ -0,0 +1,263 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi aapcs -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-apple-darwin -target-abi apcs-gnu -emit-llvm -o - %s | FileCheck -check-prefix=APCS-GNU %s
+
+#include <stdarg.h>
+
+typedef __attribute__(( ext_vector_type(2) )) int __int2;
+typedef __attribute__(( ext_vector_type(3) )) char __char3;
+typedef __attribute__(( ext_vector_type(5) )) char __char5;
+typedef __attribute__(( ext_vector_type(9) )) char __char9;
+typedef __attribute__(( ext_vector_type(19) )) char __char19;
+typedef __attribute__(( ext_vector_type(3) )) short __short3;
+typedef __attribute__(( ext_vector_type(5) )) short __short5;
+
+// Passing legal vector types as varargs.
+double varargs_vec_2i(int fixed, ...) {
+// CHECK: varargs_vec_2i
+// CHECK: alloca <2 x i32>, align 8
+// CHECK: [[ALIGN:%.*]] = and i32 [[VAR:%.*]], -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
+// CHECK: bitcast i8* [[AP_ALIGN]] to <2 x i32>*
+// APCS-GNU: varargs_vec_2i
+// APCS-GNU: alloca <2 x i32>, align 8
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <2 x i32>
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
+// APCS-GNU: bitcast <2 x i32>* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+// APCS-GNU: load <2 x i32>* [[VAR_ALIGN]]
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __int2 c3 = va_arg(ap, __int2);
+ sum = sum + c3.x + c3.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_2i(__int2 *in) {
+// CHECK: test_2i
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
+// APCS-GNU: test_2i
+// APCS-GNU: call double (i32, ...)* @varargs_vec_2i(i32 3, <2 x i32> {{%.*}})
+ return varargs_vec_2i(3, *in);
+}
+
+double varargs_vec_3c(int fixed, ...) {
+// CHECK: varargs_vec_3c
+// CHECK: alloca <3 x i8>, align 4
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
+// CHECK: bitcast i8* [[AP]] to <3 x i8>*
+// APCS-GNU: varargs_vec_3c
+// APCS-GNU: alloca <3 x i8>, align 4
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
+// APCS-GNU: bitcast i8* [[AP]] to <3 x i8>*
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __char3 c3 = va_arg(ap, __char3);
+ sum = sum + c3.x + c3.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_3c(__char3 *in) {
+// CHECK: test_3c
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
+// APCS-GNU: test_3c
+// APCS-GNU: call double (i32, ...)* @varargs_vec_3c(i32 3, i32 {{%.*}})
+ return varargs_vec_3c(3, *in);
+}
+
+double varargs_vec_5c(int fixed, ...) {
+// CHECK: varargs_vec_5c
+// CHECK: alloca <5 x i8>, align 8
+// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
+// CHECK: bitcast i8* [[AP_ALIGN]] to <5 x i8>*
+// APCS-GNU: varargs_vec_5c
+// APCS-GNU: alloca <5 x i8>, align 8
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <5 x i8>
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
+// APCS-GNU: bitcast <5 x i8>* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+// APCS-GNU: load <5 x i8>* [[VAR_ALIGN]]
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __char5 c5 = va_arg(ap, __char5);
+ sum = sum + c5.x + c5.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_5c(__char5 *in) {
+// CHECK: test_5c
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+// APCS-GNU: test_5c
+// APCS-GNU: call double (i32, ...)* @varargs_vec_5c(i32 5, <2 x i32> {{%.*}})
+ return varargs_vec_5c(5, *in);
+}
+
+double varargs_vec_9c(int fixed, ...) {
+// CHECK: varargs_vec_9c
+// CHECK: alloca <9 x i8>, align 16
+// CHECK: [[VAR_ALIGN:%.*]] = alloca <9 x i8>
+// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
+// CHECK: bitcast <9 x i8>* [[VAR_ALIGN]] to i8*
+// CHECK: call void @llvm.memcpy
+// CHECK: load <9 x i8>* [[VAR_ALIGN]]
+// APCS-GNU: varargs_vec_9c
+// APCS-GNU: alloca <9 x i8>, align 16
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <9 x i8>
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
+// APCS-GNU: bitcast <9 x i8>* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+// APCS-GNU: load <9 x i8>* [[VAR_ALIGN]]
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __char9 c9 = va_arg(ap, __char9);
+ sum = sum + c9.x + c9.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_9c(__char9 *in) {
+// CHECK: test_9c
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+// APCS-GNU: test_9c
+// APCS-GNU: call double (i32, ...)* @varargs_vec_9c(i32 9, <4 x i32> {{%.*}})
+ return varargs_vec_9c(9, *in);
+}
+
+double varargs_vec_19c(int fixed, ...) {
+// CHECK: varargs_vec_19c
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
+// CHECK: [[VAR:%.*]] = bitcast i8* [[AP]] to i8**
+// CHECK: [[VAR2:%.*]] = load i8** [[VAR]]
+// CHECK: bitcast i8* [[VAR2]] to <19 x i8>*
+// APCS-GNU: varargs_vec_19c
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* [[AP:%.*]], i32 4
+// APCS-GNU: [[VAR:%.*]] = bitcast i8* [[AP]] to i8**
+// APCS-GNU: [[VAR2:%.*]] = load i8** [[VAR]]
+// APCS-GNU: bitcast i8* [[VAR2]] to <19 x i8>*
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __char19 c19 = va_arg(ap, __char19);
+ sum = sum + c19.x + c19.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_19c(__char19 *in) {
+// CHECK: test_19c
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+// APCS-GNU: test_19c
+// APCS-GNU: call double (i32, ...)* @varargs_vec_19c(i32 19, <19 x i8>* {{%.*}})
+ return varargs_vec_19c(19, *in);
+}
+
+double varargs_vec_3s(int fixed, ...) {
+// CHECK: varargs_vec_3s
+// CHECK: alloca <3 x i16>, align 8
+// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 8
+// CHECK: bitcast i8* [[AP_ALIGN]] to <3 x i16>*
+// APCS-GNU: varargs_vec_3s
+// APCS-GNU: alloca <3 x i16>, align 8
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <3 x i16>
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 8
+// APCS-GNU: bitcast <3 x i16>* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+// APCS-GNU: load <3 x i16>* [[VAR_ALIGN]]
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __short3 c3 = va_arg(ap, __short3);
+ sum = sum + c3.x + c3.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_3s(__short3 *in) {
+// CHECK: test_3s
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+// APCS-GNU: test_3s
+// APCS-GNU: call double (i32, ...)* @varargs_vec_3s(i32 3, <2 x i32> {{%.*}})
+ return varargs_vec_3s(3, *in);
+}
+
+double varargs_vec_5s(int fixed, ...) {
+// CHECK: varargs_vec_5s
+// CHECK: alloca <5 x i16>, align 16
+// CHECK: [[VAR_ALIGN:%.*]] = alloca <5 x i16>
+// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
+// CHECK: bitcast <5 x i16>* [[VAR_ALIGN]] to i8*
+// CHECK: call void @llvm.memcpy
+// CHECK: load <5 x i16>* [[VAR_ALIGN]]
+// APCS-GNU: varargs_vec_5s
+// APCS-GNU: alloca <5 x i16>, align 16
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca <5 x i16>
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
+// APCS-GNU: bitcast <5 x i16>* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+// APCS-GNU: load <5 x i16>* [[VAR_ALIGN]]
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ __short5 c5 = va_arg(ap, __short5);
+ sum = sum + c5.x + c5.y;
+ va_end(ap);
+ return sum;
+}
+
+double test_5s(__short5 *in) {
+// CHECK: test_5s
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+// APCS-GNU: test_5s
+// APCS-GNU: call double (i32, ...)* @varargs_vec_5s(i32 5, <4 x i32> {{%.*}})
+ return varargs_vec_5s(5, *in);
+}
+
+// Pass struct as varargs.
+typedef struct
+{
+ __int2 i2;
+ float f;
+} StructWithVec;
+
+double varargs_struct(int fixed, ...) {
+// CHECK: varargs_struct
+// CHECK: [[ALIGN:%.*]] = and i32 {{%.*}}, -8
+// CHECK: [[AP_ALIGN:%.*]] = inttoptr i32 [[ALIGN]] to i8*
+// CHECK: [[AP_NEXT:%.*]] = getelementptr i8* [[AP_ALIGN]], i32 16
+// CHECK: bitcast i8* [[AP_ALIGN]] to %struct.StructWithVec*
+// APCS-GNU: varargs_struct
+// APCS-GNU: [[VAR_ALIGN:%.*]] = alloca %struct.StructWithVec
+// APCS-GNU: [[AP_NEXT:%.*]] = getelementptr i8* {{%.*}}, i32 16
+// APCS-GNU: bitcast %struct.StructWithVec* [[VAR_ALIGN]] to i8*
+// APCS-GNU: call void @llvm.memcpy
+ va_list ap;
+ double sum = fixed;
+ va_start(ap, fixed);
+ StructWithVec c3 = va_arg(ap, StructWithVec);
+ sum = sum + c3.i2.x + c3.i2.y + c3.f;
+ va_end(ap);
+ return sum;
+}
+
+double test_struct(StructWithVec* d) {
+// CHECK: test_struct
+// CHECK: call arm_aapcscc double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
+// APCS-GNU: test_struct
+// APCS-GNU: call double (i32, ...)* @varargs_struct(i32 3, [2 x i64] {{%.*}})
+ return varargs_struct(3, *d);
+}
diff --git a/test/CodeGen/arm-apcs-zerolength-bitfield.c b/test/CodeGen/arm-apcs-zerolength-bitfield.c
index 049ffae4dc6f..763db65063fc 100644
--- a/test/CodeGen/arm-apcs-zerolength-bitfield.c
+++ b/test/CodeGen/arm-apcs-zerolength-bitfield.c
@@ -1,5 +1,6 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -target-abi apcs-gnu -triple armv7-apple-darwin10 %s -verify
+// expected-no-diagnostics
//
// Note: gcc forces the alignment to 4 bytes, regardless of the type of the
// zero length bitfield.
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 2ec729eb9b3d..63ecd4c5990b 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -178,3 +178,48 @@ 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)
+
+// PR14048
+struct s34 { char c; };
+void f34(struct s34 s);
+void g34(struct s34 *s) { f34(*s); }
+// APCS-GNU: @g34(%struct.s34* %s)
+// APCS-GNU: %[[a:.*]] = alloca { [1 x i32] }
+// APCS-GNU: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
+// APCS-GNU: load [1 x i32]* %[[gep]]
+// AAPCS: @g34(%struct.s34* %s)
+// AAPCS: %[[a:.*]] = alloca { [1 x i32] }
+// AAPCS: %[[gep:.*]] = getelementptr { [1 x i32] }* %[[a]], i32 0, i32 0
+// AAPCS: load [1 x i32]* %[[gep]]
+
+// rdar://12596507
+struct s35
+{
+ float v[18]; //make sure byval is on.
+} __attribute__((aligned(16)));
+typedef struct s35 s35_with_align;
+
+typedef __attribute__((neon_vector_type(4))) float float32x4_t;
+static __attribute__((__always_inline__, __nodebug__)) float32x4_t vaddq_f32(
+ float32x4_t __a, float32x4_t __b) {
+ return __a + __b;
+}
+float32x4_t f35(int i, s35_with_align s1, s35_with_align s2) {
+ float32x4_t v = vaddq_f32(*(float32x4_t *)&s1,
+ *(float32x4_t *)&s2);
+ return v;
+}
+// APCS-GNU: 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: %[[a:.*]] = alloca %struct.s35, align 16
+// AAPCS: %[[b:.*]] = bitcast %struct.s35* %[[a]] to i8*
+// AAPCS: %[[c:.*]] = bitcast %struct.s35* %0 to i8*
+// AAPCS: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %[[b]], i8* %[[c]]
+// AAPCS: %[[d:.*]] = bitcast %struct.s35* %[[a]] to <4 x float>*
+// AAPCS: load <4 x float>* %[[d]], align 16
diff --git a/test/CodeGen/arm-asm-warn.c b/test/CodeGen/arm-asm-warn.c
new file mode 100644
index 000000000000..0c4e97aba0d1
--- /dev/null
+++ b/test/CodeGen/arm-asm-warn.c
@@ -0,0 +1,18 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple armv7 %s -emit-llvm -o /dev/null
+// <rdar://problem/12284092>
+
+typedef __attribute__((neon_vector_type(2))) long long int64x2_t;
+typedef struct int64x2x4_t {
+ int64x2_t val[4];
+} 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 size being stored is truncated, use a modifier to specify the size}}
+ [r1] "=r"(r.val[1]), // expected-warning {{the size being stored is truncated, use a modifier to specify the size}}
+ [r2] "=r"(r.val[2]), // expected-warning {{the size being stored is truncated, use a modifier to specify the size}}
+ [r3] "=r"(r.val[3]) // expected-warning {{the size being stored is truncated, use a modifier to specify the size}}
+ : [a] "r"(a));
+ return r;
+}
diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c
index b8d046af9722..5d21088eba8e 100644
--- a/test/CodeGen/arm-homogenous.c
+++ b/test/CodeGen/arm-homogenous.c
@@ -156,6 +156,47 @@ void test_return_union_with_struct_with_fundamental_elems(void) {
}
// CHECK: declare arm_aapcs_vfpcc %union.union_with_struct_with_fundamental_elems @returns_union_with_struct_with_fundamental_elems()
+// Make sure HAs that can be partially fit into VFP registers will be allocated
+// on stack and that later VFP candidates will go on stack as well.
+typedef struct {
+ double x;
+ double a2;
+ double a3;
+ double a4;
+} struct_of_four_doubles;
+extern void takes_struct_of_four_doubles(double a, struct_of_four_doubles b, struct_of_four_doubles c, double d);
+struct_of_four_doubles g_s4d;
+
+void test_struct_of_four_doubles(void) {
+// CHECK: test_struct_of_four_doubles
+// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [6 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
+ takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
+}
+
+extern void takes_struct_with_backfill(float f1, double a, float f2, struct_of_four_doubles b, struct_of_four_doubles c, double d);
+void test_struct_with_backfill(void) {
+// CHECK: test_struct_with_backfill
+// CHECK: call arm_aapcs_vfpcc void @takes_struct_with_backfill(float {{.*}}, double {{.*}}, float {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [4 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
+ takes_struct_with_backfill(3.0, 3.1, 3.2, g_s4d, g_s4d, 4.0);
+}
+
+typedef __attribute__(( ext_vector_type(8) )) char __char8;
+typedef __attribute__(( ext_vector_type(4) )) short __short4;
+typedef struct {
+ __char8 a1;
+ __short4 a2;
+ __char8 a3;
+ __short4 a4;
+} struct_of_vecs;
+extern void takes_struct_of_vecs(double a, struct_of_vecs b, struct_of_vecs c, double d);
+struct_of_vecs g_vec;
+
+void test_struct_of_vecs(void) {
+// CHECK: test_struct_of_vecs
+// CHECK: call arm_aapcs_vfpcc void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [6 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
+ takes_struct_of_vecs(3.0, g_vec, g_vec, 4.0);
+}
+
// FIXME: Tests necessary:
// - Vectors
// - C++ stuff
diff --git a/test/CodeGen/arm-pnaclcall.c b/test/CodeGen/arm-pnaclcall.c
new file mode 100644
index 000000000000..50259957eb15
--- /dev/null
+++ b/test/CodeGen/arm-pnaclcall.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple armv7-unknown-nacl-gnueabi \
+// RUN: -ffreestanding -mfloat-abi hard -target-cpu cortex-a8 \
+// RUN: -emit-llvm -w -o - %s | FileCheck %s
+
+// Test that functions with pnaclcall attribute generate portable bitcode
+// like the le32 arch target
+
+typedef struct {
+ int a;
+ int b;
+} s1;
+// CHECK: 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)
+s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
+
+union simple_union {
+ int a;
+ char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f50(%union.simple_union* byval %s)
+void __attribute__((pnaclcall)) f50(union simple_union s) {}
+
+typedef struct {
+ int b4 : 4;
+ int b3 : 3;
+ int b8 : 8;
+} bitfield1;
+// Bitfields should be passed as byval structs
+// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index b0097368ec28..670c24405d33 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -230,3 +230,12 @@ void t27(void) {
// CHECK-NOT: ia_nsdialect
// CHECK: ret void
}
+
+// Check handling of '*' and '#' constraint modifiers.
+void t28(void)
+{
+ asm volatile ("/* %0 */" : : "i#*X,*r" (1));
+// CHECK: @t28
+// CHECK: call void asm sideeffect "/* $0 */", "i|r,~{dirflag},~{fpsr},~{flags}"(i32 1)
+}
+
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
index 1a9ed36ee23e..d79f40522344 100644
--- a/test/CodeGen/atomic-ops.c
+++ b/test/CodeGen/atomic-ops.c
@@ -311,4 +311,13 @@ void atomic_init_foo()
// 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/attr-minsize.cpp b/test/CodeGen/attr-minsize.cpp
new file mode 100644
index 000000000000..a422a62f2535
--- /dev/null
+++ b/test/CodeGen/attr-minsize.cpp
@@ -0,0 +1,75 @@
+// 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 -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
+// RUN: %clang_cc1 -Os -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
+// Check that we set the minsize attribute on each function
+// when Oz optimization level is set.
+
+int test1() {
+ return 42;
+// Oz: @{{.*}}test1{{.*}}minsize
+// Oz: ret
+// OTHER: @{{.*}}test1
+// OTHER-NOT: minsize
+// OTHER: ret
+}
+
+int test2() {
+ return 42;
+// Oz: @{{.*}}test2{{.*}}minsize
+// Oz: ret
+// OTHER: @{{.*}}test2
+// OTHER-NOT: minsize
+// OTHER: ret
+}
+
+__attribute__((minsize))
+int test3() {
+ return 42;
+// Oz: @{{.*}}test3{{.*}}minsize
+// OTHER: @{{.*}}test3{{.*}}minsize
+}
+
+// Check that the minsize attribute is well propagated through
+// template instantiation
+
+template<typename T>
+__attribute__((minsize))
+void test4(T arg) {
+ return;
+}
+
+template
+void test4<int>(int arg);
+// Oz: define{{.*}}void @{{.*}}test4
+// Oz: minsize
+// OTHER: define{{.*}}void @{{.*}}test4
+// OTHER: minsize
+
+template
+void test4<float>(float arg);
+// Oz: define{{.*}}void @{{.*}}test4
+// Oz: minsize
+// OTHER: define{{.*}}void @{{.*}}test4
+// OTHER: minsize
+
+template<typename T>
+void test5(T arg) {
+ return;
+}
+
+template
+void test5<int>(int arg);
+// Oz: define{{.*}}void @{{.*}}test5
+// Oz: minsize
+// OTHER: define{{.*}}void @{{.*}}test5
+// OTHER-NOT: minsize
+
+template
+void test5<float>(float arg);
+// Oz: define{{.*}}void @{{.*}}test5
+// Oz: minsize
+// OTHER: define{{.*}}void @{{.*}}test5
+// OTHER-NOT: minsize
diff --git a/test/CodeGen/attr-weakref.c b/test/CodeGen/attr-weakref.c
index c1cc03b668d9..560d39141ca9 100644
--- a/test/CodeGen/attr-weakref.c
+++ b/test/CodeGen/attr-weakref.c
@@ -53,6 +53,12 @@ void test6_foo(void) {
test6_f();
}
+// CHECK: declare extern_weak void @test8_f()
+static void test8_g(void) __attribute__((weakref("test8_f")));
+void test8_h(void) {
+ if (test8_g)
+ test8_g();
+}
// CHECK: declare extern_weak void @test7_f()
void test7_f(void);
static void test7_g(void) __attribute__((weakref("test7_f")));
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index e971a793473a..00688dc72b5b 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -80,7 +80,7 @@ void t21(void) {
fptr(10);
}
// CHECK: [[FPTRVAR:%[a-z0-9]+]] = load void (i32)** @fptr
-// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 10)
+// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 inreg 10)
// PR9356: We might want to err on this, but for now at least make sure we
diff --git a/test/CodeGen/bitfield-promote.c b/test/CodeGen/bitfield-promote.c
index 4c3292c48feb..93aaa9d8b7a0 100644
--- a/test/CodeGen/bitfield-promote.c
+++ b/test/CodeGen/bitfield-promote.c
@@ -1,18 +1,22 @@
-// RUN: %clang -O3 -emit-llvm -S -o %t %s
-// RUN: grep 'ret i64 4294967292' %t | count 2
-// RUN: grep 'ret i64 -4' %t | count 1
+// RUN: %clang -O3 -emit-llvm -S -o - %s | FileCheck %s
long long f0(void) {
struct { unsigned f0 : 32; } x = { 18 };
return (long long) (x.f0 - (int) 22);
}
+// CHECK: @f0()
+// CHECK: ret i64 4294967292
long long f1(void) {
struct { unsigned f0 : 31; } x = { 18 };
return (long long) (x.f0 - (int) 22);
}
+// CHECK: @f1()
+// CHECK: ret i64 -4
long long f2(void) {
struct { unsigned f0 ; } x = { 18 };
return (long long) (x.f0 - (int) 22);
}
+// CHECK: @f2()
+// CHECK: ret i64 4294967292
diff --git a/test/CodeGen/bmi2-builtins.c b/test/CodeGen/bmi2-builtins.c
index 18b2319f9f97..201cac63b9fe 100644
--- a/test/CodeGen/bmi2-builtins.c
+++ b/test/CodeGen/bmi2-builtins.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -O3 -triple=i386-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s --check-prefix=B32
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -20,6 +21,15 @@ unsigned int test_pext_u32(unsigned int __X, unsigned int __Y) {
return _pext_u32(__X, __Y);
}
+unsigned int test_mulx_u32(unsigned int __X, unsigned int __Y,
+ unsigned int *__P) {
+ // CHECK: @test_mulx_u32
+ // CHECK-NOT: mul i64
+ // B32: @test_mulx_u32
+ // B32: mul i64
+ return _mulx_u32(__X, __Y, __P);
+}
+
unsigned long long test_bzhi_u64(unsigned long long __X, unsigned long long __Y) {
// CHECK: @llvm.x86.bmi.bzhi.64
return _bzhi_u64(__X, __Y);
@@ -34,3 +44,10 @@ unsigned long long test_pext_u64(unsigned long long __X, unsigned long long __Y)
// CHECK: @llvm.x86.bmi.pext.64
return _pext_u64(__X, __Y);
}
+
+unsigned long long test_mulx_u64(unsigned long long __X, unsigned long long __Y,
+ unsigned long long *__P) {
+ // CHECK: @test_mulx_u64
+ // CHECK: mul i128
+ return _mulx_u64(__X, __Y, __P);
+}
diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c
index 72d340619f37..4a06160ccbc6 100644
--- a/test/CodeGen/builtin-memfns.c
+++ b/test/CodeGen/builtin-memfns.c
@@ -63,3 +63,23 @@ int test7(int *p) {
__builtin_memset(hwparams, 0, 256); // No crash alignment = 1
// CHECK: call void @llvm.memset{{.*}}256, i32 1, i1 false)
}
+
+// <rdar://problem/11314941>
+// Make sure we don't over-estimate the alignment of fields of
+// packed structs.
+struct PS {
+ int modes[4];
+} __attribute__((packed));
+struct PS ps;
+void test8(int *arg) {
+ // CHECK: @test8
+ // CHECK: call void @llvm.memcpy{{.*}} 16, i32 1, i1 false)
+ __builtin_memcpy(arg, ps.modes, sizeof(struct PS));
+}
+
+__attribute((aligned(16))) int x[4], y[4];
+void test9() {
+ // CHECK: @test9
+ // CHECK: call void @llvm.memcpy{{.*}} 16, i32 16, i1 false)
+ __builtin_memcpy(x, y, sizeof(y));
+}
diff --git a/test/CodeGen/builtin-ms-noop.cpp b/test/CodeGen/builtin-ms-noop.cpp
new file mode 100644
index 000000000000..42c25016b138
--- /dev/null
+++ b/test/CodeGen/builtin-ms-noop.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -emit-llvm %s -o - | FileCheck %s
+
+class A {
+ public:
+ ~A() {}
+};
+
+void f() {
+// CHECK: @_Z1fv
+// CHECK-NOT: call void @_ZN1AD1Ev
+// CHECK: ret void
+ __noop(A());
+};
+
diff --git a/test/CodeGen/builtins-mips-args.c b/test/CodeGen/builtins-mips-args.c
index a961b36a9533..fd3e31443ecf 100644
--- a/test/CodeGen/builtins-mips-args.c
+++ b/test/CodeGen/builtins-mips-args.c
@@ -11,4 +11,27 @@ void foo() {
__builtin_mips_rddsp(-1); // expected-error{{argument should be a value from 0 to 63}}
__builtin_mips_wrdsp(2052, 64); // expected-error{{argument should be a value from 0 to 63}}
__builtin_mips_rddsp(64); // expected-error{{argument should be a value from 0 to 63}}
+
+ // MIPS DSP Rev 2
+
+ __builtin_mips_append(1, 2, a); // expected-error{{argument to '__builtin_mips_append' must be a constant integer}}
+ __builtin_mips_balign(1, 2, a); // expected-error{{argument to '__builtin_mips_balign' must be a constant integer}}
+ __builtin_mips_precr_sra_ph_w(1, 2, a); // expected-error{{argument to '__builtin_mips_precr_sra_ph_w' must be a constant integer}}
+ __builtin_mips_precr_sra_r_ph_w(1, 2, a); // expected-error{{argument to '__builtin_mips_precr_sra_r_ph_w' must be a constant integer}}
+ __builtin_mips_prepend(1, 2, a); // expected-error{{argument to '__builtin_mips_prepend' must be a constant integer}}
+
+ __builtin_mips_append(1, 2, -1); // expected-error{{argument should be a value from 0 to 31}}
+ __builtin_mips_append(1, 2, 32); // expected-error{{argument should be a value from 0 to 31}}
+
+ __builtin_mips_balign(1, 2, -1); // expected-error{{argument should be a value from 0 to 3}}
+ __builtin_mips_balign(1, 2, 4); // expected-error{{argument should be a value from 0 to 3}}
+
+ __builtin_mips_precr_sra_ph_w(1, 2, -1); // expected-error{{argument should be a value from 0 to 31}}
+ __builtin_mips_precr_sra_ph_w(1, 2, 32); // expected-error{{argument should be a value from 0 to 31}}
+
+ __builtin_mips_precr_sra_r_ph_w(1, 2, -1); // expected-error{{argument should be a value from 0 to 31}}
+ __builtin_mips_precr_sra_r_ph_w(1, 2, 32); // expected-error{{argument should be a value from 0 to 31}}
+
+ __builtin_mips_prepend(1, 2, -1); // expected-error{{argument should be a value from 0 to 31}}
+ __builtin_mips_prepend(1, 2, -1); // expected-error{{argument should be a value from 0 to 31}}
}
diff --git a/test/CodeGen/builtins-mips.c b/test/CodeGen/builtins-mips.c
index 8155a43c20f0..ef4662cd5946 100644
--- a/test/CodeGen/builtins-mips.c
+++ b/test/CodeGen/builtins-mips.c
@@ -8,10 +8,14 @@ typedef unsigned int ui32;
typedef long long a64;
typedef signed char v4i8 __attribute__ ((vector_size(4)));
+typedef signed char v4q7 __attribute__ ((vector_size(4)));
+typedef short v2i16 __attribute__ ((vector_size(4)));
typedef short v2q15 __attribute__ ((vector_size(4)));
void foo() {
v2q15 v2q15_r, v2q15_a, v2q15_b, v2q15_c;
+ v2i16 v2i16_r, v2i16_a, v2i16_b, v2i16_c;
+ v4q7 v4q7_r, v4q7_a, v4q7_b;
v4i8 v4i8_r, v4i8_a, v4i8_b, v4i8_c;
q31 q31_r, q31_a, q31_b, q31_c;
i32 i32_r, i32_a, i32_b, i32_c;
@@ -321,4 +325,210 @@ void foo() {
int array_c[100];
i32_r = __builtin_mips_lwx(array_c, 20);
// CHECK: call i32 @llvm.mips.lwx
+
+ // MIPS DSP Rev 2
+
+ v4q7_a = (v4q7) {0x81, 0xff, 0x80, 0x23};
+ v4q7_r = __builtin_mips_absq_s_qb (v4q7_a);
+// CHECK: call <4 x i8> @llvm.mips.absq.s.qb
+
+ v2q15_a = (v2q15) {0x3334, 0x4444};
+ v2q15_b = (v2q15) {0x1111, 0x2222};
+ v2q15_r = __builtin_mips_addqh_ph(v2q15_a, v2q15_b);
+// CHECK: call <2 x i16> @llvm.mips.addqh.ph
+ v2q15_a = (v2q15) {0x3334, 0x4444};
+ v2q15_b = (v2q15) {0x1111, 0x2222};
+ v2q15_r = __builtin_mips_addqh_r_ph(v2q15_a, v2q15_b);
+// CHECK: call <2 x i16> @llvm.mips.addqh.r.ph
+ q31_a = 0x11111112;
+ q31_b = 0x99999999;
+ q31_r = __builtin_mips_addqh_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.addqh.w
+ q31_a = 0x11111112;
+ q31_b = 0x99999999;
+ q31_r = __builtin_mips_addqh_r_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.addqh.r.w
+
+ v2i16_a = (v2i16) {0xffff, 0x2468};
+ v2i16_b = (v2i16) {0x1234, 0x1111};
+ v2i16_r = __builtin_mips_addu_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.addu.ph
+ v2i16_a = (v2i16) {0xffff, 0x2468};
+ v2i16_b = (v2i16) {0x1234, 0x1111};
+ v2i16_r = __builtin_mips_addu_s_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.addu.s.ph
+ v4i8_a = (v4i8) {0x11, 0x22, 0x33, 0xff};
+ v4i8_b = (v4i8) {0x11, 0x33, 0x99, 0xff};
+ v4i8_r = __builtin_mips_adduh_qb(v4i8_a, v4i8_b);
+// CHECK: call <4 x i8> @llvm.mips.adduh.qb
+ v4i8_a = (v4i8) {0x11, 0x22, 0x33, 0xff};
+ v4i8_b = (v4i8) {0x11, 0x33, 0x99, 0xff};
+ v4i8_r = __builtin_mips_adduh_r_qb(v4i8_a, v4i8_b);
+// CHECK: call <4 x i8> @llvm.mips.adduh.r.qb
+
+ i32_a = 0x12345678;
+ i32_b = 0x87654321;
+ i32_r = __builtin_mips_append(i32_a, i32_b, 16);
+// CHECK: call i32 @llvm.mips.append
+ i32_a = 0x12345678;
+ i32_b = 0x87654321;
+ i32_r = __builtin_mips_balign(i32_a, i32_b, 3);
+// CHECK: call i32 @llvm.mips.balign
+
+ v4i8_a = (v4i8) {0x11, 0x22, 0x33, 0x44};
+ v4i8_b = (v4i8) {0x11, 0x33, 0x33, 0x44};
+ i32_r = __builtin_mips_cmpgdu_eq_qb(v4i8_a, v4i8_b);
+// CHECK: call i32 @llvm.mips.cmpgdu.eq.qb
+ v4i8_a = (v4i8) {0x11, 0x22, 0x33, 0x44};
+ v4i8_b = (v4i8) {0x11, 0x33, 0x33, 0x44};
+ i32_r = __builtin_mips_cmpgdu_lt_qb(v4i8_a, v4i8_b);
+// CHECK: call i32 @llvm.mips.cmpgdu.lt.qb
+ v4i8_a = (v4i8) {0x11, 0x22, 0x33, 0x54};
+ v4i8_b = (v4i8) {0x11, 0x33, 0x33, 0x44};
+ i32_r = __builtin_mips_cmpgdu_le_qb(v4i8_a, v4i8_b);
+// CHECK: call i32 @llvm.mips.cmpgdu.le.qb
+
+ a64_a = 0x12345678;
+ v2i16_b = (v2i16) {0xffff, 0x1555};
+ v2i16_c = (v2i16) {0x1234, 0x3322};
+ a64_r = __builtin_mips_dpa_w_ph(a64_a, v2i16_b, v2i16_c);
+// CHECK: call i64 @llvm.mips.dpa.w.ph
+ a64_a = 0x12345678;
+ v2i16_b = (v2i16) {0xffff, 0x1555};
+ v2i16_c = (v2i16) {0x1234, 0x3322};
+ a64_r = __builtin_mips_dps_w_ph(a64_a, v2i16_b, v2i16_c);
+// CHECK: call i64 @llvm.mips.dps.w.ph
+
+ a64_a = 0x70000000;
+ v2q15_b = (v2q15) {0x4000, 0x2000};
+ v2q15_c = (v2q15) {0x2000, 0x4000};
+ a64_r = __builtin_mips_dpaqx_s_w_ph(a64_a, v2q15_b, v2q15_c);
+// CHECK: call i64 @llvm.mips.dpaqx.s.w.ph
+ a64_a = 0x70000000;
+ v2q15_b = (v2q15) {0x4000, 0x2000};
+ v2q15_c = (v2q15) {0x2000, 0x4000};
+ a64_r = __builtin_mips_dpaqx_sa_w_ph(a64_a, v2q15_b, v2q15_c);
+// CHECK: call i64 @llvm.mips.dpaqx.sa.w.ph
+ a64_a = 0x1111222212345678LL;
+ v2i16_b = (v2i16) {0x1, 0x2};
+ v2i16_c = (v2i16) {0x3, 0x4};
+ a64_r = __builtin_mips_dpax_w_ph(a64_a, v2i16_b, v2i16_c);
+// CHECK: call i64 @llvm.mips.dpax.w.ph
+ a64_a = 0x9999111112345678LL;
+ v2i16_b = (v2i16) {0x1, 0x2};
+ v2i16_c = (v2i16) {0x3, 0x4};
+ a64_r = __builtin_mips_dpsx_w_ph(a64_a, v2i16_b, v2i16_c);
+// CHECK: call i64 @llvm.mips.dpsx.w.ph
+ a64_a = 0x70000000;
+ v2q15_b = (v2q15) {0x4000, 0x2000};
+ v2q15_c = (v2q15) {0x2000, 0x4000};
+ a64_r = __builtin_mips_dpsqx_s_w_ph(a64_a, v2q15_b, v2q15_c);
+// CHECK: call i64 @llvm.mips.dpsqx.s.w.ph
+ a64_a = 0xFFFFFFFF80000000LL;
+ v2q15_b = (v2q15) {0x4000, 0x2000};
+ v2q15_c = (v2q15) {0x2000, 0x4000};
+ a64_r = __builtin_mips_dpsqx_sa_w_ph(a64_a, v2q15_b, v2q15_c);
+// CHECK: call i64 @llvm.mips.dpsqx.sa.w.ph
+
+ v2i16_a = (v2i16) {0xffff, 0x2468};
+ v2i16_b = (v2i16) {0x1234, 0x1111};
+ v2i16_r = __builtin_mips_mul_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.mul.ph
+ v2i16_a = (v2i16) {0x8000, 0x7fff};
+ v2i16_b = (v2i16) {0x1234, 0x1111};
+ v2i16_r = __builtin_mips_mul_s_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.mul.s.ph
+
+ q31_a = 0x80000000;
+ q31_b = 0x80000000;
+ q31_r = __builtin_mips_mulq_rs_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.mulq.rs.w
+ v2q15_a = (v2q15) {0xffff, 0x8000};
+ v2q15_b = (v2q15) {0x1111, 0x8000};
+ v2q15_r = __builtin_mips_mulq_s_ph(v2q15_a, v2q15_b);
+// CHECK: call <2 x i16> @llvm.mips.mulq.s.ph
+ q31_a = 0x00000002;
+ q31_b = 0x80000000;
+ q31_r = __builtin_mips_mulq_s_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.mulq.s.w
+ a64_a = 0x19848419;
+ v2i16_b = (v2i16) {0xffff, 0x8000};
+ v2i16_c = (v2i16) {0x1111, 0x8000};
+ a64_r = __builtin_mips_mulsa_w_ph(a64_a, v2i16_b, v2i16_c);
+// CHECK: call i64 @llvm.mips.mulsa.w.ph
+
+ v2i16_a = (v2i16) {0x1234, 0x5678};
+ v2i16_b = (v2i16) {0x2233, 0x5566};
+ v4i8_r = __builtin_mips_precr_qb_ph(v2i16_a, v2i16_b);
+// CHECK: call <4 x i8> @llvm.mips.precr.qb.ph
+ i32_a = 0x12345678;
+ i32_b = 0x33334444;
+ v2i16_r = __builtin_mips_precr_sra_ph_w(i32_a, i32_b, 4);
+// CHECK: call <2 x i16> @llvm.mips.precr.sra.ph.w
+ i32_a = 0x12345678;
+ i32_b = 0x33334444;
+ v2i16_r = __builtin_mips_precr_sra_r_ph_w(i32_a, i32_b, 4);
+// CHECK: call <2 x i16> @llvm.mips.precr.sra.r.ph.w
+
+ i32_a = 0x12345678;
+ i32_b = 0x87654321;
+ i32_r = __builtin_mips_prepend(i32_a, i32_b, 16);
+// CHECK: call i32 @llvm.mips.prepend
+
+ v4i8_a = (v4i8) {0x12, 0x45, 0x77, 0x99};
+ v4i8_r = __builtin_mips_shra_qb(v4i8_a, 1);
+// CHECK: call <4 x i8> @llvm.mips.shra.qb
+ v4i8_a = (v4i8) {0x12, 0x45, 0x77, 0x99};
+ i32_b = 1;
+ v4i8_r = __builtin_mips_shra_qb(v4i8_a, i32_b);
+// CHECK: call <4 x i8> @llvm.mips.shra.qb
+ v4i8_a = (v4i8) {0x12, 0x45, 0x77, 0x99};
+ v4i8_r = __builtin_mips_shra_r_qb(v4i8_a, 1);
+// CHECK: call <4 x i8> @llvm.mips.shra.r.qb
+ v4i8_a = (v4i8) {0x12, 0x45, 0x77, 0x99};
+ i32_b = 1;
+ v4i8_r = __builtin_mips_shra_r_qb(v4i8_a, i32_b);
+// CHECK: call <4 x i8> @llvm.mips.shra.r.qb
+ v2i16_a = (v2i16) {0x1357, 0x2468};
+ v2i16_r = __builtin_mips_shrl_ph(v2i16_a, 4);
+// CHECK: call <2 x i16> @llvm.mips.shrl.ph
+ v2i16_a = (v2i16) {0x1357, 0x2468};
+ i32_b = 8;
+ v2i16_r = __builtin_mips_shrl_ph (v2i16_a, i32_b);
+// CHECK: call <2 x i16> @llvm.mips.shrl.ph
+
+ v2q15_a = (v2q15) {0x3334, 0x4444};
+ v2q15_b = (v2q15) {0x1111, 0x2222};
+ v2q15_r = __builtin_mips_subqh_ph(v2q15_a, v2q15_b);
+// CHECK: call <2 x i16> @llvm.mips.subqh.ph
+ v2q15_a = (v2q15) {0x3334, 0x4444};
+ v2q15_b = (v2q15) {0x1111, 0x2222};
+ v2q15_r = __builtin_mips_subqh_r_ph(v2q15_a, v2q15_b);
+// CHECK: call <2 x i16> @llvm.mips.subqh.r.ph
+ q31_a = 0x11111112;
+ q31_b = 0x99999999;
+ q31_r = __builtin_mips_subqh_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.subqh.w
+ q31_a = 0x11111112;
+ q31_b = 0x99999999;
+ q31_r = __builtin_mips_subqh_r_w(q31_a, q31_b);
+// CHECK: call i32 @llvm.mips.subqh.r.w
+
+ v2i16_a = (v2i16) {0x1357, 0x4455};
+ v2i16_b = (v2i16) {0x3333, 0x4444};
+ v2i16_r = __builtin_mips_subu_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.subu.ph
+ v2i16_a = (v2i16) {0x1357, 0x4455};
+ v2i16_b = (v2i16) {0x3333, 0x4444};
+ v2i16_r = __builtin_mips_subu_s_ph(v2i16_a, v2i16_b);
+// CHECK: call <2 x i16> @llvm.mips.subu.s.ph
+
+ v4i8_a = (v4i8) {0x33 ,0x44, 0x55, 0x66};
+ v4i8_b = (v4i8) {0x99 ,0x15, 0x85, 0xff};
+ v4i8_r = __builtin_mips_subuh_qb(v4i8_a, v4i8_b);
+// CHECK: call <4 x i8> @llvm.mips.subuh.qb
+ v4i8_a = (v4i8) {0x33 ,0x44, 0x55, 0x66};
+ v4i8_b = (v4i8) {0x99 ,0x15, 0x85, 0xff};
+ v4i8_r = __builtin_mips_subuh_r_qb(v4i8_a, v4i8_b);
+// CHECK: call <4 x i8> @llvm.mips.subuh.r.qb
}
diff --git a/test/CodeGen/builtins-nvptx.c b/test/CodeGen/builtins-nvptx.c
index fa6b14c1ca7d..2c7e0c136769 100644
--- a/test/CodeGen/builtins-nvptx.c
+++ b/test/CodeGen/builtins-nvptx.c
@@ -1,8 +1,15 @@
-// RUN: %clang_cc1 -triple nvptx-unknown-unknown -emit-llvm -o %t %s
-// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -emit-llvm -o %t %s
+// REQUIRES: nvptx-registered-target
+// REQUIRES: nvptx64-registered-target
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
int read_tid() {
+// CHECK: call i32 @llvm.ptx.read.tid.x()
+// CHECK: call i32 @llvm.ptx.read.tid.y()
+// CHECK: call i32 @llvm.ptx.read.tid.z()
+// CHECK: call i32 @llvm.ptx.read.tid.w()
+
int x = __builtin_ptx_read_tid_x();
int y = __builtin_ptx_read_tid_y();
int z = __builtin_ptx_read_tid_z();
@@ -14,6 +21,11 @@ int read_tid() {
int read_ntid() {
+// CHECK: call i32 @llvm.ptx.read.ntid.x()
+// CHECK: call i32 @llvm.ptx.read.ntid.y()
+// CHECK: call i32 @llvm.ptx.read.ntid.z()
+// CHECK: call i32 @llvm.ptx.read.ntid.w()
+
int x = __builtin_ptx_read_ntid_x();
int y = __builtin_ptx_read_ntid_y();
int z = __builtin_ptx_read_ntid_z();
@@ -25,6 +37,11 @@ int read_ntid() {
int read_ctaid() {
+// CHECK: call i32 @llvm.ptx.read.ctaid.x()
+// CHECK: call i32 @llvm.ptx.read.ctaid.y()
+// CHECK: call i32 @llvm.ptx.read.ctaid.z()
+// CHECK: call i32 @llvm.ptx.read.ctaid.w()
+
int x = __builtin_ptx_read_ctaid_x();
int y = __builtin_ptx_read_ctaid_y();
int z = __builtin_ptx_read_ctaid_z();
@@ -36,6 +53,11 @@ int read_ctaid() {
int read_nctaid() {
+// CHECK: call i32 @llvm.ptx.read.nctaid.x()
+// CHECK: call i32 @llvm.ptx.read.nctaid.y()
+// CHECK: call i32 @llvm.ptx.read.nctaid.z()
+// CHECK: call i32 @llvm.ptx.read.nctaid.w()
+
int x = __builtin_ptx_read_nctaid_x();
int y = __builtin_ptx_read_nctaid_y();
int z = __builtin_ptx_read_nctaid_z();
@@ -47,6 +69,13 @@ int read_nctaid() {
int read_ids() {
+// CHECK: call i32 @llvm.ptx.read.laneid()
+// CHECK: call i32 @llvm.ptx.read.warpid()
+// CHECK: call i32 @llvm.ptx.read.nwarpid()
+// CHECK: call i32 @llvm.ptx.read.smid()
+// CHECK: call i32 @llvm.ptx.read.nsmid()
+// CHECK: call i32 @llvm.ptx.read.gridid()
+
int a = __builtin_ptx_read_laneid();
int b = __builtin_ptx_read_warpid();
int c = __builtin_ptx_read_nwarpid();
@@ -60,6 +89,12 @@ int read_ids() {
int read_lanemasks() {
+// CHECK: call i32 @llvm.ptx.read.lanemask.eq()
+// CHECK: call i32 @llvm.ptx.read.lanemask.le()
+// CHECK: call i32 @llvm.ptx.read.lanemask.lt()
+// CHECK: call i32 @llvm.ptx.read.lanemask.ge()
+// CHECK: call i32 @llvm.ptx.read.lanemask.gt()
+
int a = __builtin_ptx_read_lanemask_eq();
int b = __builtin_ptx_read_lanemask_le();
int c = __builtin_ptx_read_lanemask_lt();
@@ -73,6 +108,9 @@ int read_lanemasks() {
long read_clocks() {
+// CHECK: call i32 @llvm.ptx.read.clock()
+// CHECK: call i64 @llvm.ptx.read.clock64()
+
int a = __builtin_ptx_read_clock();
long b = __builtin_ptx_read_clock64();
@@ -82,6 +120,11 @@ long read_clocks() {
int read_pms() {
+// CHECK: call i32 @llvm.ptx.read.pm0()
+// CHECK: call i32 @llvm.ptx.read.pm1()
+// CHECK: call i32 @llvm.ptx.read.pm2()
+// CHECK: call i32 @llvm.ptx.read.pm3()
+
int a = __builtin_ptx_read_pm0();
int b = __builtin_ptx_read_pm1();
int c = __builtin_ptx_read_pm2();
@@ -93,6 +136,33 @@ int read_pms() {
void sync() {
+// CHECK: call void @llvm.ptx.bar.sync(i32 0)
+
__builtin_ptx_bar_sync(0);
}
+
+
+// NVVM intrinsics
+
+// The idea is not to test all intrinsics, just that Clang is recognizing the
+// builtins defined in BuiltinsNVPTX.def
+void nvvm_math(float f1, float f2, double d1, double d2) {
+// CHECK: call float @llvm.nvvm.fmax.f
+ float t1 = __nvvm_fmax_f(f1, f2);
+// CHECK: call float @llvm.nvvm.fmin.f
+ float t2 = __nvvm_fmin_f(f1, f2);
+// CHECK: call float @llvm.nvvm.sqrt.rn.f
+ float t3 = __nvvm_sqrt_rn_f(f1);
+// CHECK: call float @llvm.nvvm.rcp.rn.f
+ float t4 = __nvvm_rcp_rn_f(f2);
+
+// CHECK: call double @llvm.nvvm.fmax.d
+ double td1 = __nvvm_fmax_d(d1, d2);
+// CHECK: call double @llvm.nvvm.fmin.d
+ double td2 = __nvvm_fmin_d(d1, d2);
+// CHECK: call double @llvm.nvvm.sqrt.rn.d
+ double td3 = __nvvm_sqrt_rn_d(d1);
+// CHECK: call double @llvm.nvvm.rcp.rn.d
+ double td4 = __nvvm_rcp_rn_d(d2);
+}
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index 65b9ad111fd8..9ba12bbf2fec 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -113,6 +113,7 @@ int main() {
// Whatever
+ P(bswap16, (N));
P(bswap32, (N));
P(bswap64, (N));
// FIXME
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index ee0b6586dd84..4198b62ea56c 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -1,17 +1,248 @@
-// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,divide-by-zero -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -fsanitize=null -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-NULL
+// RUN: %clang_cc1 -fsanitize=signed-integer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-OVERFLOW
+
+// CHECK: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
+
+// FIXME: When we only emit each type once, use [[INT]] more below.
+// CHECK: @[[LINE_100:.*]] = private unnamed_addr constant {{.*}}, i32 100, i32 5 {{.*}} @[[INT]], i64 4, i8 1
+// CHECK: @[[LINE_200:.*]] = {{.*}}, i32 200, i32 10 {{.*}}, i64 4, i8 0
+// CHECK: @[[LINE_300_A:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_300_B:.*]] = {{.*}}, i32 300, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_400:.*]] = {{.*}}, i32 400, i32 12 {{.*}} @{{.*}}, {{.*}} @{{.*}}
+// CHECK: @[[LINE_500:.*]] = {{.*}}, i32 500, i32 10 {{.*}} @{{.*}}, i64 4, i8 0 }
+// CHECK: @[[LINE_600:.*]] = {{.*}}, i32 600, i32 3 {{.*}} @{{.*}}, i64 4, i8 1 }
+
+// CHECK: @[[STRUCT_S:.*]] = private unnamed_addr constant { i16, i16, [11 x i8] } { i16 -1, i16 0, [11 x i8] c"'struct S'\00" }
+
+// CHECK: @[[LINE_700:.*]] = {{.*}}, i32 700, i32 14 {{.*}} @[[STRUCT_S]], i64 4, i8 3 }
+// CHECK: @[[LINE_800:.*]] = {{.*}}, i32 800, i32 12 {{.*}} @{{.*}} }
+// CHECK: @[[LINE_900:.*]] = {{.*}}, i32 900, i32 11 {{.*}} @{{.*}} }
+
+// CHECK-NULL: @[[LINE_100:.*]] = private unnamed_addr constant {{.*}}, i32 100, i32 5 {{.*}}
// PR6805
// CHECK: @foo
+// CHECK-NULL: @foo
void foo() {
union { int i; } u;
- // CHECK: objectsize
- // CHECK: icmp uge
+ // CHECK: %[[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: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+ // CHECK-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+
+ // CHECK: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
+ // CHECK-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
+ // CHECK-NEXT: br i1 %[[OK]]
+
+ // CHECK: %[[ARG:.*]] = ptrtoint {{.*}} %[[PTR]] to i64
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %[[ARG]]) noreturn nounwind
+
+ // With -fsanitize=null, only perform the null check.
+ // CHECK-NULL: %[[NULL:.*]] = icmp ne {{.*}}, null
+ // CHECK-NULL: br i1 %[[NULL]]
+ // CHECK-NULL: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 100
u.i=1;
}
// CHECK: @bar
int bar(int *a) {
- // CHECK: objectsize
- // CHECK: icmp uge
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+
+ // CHECK: %[[ARG:.*]] = ptrtoint
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]]) noreturn nounwind
+#line 200
+ return *a;
+}
+
+// CHECK: @addr_space
+int addr_space(int __attribute__((address_space(256))) *a) {
+ // CHECK-NOT: __ubsan
return *a;
}
+
+// CHECK: @lsh_overflow
+int lsh_overflow(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-NEXT: br i1 %[[INBOUNDS]]
+
+ // FIXME: Only emit one trap block here.
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300_A]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+
+ // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+ // CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
+ // CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
+
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300_B]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+
+ // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+#line 300
+ return a << b;
+}
+
+// CHECK: @rsh_inbounds
+int rsh_inbounds(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
+ // CHECK: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_400]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+
+ // CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+#line 400
+ return a >> b;
+}
+
+// CHECK: @load
+int load(int *p) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 500
+ return *p;
+}
+
+// CHECK: @store
+void store(int *p, int q) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 600
+ *p = q;
+}
+
+struct S { int k; };
+
+// CHECK: @member_access
+int *member_access(struct S *p) {
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}}) noreturn nounwind
+#line 700
+ return &p->k;
+}
+
+// CHECK: @signed_overflow
+int signed_overflow(int a, int b) {
+ // CHECK: %[[ARG1:.*]] = zext
+ // CHECK-NEXT: %[[ARG2:.*]] = zext
+ // CHECK-NEXT: call void @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_800]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]]) noreturn nounwind
+#line 800
+ return a + b;
+}
+
+// CHECK: @no_return
+int no_return() {
+ // Reaching the end of a noreturn function is fine in C.
+ // FIXME: If the user explicitly requests -fsanitize=return, we should catch
+ // that here even though it's not undefined behavior.
+ // CHECK-NOT: call
+ // CHECK-NOT: unreachable
+ // CHECK: ret i32
+}
+
+// CHECK: @vla_bound
+void vla_bound(int n) {
+ // CHECK: icmp sgt i32 %[[PARAM:.*]], 0
+ //
+ // CHECK: %[[ARG:.*]] = zext i32 %[[PARAM]] to i64
+ // CHECK-NEXT: call void @__ubsan_handle_vla_bound_not_positive(i8* bitcast ({{.*}} @[[LINE_900]] to i8*), i64 %[[ARG]]) noreturn nounwind
+#line 900
+ int arr[n * 3];
+}
+
+// CHECK: @int_float_no_overflow
+float int_float_no_overflow(__int128 n) {
+ // CHECK-NOT: call void @__ubsan_handle
+ return n;
+}
+
+// CHECK: @int_float_overflow
+float int_float_overflow(unsigned __int128 n) {
+ // This is 2**104. FLT_MAX is 2**128 - 2**104.
+ // CHECK: icmp ule i128 %{{.*}}, -20282409603651670423947251286016
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ return n;
+}
+
+// CHECK: @int_fp16_overflow
+void int_fp16_overflow(int n, __fp16 *p) {
+ // CHECK: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
+ // CHECK: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
+ // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ *p = n;
+}
+
+// CHECK: @float_int_overflow
+int float_int_overflow(float f) {
+ // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0xC1E0000000000000
+ // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41DFFFFFE0000000
+ // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ return f;
+}
+
+// CHECK: @float_uint_overflow
+unsigned float_uint_overflow(float f) {
+ // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0.{{0*}}e+00
+ // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41EFFFFFE0000000
+ // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ return f;
+}
+
+// CHECK: @fp16_char_overflow
+signed char fp16_char_overflow(__fp16 *p) {
+ // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], -1.28{{0*}}e+02
+ // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 1.27{{0*}}e+02
+ // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ return *p;
+}
+
+// CHECK: @float_float_overflow
+float float_float_overflow(double f) {
+ // CHECK: %[[GE:.*]] = fcmp oge double %[[F:.*]], 0xC7EFFFFFE0000000
+ // CHECK: %[[LE:.*]] = fcmp ole double %[[F]], 0x47EFFFFFE0000000
+ // CHECK: and i1 %[[GE]], %[[LE]]
+ // CHECK: call void @__ubsan_handle_float_cast_overflow(
+ return f;
+}
+
+// CHECK: @int_divide_overflow
+// CHECK-OVERFLOW: @int_divide_overflow
+int int_divide_overflow(int a, int b) {
+ // CHECK: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
+ // CHECK-OVERFLOW-NOT: icmp ne i32 %{{.*}}, 0
+
+ // CHECK: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
+ // CHECK-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
+ // CHECK-NEXT: %[[OVER:.*]] = or i1 %[[AOK]], %[[BOK]]
+
+ // CHECK-OVERFLOW: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
+ // CHECK-OVERFLOW-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B:.*]], -1
+ // CHECK-OVERFLOW-NEXT: %[[OK:.*]] = or i1 %[[AOK]], %[[BOK]]
+
+ // CHECK: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
+
+ // CHECK: br i1 %[[OK]]
+ // CHECK-OVERFLOW: br i1 %[[OK]]
+ return a / b;
+
+ // CHECK: }
+ // CHECK-OVERFLOW: }
+}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 4f3f7ab55330..5f729b8df428 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -144,3 +144,18 @@ void g28() {
static v12i16 b = (v2f80){1,2};
static v2f80 c = (v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0};
}
+
+// PR13643
+void g29() {
+ typedef char DCC_PASSWD[2];
+ typedef struct
+ {
+ DCC_PASSWD passwd;
+ } DCC_SRVR_NM;
+ // CHECK: @g29.a = internal global %struct.DCC_SRVR_NM { [2 x i8] c"@\00" }, align 1
+ // 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 c[1] = { L"a" };
+}
diff --git a/test/CodeGen/const-label-addr.c b/test/CodeGen/const-label-addr.c
index 9d99f88c8a65..e606c3b2cda2 100644
--- a/test/CodeGen/const-label-addr.c
+++ b/test/CodeGen/const-label-addr.c
@@ -1,4 +1,17 @@
-// RUN: %clang_cc1 %s -emit-llvm -o %t
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// REQUIRES: asserts
+
+// CHECK: @a.a = internal global i8* blockaddress(@a, %A)
int a() {
A:;static void* a = &&A;
}
+
+// PR14005
+// CHECK: @b.ar = internal global {{.*}} sub (i{{..}} ptrtoint (i8* blockaddress(@b, %l2) to i{{..}}), i{{..}} ptrtoint (i8* blockaddress(@b, %l1) to i{{..}}))
+int b() {
+ static int ar = &&l2 - &&l1;
+l1:
+ return 10;
+l2:
+ return 11;
+}
diff --git a/test/CodeGen/debug-info-iv.c b/test/CodeGen/debug-info-iv.c
index 6684fe346992..aafd71d2ec2a 100644
--- a/test/CodeGen/debug-info-iv.c
+++ b/test/CodeGen/debug-info-iv.c
@@ -27,7 +27,7 @@ int main() {
Array[i][j] = 0;
test_indvars(Array[0], Array);
-//CHECK: .loc 2 31 8
+//CHECK: .loc 2 31
for (i=0; i < 100; i+=2)
for (j=0; j < 200; j++)
sum += Array[i][j];
diff --git a/test/CodeGen/debug-info-line3.c b/test/CodeGen/debug-info-line3.c
index a4e35e753d74..d01b023b82d3 100644
--- a/test/CodeGen/debug-info-line3.c
+++ b/test/CodeGen/debug-info-line3.c
@@ -12,5 +12,5 @@ void func(char c, char* d)
}
-// CHECK: ret void, !dbg !17
-// CHECK: !17 = metadata !{i32 6,
+// CHECK: ret void, !dbg [[LINE:.*]]
+// CHECK: [[LINE]] = metadata !{i32 6,
diff --git a/test/CodeGen/debug-info-line4.c b/test/CodeGen/debug-info-line4.c
new file mode 100644
index 000000000000..004176c7a507
--- /dev/null
+++ b/test/CodeGen/debug-info-line4.c
@@ -0,0 +1,11 @@
+// RUN: %clang %s -g -gcolumn-info -S -emit-llvm -o - | FileCheck %s
+// Checks that clang emits column information when -gcolumn-info is passed.
+
+int foo(int a, int b) { int c = a + b;
+
+
+ return c;
+}
+
+// Without column information we wouldn't change locations for b.
+// CHECK: metadata !{i32 4, i32 20,
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index af2ce969bceb..12ba6058d39e 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unk-unk -o %t -emit-llvm -g %s
-// RUN: FileCheck --input-file=%t %s
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -g %s | FileCheck %s
// PR3023
void convert(void) {
@@ -8,7 +7,7 @@ void convert(void) {
// PR2784
-struct OPAQUE;
+struct OPAQUE; // CHECK: DW_TAG_structure_type
typedef struct OPAQUE *PTR;
PTR p;
diff --git a/test/CodeGen/debug-line-1.c b/test/CodeGen/debug-line-1.c
index 0c2d18583298..be1da0820931 100644
--- a/test/CodeGen/debug-line-1.c
+++ b/test/CodeGen/debug-line-1.c
@@ -4,7 +4,7 @@
// Check to make sure that we emit the block for the break so that we can count the line.
// CHECK: sw.bb: ; preds = %entry
-// CHECK: br label %sw.epilog, !dbg !19
+// CHECK: br label %sw.epilog, !dbg !
extern int atoi(const char *);
diff --git a/test/CodeGen/decl-in-prototype.c b/test/CodeGen/decl-in-prototype.c
index 949793da445a..2c0fc4fc3b17 100644
--- a/test/CodeGen/decl-in-prototype.c
+++ b/test/CodeGen/decl-in-prototype.c
@@ -1,4 +1,4 @@
-// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -target i386-unknown-unknown -emit-llvm -S -o - %s | FileCheck %s
const int AA = 5;
diff --git a/test/CodeGen/dostmt.c b/test/CodeGen/dostmt.c
index 1a2e02a78e6b..54973dc99b6e 100644
--- a/test/CodeGen/dostmt.c
+++ b/test/CodeGen/dostmt.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o -
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
int bar();
int test0() {
@@ -66,5 +66,11 @@ void test5() {
do { break; } while(0);
}
-
+// PR14191
+void test6f(void);
+void test6() {
+ do {
+ } while (test6f(), 0);
+ // CHECK: call void @test6f()
+}
diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c
index cc03be6a922a..f8f28330ab77 100644
--- a/test/CodeGen/exprs.c
+++ b/test/CodeGen/exprs.c
@@ -174,3 +174,13 @@ void f16() {
lbl:
;
}
+
+// PR13704: negative increment in i128 is not preserved.
+// CHECK: define void @f17()
+void f17() {
+ extern void extfunc(__int128);
+ __int128 x = 2;
+ x--;
+ extfunc(x);
+// CHECK: add nsw i128 %{{.}}, -1
+}
diff --git a/test/CodeGen/extern-inline.c b/test/CodeGen/extern-inline.c
index e3df9968bfd2..77cb270191a0 100644
--- a/test/CodeGen/extern-inline.c
+++ b/test/CodeGen/extern-inline.c
@@ -1,5 +1,5 @@
-// RUN: %clang -S -emit-llvm -std=gnu89 -o - %s | FileCheck %s
-// RUN: %clang -S -emit-llvm -fgnu89-inline -o - %s | FileCheck %s
+// RUN: %clang -target i386-unknown-unknown -S -emit-llvm -std=gnu89 -o - %s | FileCheck %s
+// RUN: %clang -target i386-unknown-unknown -S -emit-llvm -fgnu89-inline -o - %s | FileCheck %s
// PR5253
// If an extern inline function is redefined, functions should call the
diff --git a/test/CodeGen/f16c-builtins.c b/test/CodeGen/f16c-builtins.c
new file mode 100644
index 000000000000..28430d52f661
--- /dev/null
+++ b/test/CodeGen/f16c-builtins.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +f16c -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+__m128 test_mm_cvtph_ps(__m128i a) {
+ // CHECK: @llvm.x86.vcvtph2ps.128
+ return _mm_cvtph_ps(a);
+}
+
+__m256 test_mm256_cvtph_ps(__m128i a) {
+ // CHECK: @llvm.x86.vcvtph2ps.256
+ return _mm256_cvtph_ps(a);
+}
+
+__m128i test_mm_cvtps_ph(__m128 a) {
+ // CHECK: @llvm.x86.vcvtps2ph.128
+ return _mm_cvtps_ph(a, 0);
+}
+
+__m128i test_mm256_cvtps_ph(__m256 a) {
+ // CHECK: @llvm.x86.vcvtps2ph.256
+ return _mm256_cvtps_ph(a, 0);
+}
diff --git a/test/CodeGen/fp-contract.c b/test/CodeGen/ffp-contract-option.c
index eb95f1e21775..eb95f1e21775 100644
--- a/test/CodeGen/fp-contract.c
+++ b/test/CodeGen/ffp-contract-option.c
diff --git a/test/CodeGen/fold-const-declref.c b/test/CodeGen/fold-const-declref.c
index 5a7ba8e26a77..f49611cda79a 100644
--- a/test/CodeGen/fold-const-declref.c
+++ b/test/CodeGen/fold-const-declref.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -verify -emit-llvm-only
+// RUN: %clang_cc1 -verify -emit-llvm-only %s
// PR7242: Check that this doesn't crash.
int main(void)
{
int __negative = 1;
const int __max = __negative && 0 ;
- __max / 0;
+ __max / 0; // expected-warning{{expression result unused}} expected-warning{{division by zero is undefined}}
}
diff --git a/test/CodeGen/fp-contract-pragma.cpp b/test/CodeGen/fp-contract-pragma.cpp
new file mode 100644
index 000000000000..afd8c43121e6
--- /dev/null
+++ b/test/CodeGen/fp-contract-pragma.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -O3 -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT is honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: tail call float @llvm.fmuladd
+ #pragma STDC FP_CONTRACT ON
+ return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+// CHECK: _Z13fp_contract_2fff
+// CHECK: %[[M:.+]] = fmul float %a, %b
+// CHECK-NEXT: fadd float %[[M]], %c
+ {
+ #pragma STDC FP_CONTRACT ON
+ }
+ return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instatiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+ #pragma STDC FP_CONTRACT ON
+ return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+// CHECK: _Z13fp_contract_3fff
+// CHECK: tail call float @llvm.fmuladd
+ return template_muladd<float>(a, b, c);
+}
+
+template<typename T> class fp_contract_4 {
+ float method(float a, float b, float c) {
+ #pragma STDC FP_CONTRACT ON
+ return a * b + c;
+ }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: tail call float @llvm.fmuladd
+
+// Check file-scoped FP_CONTRACT
+#pragma STDC FP_CONTRACT ON
+float fp_contract_5(float a, float b, float c) {
+// CHECK: _Z13fp_contract_5fff
+// CHECK: tail call float @llvm.fmuladd
+ return a * b + c;
+}
+
+#pragma STDC FP_CONTRACT OFF
+float fp_contract_6(float a, float b, float c) {
+// CHECK: _Z13fp_contract_6fff
+// CHECK: %[[M:.+]] = fmul float %a, %b
+// CHECK-NEXT: fadd float %[[M]], %c
+ return a * b + c;
+}
+
diff --git a/test/CodeGen/func-ptr-cast-decl.c b/test/CodeGen/func-ptr-cast-decl.c
index e6307964294a..28364dec9aae 100644
--- a/test/CodeGen/func-ptr-cast-decl.c
+++ b/test/CodeGen/func-ptr-cast-decl.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only %s -verify
+// expected-no-diagnostics
// PR5882
int q_sk_num(void *a);
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index 426233d8dfd3..259d34d5951c 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -69,6 +69,8 @@ char test8(int X) {
// CHECK: store i8 97
// CHECK: store i8 98
// CHECK: store i8 99
+// CHECK-NOT: getelementptr
+// CHECK: load
}
void bar(void*);
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 2a01f255dc01..addb30bde42a 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -1,5 +1,5 @@
// RUN: echo "GNU89 tests:"
-// RUN: %clang %s -O1 -emit-llvm -S -o %t -std=gnu89
+// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o %t -std=gnu89
// RUN: grep "define available_externally i32 @ei()" %t
// RUN: grep "define i32 @foo()" %t
// RUN: grep "define i32 @bar()" %t
@@ -21,7 +21,7 @@
// RUN: grep "define void @testC" %t
// RUN: echo "C99 tests:"
-// RUN: %clang %s -O1 -emit-llvm -S -o %t -std=gnu99
+// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o %t -std=gnu99
// RUN: grep "define i32 @ei()" %t
// RUN: grep "define available_externally i32 @foo()" %t
// RUN: grep "define i32 @bar()" %t
@@ -43,7 +43,7 @@
// RUN: grep "define void @testC" %t
// RUN: echo "C++ tests:"
-// RUN: %clang -x c++ %s -O1 -emit-llvm -S -o %t -std=c++98
+// RUN: %clang -x c++ %s -target i386-unknown-unknown -O1 -emit-llvm -S -o %t -std=c++98
// RUN: grep "define linkonce_odr i32 @_Z2eiv()" %t
// RUN: grep "define linkonce_odr i32 @_Z3foov()" %t
// RUN: grep "define i32 @_Z3barv()" %t
diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c
index d7fff4ee4a2a..ed2dede7814c 100644
--- a/test/CodeGen/integer-overflow.c
+++ b/test/CodeGen/integer-overflow.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CATCH_UB
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER
@@ -15,24 +16,28 @@ void test1() {
// DEFAULT: add nsw i32
// WRAPV: add i32
// TRAPV: llvm.sadd.with.overflow.i32
+ // CATCH_UB: llvm.sadd.with.overflow.i32
// TRAPV_HANDLER: foo(
f11G = a + b;
// DEFAULT: sub nsw i32
// WRAPV: sub i32
// TRAPV: llvm.ssub.with.overflow.i32
+ // CATCH_UB: llvm.ssub.with.overflow.i32
// TRAPV_HANDLER: foo(
f11G = a - b;
// DEFAULT: mul nsw i32
// WRAPV: mul i32
// TRAPV: llvm.smul.with.overflow.i32
+ // CATCH_UB: llvm.smul.with.overflow.i32
// TRAPV_HANDLER: foo(
f11G = a * b;
// DEFAULT: sub nsw i32 0,
// WRAPV: sub i32 0,
// TRAPV: llvm.ssub.with.overflow.i32(i32 0
+ // CATCH_UB: llvm.ssub.with.overflow.i32(i32 0
// TRAPV_HANDLER: foo(
f11G = -a;
@@ -41,12 +46,14 @@ void test1() {
// DEFAULT: add nsw i32 {{.*}}, 1
// WRAPV: add i32 {{.*}}, 1
// TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 1)
+ // CATCH_UB: llvm.sadd.with.overflow.i32({{.*}}, i32 1)
// TRAPV_HANDLER: foo(
++a;
// DEFAULT: add nsw i32 {{.*}}, -1
// WRAPV: add i32 {{.*}}, -1
// TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 -1)
+ // CATCH_UB: llvm.sadd.with.overflow.i32({{.*}}, i32 -1)
// TRAPV_HANDLER: foo(
--a;
@@ -56,11 +63,13 @@ void test1() {
// DEFAULT: getelementptr inbounds i32*
// WRAPV: getelementptr i32*
// TRAPV: getelementptr inbounds i32*
+ // CATCH_UB: getelementptr inbounds i32*
// PR9350: char increment never overflows.
extern volatile signed char PR9350;
// DEFAULT: add i8 {{.*}}, 1
// WRAPV: add i8 {{.*}}, 1
// TRAPV: add i8 {{.*}}, 1
+ // CATCH_UB: add i8 {{.*}}, 1
++PR9350;
}
diff --git a/test/CodeGen/le32-arguments.c b/test/CodeGen/le32-arguments.c
new file mode 100644
index 000000000000..2cbbc0fbea45
--- /dev/null
+++ b/test/CodeGen/le32-arguments.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple le32-unknown-nacl %s -emit-llvm -o - | FileCheck %s
+
+// Basic argument/attribute tests for le32/PNaCl
+
+// CHECK: define void @f0(i32 %i, i32 %j, double %k)
+void f0(int i, long j, double k) {}
+
+typedef struct {
+ int aa;
+ int bb;
+} s1;
+// Structs should be passed byval and not split up
+// CHECK: 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)
+s2 f2() {
+ s2 foo;
+ return foo;
+}
+
+// CHECK: 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)
+void f4(char a, short b) {}
+
+// CHECK: define void @f5(i8 zeroext %a, i16 zeroext %b)
+void f5(unsigned char a, unsigned short b) {}
+
+
+enum my_enum {
+ ENUM1,
+ ENUM2,
+ ENUM3,
+};
+// Enums should be treated as the underlying i32
+// CHECK: define void @f6(i32 %a)
+void f6(enum my_enum a) {}
+
+union simple_union {
+ int a;
+ char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f7(%union.simple_union* byval %s)
+void f7(union simple_union s) {}
+
+typedef struct {
+ int b4 : 4;
+ int b3 : 3;
+ int b8 : 8;
+} bitfield1;
+// Bitfields should be passed as byval structs
+// CHECK: define void @f8(%struct.bitfield1* byval %bf1)
+void f8(bitfield1 bf1) {}
diff --git a/test/CodeGen/le32-regparm.c b/test/CodeGen/le32-regparm.c
new file mode 100644
index 000000000000..6ab5a11106b1
--- /dev/null
+++ b/test/CodeGen/le32-regparm.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple le32-unknown-nacl %s -emit-llvm -o - | FileCheck %s
+
+#define FASTCALL __attribute__((regparm(2)))
+
+typedef struct {
+ int aaa;
+ double bbbb;
+ int ccc[200];
+} foo;
+
+// 2 inreg arguments are supported.
+void FASTCALL f1(int i, int j, int k);
+// CHECK: define void @f1(i32 inreg %i, i32 inreg %j, i32 %k)
+void f1(int i, int j, int k) { }
+
+// inreg structs are not supported.
+// CHECK: define void @f2(%struct.foo* inreg %a)
+void __attribute__((regparm(1))) f2(foo* a) {}
+
+// Only the first 2 arguments can be passed inreg, and the first
+// non-integral type consumes remaining available registers.
+// CHECK: define void @f3(%struct.foo* byval %a, i32 %b)
+void __attribute__((regparm(2))) f3(foo a, int b) {}
+
+// Only 64 total bits are supported
+// CHECK: define void @f4(i64 inreg %g, i32 %h)
+void __attribute__((regparm(2))) f4(long long g, int h) {}
+
+typedef void (*FType)(int, int) __attribute ((regparm (2)));
+FType bar;
+extern void FASTCALL reduced(char b, double c, foo* d, double e, int f);
+
+int
+main(void) {
+ // The presence of double c means that foo* d is not passed inreg. This
+ // behavior is different from current x86-32 behavior
+ // CHECK: call void @reduced(i8 signext inreg 0, {{.*}} %struct.foo* null
+ reduced(0, 0.0, 0, 0.0, 0);
+ // CHECK: call void {{.*}}(i32 inreg 1, i32 inreg 2)
+ bar(1,2);
+}
diff --git a/test/CodeGen/libcall-declarations.c b/test/CodeGen/libcall-declarations.c
new file mode 100644
index 000000000000..4517643e4c4e
--- /dev/null
+++ b/test/CodeGen/libcall-declarations.c
@@ -0,0 +1,191 @@
+// 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
+
+// Prototypes.
+double acos(double);
+long double acosl(long double);
+float acosf(float);
+double asin(double);
+long double asinl(long double);
+float asinf(float);
+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);
+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);
+double cos(double);
+long double cosl(long double);
+float cosf(float);
+double exp(double);
+long double expl(long double);
+float expf(float);
+double exp2(double);
+long double exp2l(long double);
+float exp2f(float);
+double fabs(double);
+long double fabsl(long double);
+float fabsf(float);
+double floor(double);
+long double floorl(long double);
+float floorf(float);
+double fma(double, double, double);
+long double fmal(long double, long double, long double);
+float fmaf(float, float, float);
+double fmax(double, double);
+long double fmaxl(long double, long double);
+float fmaxf(float, float);
+double fmin(double, double);
+long double fminl(long double, long double);
+float fminf(float, float);
+double log(double);
+long double logl(long double);
+float logf(float);
+double log2(double);
+long double log2l(long double);
+float log2f(float);
+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);
+double rint(double);
+long double rintl(long double);
+float rintf(float);
+double round(double);
+long double roundl(long double);
+float roundf(float);
+double sin(double);
+long double sinl(long double);
+float sinf(float);
+double sqrt(double);
+long double sqrtl(long double);
+float sqrtf(float);
+double tan(double);
+long double tanl(long double);
+float tanf(float);
+double trunc(double);
+long double truncl(long double);
+float truncf(float);
+
+// Force emission of the declare statements.
+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
+};
+
+// CHECK-NOERRNO: declare double @acos(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @acosl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @acosf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @asin(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @asinl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @asinf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @atan(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @atanl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @atanf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @atan2(double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @atan2f(float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @ceil(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @ceill(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @ceilf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @copysign(double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @copysignf(float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @cos(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @cosl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @cosf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @exp(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @expl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @expf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @exp2(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @exp2l(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @exp2f(float) nounwind readnone
+// CHECK-NOERRNO: declare double @fabs(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @fabsl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @fabsf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @floor(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @floorl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @floorf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @fma(double, double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @fmaf(float, float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @fmax(double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @fmaxf(float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @fmin(double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @fminf(float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @log(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @logl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @logf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @log2(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @log2l(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @log2f(float) nounwind readnone
+// CHECK-NOERRNO: declare double @nearbyint(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @nearbyintl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @nearbyintf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @pow(double, double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @powl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @powf(float, float) nounwind readnone
+// CHECK-NOERRNO: declare double @rint(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @rintl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @rintf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @round(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @roundl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @roundf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @sin(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @sinl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @sinf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @sqrt(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @sqrtl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @sqrtf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @tan(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @tanl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @tanf(float) nounwind readnone
+// CHECK-NOERRNO: declare double @trunc(double) nounwind readnone
+// CHECK-NOERRNO: declare x86_fp80 @truncl(x86_fp80) nounwind readnone
+// CHECK-NOERRNO: declare float @truncf(float) nounwind readnone
+
+// CHECK-ERRNO: declare double @ceil(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @ceill(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @ceilf(float) nounwind readnone
+// CHECK-ERRNO: declare double @copysign(double, double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @copysignf(float, float) nounwind readnone
+// CHECK-ERRNO: declare double @fabs(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @fabsl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @fabsf(float) nounwind readnone
+// CHECK-ERRNO: declare double @floor(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @floorl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @floorf(float) nounwind readnone
+// CHECK-ERRNO: declare double @fmax(double, double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @fmaxf(float, float) nounwind readnone
+// CHECK-ERRNO: declare double @fmin(double, double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @fminf(float, float) nounwind readnone
+// CHECK-ERRNO: declare double @nearbyint(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @nearbyintl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @nearbyintf(float) nounwind readnone
+// CHECK-ERRNO: declare double @rint(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @rintl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @rintf(float) nounwind readnone
+// CHECK-ERRNO: declare double @round(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @roundl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @roundf(float) nounwind readnone
+// CHECK-ERRNO: declare double @trunc(double) nounwind readnone
+// CHECK-ERRNO: declare x86_fp80 @truncl(x86_fp80) nounwind readnone
+// CHECK-ERRNO: declare float @truncf(float) nounwind readnone
diff --git a/test/CodeGen/libcalls-fno-builtin.c b/test/CodeGen/libcalls-fno-builtin.c
index ce10759b0c5f..e7f3ef7b41d3 100644
--- a/test/CodeGen/libcalls-fno-builtin.c
+++ b/test/CodeGen/libcalls-fno-builtin.c
@@ -1,11 +1,32 @@
// RUN: %clang_cc1 -S -O3 -fno-builtin -o - %s | FileCheck %s
// rdar://10551066
+typedef __SIZE_TYPE__ size_t;
+
double ceil(double x);
double copysign(double,double);
double cos(double x);
double fabs(double x);
double floor(double x);
+char *strcat(char *s1, const char *s2);
+char *strncat(char *s1, const char *s2, size_t n);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+char *strcpy(char *s1, const char *s2);
+char *stpcpy(char *s1, const char *s2);
+char *strncpy(char *s1, const char *s2, size_t n);
+size_t strlen(const char *s);
+char *strpbrk(const char *s1, const char *s2);
+size_t strspn(const char *s1, const char *s2);
+double strtod(const char *nptr, char **endptr);
+float strtof(const char *nptr, char **endptr);
+long double strtold(const char *nptr, char **endptr);
+long int strtol(const char *nptr, char **endptr, int base);
+long long int strtoll(const char *nptr, char **endptr, int base);
+unsigned long int strtoul(const char *nptr, char **endptr, int base);
+unsigned long long int strtoull(const char *nptr, char **endptr, int base);
double t1(double x) { return ceil(x); }
// CHECK: t1
@@ -26,3 +47,79 @@ double t4(double x) { return fabs(x); }
double t5(double x) { return floor(x); }
// CHECK: t5
// CHECK: floor
+
+char *t6(char *x) { return strcat(x, ""); }
+// CHECK: t6
+// CHECK: strcat
+
+char *t7(char *x) { return strncat(x, "", 1); }
+// CHECK: t7
+// CHECK: strncat
+
+char *t8(void) { return strchr("hello, world", 'w'); }
+// CHECK: t8
+// CHECK: strchr
+
+char *t9(void) { return strrchr("hello, world", 'w'); }
+// CHECK: t9
+// CHECK: strrchr
+
+int t10(void) { return strcmp("foo", "bar"); }
+// CHECK: t10
+// CHECK: strcmp
+
+int t11(void) { return strncmp("foo", "bar", 3); }
+// CHECK: t11
+// CHECK: strncmp
+
+char *t12(char *x) { return strcpy(x, "foo"); }
+// CHECK: t12
+// CHECK: strcpy
+
+char *t13(char *x) { return stpcpy(x, "foo"); }
+// CHECK: t13
+// CHECK: stpcpy
+
+char *t14(char *x) { return strncpy(x, "foo", 3); }
+// CHECK: t14
+// CHECK: strncpy
+
+size_t t15(void) { return strlen("foo"); }
+// CHECK: t15
+// CHECK: strlen
+
+char *t16(char *x) { return strpbrk(x, ""); }
+// CHECK: t16
+// CHECK: strpbrk
+
+size_t t17(char *x) { return strspn(x, ""); }
+// CHECK: t17
+// CHECK: strspn
+
+double t18(char **x) { return strtod("123.4", x); }
+// CHECK: t18
+// CHECK: strtod
+
+float t19(char **x) { return strtof("123.4", x); }
+// CHECK: t19
+// CHECK: strtof
+
+long double t20(char **x) { return strtold("123.4", x); }
+// CHECK: t20
+// CHECK: strtold
+
+long int t21(char **x) { return strtol("1234", x, 10); }
+// CHECK: t21
+// CHECK: strtol
+
+long int t22(char **x) { return strtoll("1234", x, 10); }
+// CHECK: t22
+// CHECK: strtoll
+
+long int t23(char **x) { return strtoul("1234", x, 10); }
+// CHECK: t23
+// CHECK: strtoul
+
+long int t24(char **x) { return strtoull("1234", x, 10); }
+// CHECK: t24
+// CHECK: strtoull
diff --git a/test/CodeGen/long-double-x86-nacl.c b/test/CodeGen/long-double-x86-nacl.c
new file mode 100644
index 000000000000..175129cb6a2a
--- /dev/null
+++ b/test/CodeGen/long-double-x86-nacl.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-nacl | FileCheck %s
+
+long double x = 0;
+int checksize[sizeof(x) == 8 ? 1 : -1];
+
+// CHECK: define void @s1(double %a)
+void s1(long double a) {}
diff --git a/test/CodeGen/microsoft-call-conv-x64.c b/test/CodeGen/microsoft-call-conv-x64.c
new file mode 100644
index 000000000000..97a1d99d6b6d
--- /dev/null
+++ b/test/CodeGen/microsoft-call-conv-x64.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm < %s | FileCheck %s
+
+void __fastcall f1(void);
+void __stdcall f2(void);
+void __fastcall f4(void) {
+// CHECK: define void @f4()
+ f1();
+// CHECK: call void @f1()
+}
+void __stdcall f5(void) {
+// CHECK: define void @f5()
+ f2();
+// CHECK: call void @f2()
+}
+
+// PR5280
+void (__fastcall *pf1)(void) = f1;
+void (__stdcall *pf2)(void) = f2;
+void (__fastcall *pf4)(void) = f4;
+void (__stdcall *pf5)(void) = f5;
+
+int main(void) {
+ f4(); f5();
+ // CHECK: call void @f4()
+ // CHECK: call void @f5()
+ pf1(); pf2(); pf4(); pf5();
+ // CHECK: call void %{{.*}}()
+ // CHECK: call void %{{.*}}()
+ // CHECK: call void %{{.*}}()
+ // CHECK: call void %{{.*}}()
+ return 0;
+}
+
+// PR7117
+void __stdcall f7(foo) int foo; {}
+void f8(void) {
+ f7(0);
+ // CHECK: call void @f7(i32 0)
+}
diff --git a/test/CodeGen/microsoft-call-conv.c b/test/CodeGen/microsoft-call-conv.c
index 390c3be05e61..64d10fb4f4ff 100644
--- a/test/CodeGen/microsoft-call-conv.c
+++ b/test/CodeGen/microsoft-call-conv.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux -emit-llvm < %s | FileCheck %s
void __fastcall f1(void);
void __stdcall f2(void);
diff --git a/test/CodeGen/mips-byval-arg.c b/test/CodeGen/mips-byval-arg.c
index 4e5f41a14972..41ccd60e8f3e 100644
--- a/test/CodeGen/mips-byval-arg.c
+++ b/test/CodeGen/mips-byval-arg.c
@@ -1,5 +1,5 @@
-// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64
+// 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
typedef struct {
float f[3];
diff --git a/test/CodeGen/mips-clobber-reg.c b/test/CodeGen/mips-clobber-reg.c
index 2a06e53b39a5..be18353af820 100644
--- a/test/CodeGen/mips-clobber-reg.c
+++ b/test/CodeGen/mips-clobber-reg.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -S -o - -emit-llvm %s
+// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s
/*
This checks that the frontend will accept both
diff --git a/test/CodeGen/mips-constraint-regs.c b/test/CodeGen/mips-constraint-regs.c
index 075be058dc3e..ea063b50d5ce 100644
--- a/test/CodeGen/mips-constraint-regs.c
+++ b/test/CodeGen/mips-constraint-regs.c
@@ -1,4 +1,5 @@
-// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -S -o - -emit-llvm %s
+// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s \
+// RUN: | FileCheck %s
// This checks that the frontend will accept inline asm constraints
// c', 'l' and 'x'. Semantic checking will happen in the
@@ -10,6 +11,7 @@ int main()
// 'c': 16 bit address register for Mips16, GPR for all others
// I am using 'c' to constrain both the target and one of the source
// registers. We are looking for syntactical correctness.
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "addi $0,$1,$2 \0A\09\09", "=c,c,I"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) nounwind, !srcloc !{{[0-9]+}}
int __s, __v = 17;
int __t;
__asm__ __volatile__(
@@ -20,6 +22,7 @@ int main()
// 'l': lo register
// We are making it clear that destination register is lo with the
// use of the 'l' constraint ("=l").
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "mtlo $1 \0A\09\09", "=l,r,~{lo}"(i32 %{{[0-9]+}}) nounwind, !srcloc !{{[0-9]+}}
int i_temp = 44;
int i_result;
__asm__ __volatile__(
@@ -31,6 +34,7 @@ int main()
// 'x': Combined lo/hi registers
// We are specifying that destination registers are the hi/lo pair with the
// use of the 'x' constraint ("=x").
+ // CHECK: %{{[0-9]+}} = call i64 asm sideeffect "mthi $1 \0A\09\09mtlo $2 \0A\09\09", "=x,r,r"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) nounwind, !srcloc !{{[0-9]+}}
int i_hi = 3;
int i_lo = 2;
long long ll_result = 0;
@@ -40,5 +44,6 @@ int main()
: "=x" (ll_result)
: "r" (i_hi), "r" (i_lo)
: );
+
return 0;
}
diff --git a/test/CodeGen/mips-vector-arg.c b/test/CodeGen/mips-vector-arg.c
index 39998d91a64a..584192faf070 100644
--- a/test/CodeGen/mips-vector-arg.c
+++ b/test/CodeGen/mips-vector-arg.c
@@ -1,5 +1,5 @@
-// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64
+// 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
// check that
// 1. vector arguments are passed in integer registers
diff --git a/test/CodeGen/mips-vector-return.c b/test/CodeGen/mips-vector-return.c
index 12e71fadf87b..0bff96969000 100644
--- a/test/CodeGen/mips-vector-return.c
+++ b/test/CodeGen/mips-vector-return.c
@@ -1,5 +1,5 @@
-// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o - -emit-llvm %s | FileCheck %s -check-prefix=O32
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s -check-prefix=N64
+// 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
// vectors larger than 16-bytes are returned via the hidden pointer argument.
// N64/N32 returns vectors whose size is equal to or smaller than 16-bytes in
diff --git a/test/CodeGen/mips64-class-return.cpp b/test/CodeGen/mips64-class-return.cpp
index 8e32d5cbd6f0..2a786df3effa 100644
--- a/test/CodeGen/mips64-class-return.cpp
+++ b/test/CodeGen/mips64-class-return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
class B0 {
double d;
diff --git a/test/CodeGen/mips64-f128-literal.c b/test/CodeGen/mips64-f128-literal.c
index 2f01520a4f5f..9121169b726e 100644
--- a/test/CodeGen/mips64-f128-literal.c
+++ b/test/CodeGen/mips64-f128-literal.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
typedef long double LD;
diff --git a/test/CodeGen/mips64-nontrivial-return.cpp b/test/CodeGen/mips64-nontrivial-return.cpp
index 8aff9ab32f0f..2164b20c184a 100644
--- a/test/CodeGen/mips64-nontrivial-return.cpp
+++ b/test/CodeGen/mips64-nontrivial-return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
class B {
public:
diff --git a/test/CodeGen/mips64-padding-arg.c b/test/CodeGen/mips64-padding-arg.c
index b4dcfbace9d4..9d7f8774f6e7 100644
--- a/test/CodeGen/mips64-padding-arg.c
+++ b/test/CodeGen/mips64-padding-arg.c
@@ -1,4 +1,4 @@
-// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
typedef struct {
double d;
diff --git a/test/CodeGen/ms-inline-asm-64.c b/test/CodeGen/ms-inline-asm-64.c
new file mode 100644
index 000000000000..a74ede09e001
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm-64.c
@@ -0,0 +1,16 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -O0 -fms-extensions -fenable-experimental-ms-inline-asm -w -emit-llvm -o - | FileCheck %s
+
+void t1() {
+ int var = 10;
+ __asm mov rax, offset var ; rax = address of myvar
+// CHECK: t1
+// CHECK: call void asm sideeffect inteldialect "mov rax, $0", "r,~{rax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+}
+
+void t2() {
+ int var = 10;
+ __asm mov [eax], offset var
+// CHECK: t2
+// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+}
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index c140d60551d9..7f43da891e90 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -1,17 +1,18 @@
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -O0 -fms-extensions -fenable-experimental-ms-inline-asm -w -emit-llvm -o - | FileCheck %s
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -O0 -fms-extensions -fenable-experimental-ms-inline-asm -w -emit-llvm -o - | FileCheck %s
void t1() {
// CHECK: @t1
-// CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret void
__asm {}
}
void t2() {
// CHECK: @t2
-// CHECK: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret void
__asm nop
__asm nop
@@ -20,15 +21,15 @@ void t2() {
void t3() {
// CHECK: @t3
-// CHECK: call void asm sideeffect "nop\0Anop\0Anop", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "nop\0A\09nop\0A\09nop", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret void
__asm nop __asm nop __asm nop
}
void t4(void) {
// CHECK: @t4
-// CHECK: call void asm sideeffect "mov ebx, eax", "~{ebx},~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "mov ecx, ebx", "~{ecx},~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "mov ebx, eax", "~{ebx},~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "mov ecx, ebx", "~{ecx},~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret void
__asm mov ebx, eax
__asm mov ecx, ebx
@@ -36,7 +37,7 @@ void t4(void) {
void t5(void) {
// CHECK: @t5
-// CHECK: call void asm sideeffect "mov ebx, eax\0Amov ecx, ebx", "~{ebx},~{ecx},~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "mov ebx, eax\0A\09mov ecx, ebx", "~{ebx},~{ecx},~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret void
__asm mov ebx, eax __asm mov ecx, ebx
}
@@ -44,77 +45,158 @@ void t5(void) {
void t6(void) {
__asm int 0x2c
// CHECK: t6
-// CHECK: call void asm sideeffect "int 0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind
}
-void* t7(void) {
- __asm mov eax, fs:[0x10]
-// CHECK: t7
-// CHECK: call void asm sideeffect "mov eax, fs:[0x10]", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-}
-
-void t8() {
+void t7() {
__asm {
int 0x2c ; } asm comments are fun! }{
}
__asm {}
-// CHECK: t8
-// CHECK: call void asm sideeffect "int 0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: t7
+// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
}
-int t9() {
- __asm int 3 ; } comments for single-line asm
+
+int t8() {
+ __asm int 4 ; } comments for single-line asm
__asm {}
__asm int 4
return 10;
-// CHECK: t9
-// CHECK: call void asm sideeffect "int 3", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
-// CHECK: call void asm sideeffect "int 4", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: t8
+// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret i32 10
}
-void t10() {
+
+void t9() {
__asm {
push ebx
mov ebx, 0x07
pop ebx
}
-// CHECK: t10
-// CHECK: call void asm sideeffect "push ebx\0Amov ebx, 0x07\0Apop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: t9
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"() nounwind
}
-unsigned t11(void) {
+unsigned t10(void) {
unsigned i = 1, j;
__asm {
mov eax, i
mov j, eax
}
return j;
-// CHECK: t11
+// CHECK: t10
// CHECK: [[I:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: [[J:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: store i32 1, i32* [[I]], align 4
-// CHECK: call void asm sideeffect "mov eax, i\0Amov j, eax", "~{dirflag},~{fpsr},~{flags}"() nounwind ia_nsdialect
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $1\0A\09mov dword ptr $0, eax", "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}) nounwind
// CHECK: [[RET:%[a-zA-Z0-9]+]] = load i32* [[J]], align 4
// CHECK: ret i32 [[RET]]
}
-void t12(void) {
- __asm EVEN
- __asm ALIGN
+void t11(void) {
+ __asm mov eax, 1
+// CHECK: t11
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
+}
+
+unsigned t12(void) {
+ unsigned i = 1, j, l = 1, m;
+ __asm {
+ mov eax, i
+ mov j, eax
+ mov eax, l
+ mov m, eax
+ }
+ return j + m;
+// CHECK: t12
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $2\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $3\0A\09mov dword ptr $1, eax", "=*m,=*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}) nounwind
+}
+
+void t13() {
+ char i = 1;
+ short j = 2;
+ __asm movzx eax, i
+ __asm movzx eax, j
+// CHECK: t13
+// CHECK: call void asm sideeffect inteldialect "movzx eax, byte ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}}) nounwind
+// CHECK: call void asm sideeffect inteldialect "movzx eax, word ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i16* %{{.*}}) nounwind
+}
+
+void t14() {
+ unsigned i = 1, j = 2;
+ __asm {
+ .if 1
+ mov eax, i
+ .else
+ mov ebx, j
+ .endif
+ }
+// CHECK: t14
+// CHECK: call void asm sideeffect inteldialect ".if 1\0A\09mov eax, dword ptr $0\0A\09.else\0A\09mov ebx, j\0A\09.endif", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+}
+
+void t15() {
+ int var = 10;
+ __asm mov eax, var ; eax = 10
+ __asm mov eax, offset var ; eax = address of myvar
+// CHECK: t15
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+}
+
+void t16() {
+ int var = 10;
+ __asm mov [eax], offset var
+// CHECK: t16
+// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+}
+
+void t17() {
+ __asm _emit 0x4A
+ __asm _emit 0x43
+ __asm _emit 0x4B
+// CHECK: t17
+// CHECK: call void asm sideeffect inteldialect ".byte 0x4A", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect ".byte 0x43", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect ".byte 0x4B", "~{dirflag},~{fpsr},~{flags}"() nounwind
+}
+
+struct t18_type { int a, b; };
+
+int t18() {
+ struct t18_type foo;
+ foo.a = 1;
+ foo.b = 2;
+ __asm {
+ lea ebx, foo
+ mov eax, [ebx].0
+ mov [ebx].4, ecx
+ }
+ return foo.b;
+// CHECK: t18
+// CHECK: call void asm sideeffect inteldialect "lea ebx, foo\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
}
-void t13(void) {
+int t19() {
+ struct t18_type foo;
+ foo.a = 1;
+ foo.b = 2;
__asm {
- _emit 0x4A
- _emit 0x43
- _emit 0x4B
+ lea ebx, foo
+ mov eax, [ebx].foo.a
+ mov [ebx].foo.b, ecx
}
+ return foo.b;
+// CHECK: t19
+// CHECK: call void asm sideeffect inteldialect "lea ebx, foo\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
}
-void t14(void) {
- unsigned arr[10];
- __asm LENGTH arr ; sizeof(arr)/sizeof(arr[0])
- __asm SIZE arr ; sizeof(arr)
- __asm TYPE arr ; sizeof(arr[0])
+void t20() {
+ int foo;
+ __asm mov eax, TYPE foo
+// CHECK: t20
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
}
diff --git a/test/CodeGen/ppc-atomics.c b/test/CodeGen/ppc-atomics.c
new file mode 100644
index 000000000000..3fcb0fbec963
--- /dev/null
+++ b/test/CodeGen/ppc-atomics.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple powerpc-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=32
+// RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=64
+
+unsigned char c1, c2;
+unsigned short s1, s2;
+unsigned int i1, i2;
+unsigned long long ll1, ll2;
+
+enum memory_order {
+ memory_order_relaxed,
+ memory_order_consume,
+ memory_order_acquire,
+ memory_order_release,
+ memory_order_acq_rel,
+ memory_order_seq_cst
+};
+
+void test1(void) {
+ (void)__atomic_load(&c1, &c2, memory_order_seq_cst);
+ (void)__atomic_load(&s1, &s2, memory_order_seq_cst);
+ (void)__atomic_load(&i1, &i2, memory_order_seq_cst);
+ (void)__atomic_load(&ll1, &ll2, memory_order_seq_cst);
+
+// 32: define void @test1
+// 32: load atomic i8* @c1 seq_cst
+// 32: load atomic i16* @s1 seq_cst
+// 32: load atomic i32* @i1 seq_cst
+// 32: call void @__atomic_load(i32 8, i8* bitcast (i64* @ll1 to i8*)
+
+// 64: define void @test1
+// 64: load atomic i8* @c1 seq_cst
+// 64: load atomic i16* @s1 seq_cst
+// 64: load atomic i32* @i1 seq_cst
+// 64: load atomic i64* @ll1 seq_cst
+}
diff --git a/test/CodeGen/ppc64-align-long-double.c b/test/CodeGen/ppc64-align-long-double.c
new file mode 100644
index 000000000000..c4dcfa072367
--- /dev/null
+++ b/test/CodeGen/ppc64-align-long-double.c
@@ -0,0 +1,18 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: -f128:128:128-
+
+struct S {
+ double a;
+ long double b;
+};
+
+// CHECK: %struct.{{[a-zA-Z0-9]+}} = type { double, ppc_fp128 }
+
+long double test (struct S x)
+{
+ return x.b;
+}
+
+// CHECK: %{{[0-9]}} = load ppc_fp128* %{{[a-zA-Z0-9]+}}, align 16
diff --git a/test/CodeGen/ppc64-extend.c b/test/CodeGen/ppc64-extend.c
new file mode 100644
index 000000000000..f4d6bf9c68df
--- /dev/null
+++ b/test/CodeGen/ppc64-extend.c
@@ -0,0 +1,15 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -O0 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+void f1(int x) { return; }
+// CHECK: define void @f1(i32 signext %x) nounwind
+
+void f2(unsigned int x) { return; }
+// CHECK: define void @f2(i32 zeroext %x) nounwind
+
+int f3(void) { return 0; }
+// CHECK: define signext i32 @f3() nounwind
+
+unsigned int f4(void) { return 0; }
+// CHECK: define zeroext i32 @f4() nounwind
+
diff --git a/test/CodeGen/ppc64-struct-onefloat.c b/test/CodeGen/ppc64-struct-onefloat.c
new file mode 100644
index 000000000000..4f9e1949cea3
--- /dev/null
+++ b/test/CodeGen/ppc64-struct-onefloat.c
@@ -0,0 +1,49 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -O0 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+typedef struct s1 { float f; } Sf;
+typedef struct s2 { double d; } Sd;
+typedef struct s4 { Sf fs; } SSf;
+typedef struct s5 { Sd ds; } SSd;
+
+void bar(Sf a, Sd b, SSf d, SSd e) {}
+
+// CHECK: define void @bar
+// CHECK: %a = alloca %struct.s1, align 4
+// CHECK: %b = alloca %struct.s2, align 8
+// CHECK: %d = alloca %struct.s4, align 4
+// CHECK: %e = alloca %struct.s5, align 8
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1* %a, i32 0, i32 0
+// CHECK: store float %a.coerce, float* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2* %b, i32 0, i32 0
+// CHECK: store double %b.coerce, double* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s4* %d, i32 0, i32 0
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0
+// CHECK: store float %d.coerce, float* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s5* %e, i32 0, i32 0
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0
+// CHECK: store double %e.coerce, double* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: ret void
+
+void foo(void)
+{
+ Sf p1 = { 22.63f };
+ Sd p2 = { 19.47 };
+ SSf p4 = { { 22.63f } };
+ SSd p5 = { { 19.47 } };
+ bar(p1, p2, p4, p5);
+}
+
+// CHECK: 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
+// CHECK: %{{[0-9]+}} = load double* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s4* %p4, i32 0, i32 0
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s1* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0
+// CHECK: %{{[0-9]+}} = load float* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s5* %p5, i32 0, i32 0
+// CHECK: %{{[a-zA-Z0-9.]+}} = getelementptr %struct.s2* %{{[a-zA-Z0-9.]+}}, i32 0, i32 0
+// CHECK: %{{[0-9]+}} = load double* %{{[a-zA-Z0-9.]+}}, align 1
+// CHECK: call void @bar(float inreg %{{[0-9]+}}, double inreg %{{[0-9]+}}, float inreg %{{[0-9]+}}, double inreg %{{[0-9]+}})
+// CHECK: ret void
diff --git a/test/CodeGen/ppc64-varargs-struct.c b/test/CodeGen/ppc64-varargs-struct.c
new file mode 100644
index 000000000000..61c33b052980
--- /dev/null
+++ b/test/CodeGen/ppc64-varargs-struct.c
@@ -0,0 +1,30 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+#include <stdarg.h>
+
+struct x {
+ long a;
+ double b;
+};
+
+void testva (int n, ...)
+{
+ va_list ap;
+
+ struct x t = va_arg (ap, struct x);
+// CHECK: bitcast i8* %{{[a-z.0-9]*}} to %struct.x*
+// CHECK: bitcast %struct.x* %t to i8*
+// CHECK: bitcast %struct.x* %{{[0-9]+}} to i8*
+// CHECK: call void @llvm.memcpy
+
+ int v = va_arg (ap, int);
+// CHECK: ptrtoint i8* %{{[a-z.0-9]*}} to i64
+// CHECK: add i64 %{{[0-9]+}}, 4
+// CHECK: inttoptr i64 %{{[0-9]+}} to i8*
+// CHECK: bitcast i8* %{{[0-9]+}} to i32*
+
+ __int128_t u = va_arg (ap, __int128_t);
+// CHECK: bitcast i8* %{{[a-z.0-9]+}} to i128*
+// CHECK-NEXT: load i128* %{{[0-9]+}}
+}
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index 7ad2b77d8e7e..2efc2ebc28d8 100644
--- a/test/CodeGen/pragma-weak.c
+++ b/test/CodeGen/pragma-weak.c
@@ -157,6 +157,15 @@ void PR10878() { SHA384Pad(0); }
// CHECK: call void @SHA384Pad(i8* null)
+// PR14046: Parse #pragma weak in function-local context
+extern int PR14046e(void);
+void PR14046f() {
+#pragma weak PR14046e
+ PR14046e();
+}
+// CHECK: declare extern_weak i32 @PR14046e()
+
+
///////////// TODO: stuff that still doesn't work
// due to the fact that disparate TopLevelDecls cannot affect each other
diff --git a/test/CodeGen/rtm-builtins.c b/test/CodeGen/rtm-builtins.c
new file mode 100644
index 000000000000..c4939a9a3d9f
--- /dev/null
+++ b/test/CodeGen/rtm-builtins.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +rtm -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+unsigned int test_xbegin(void) {
+ // CHECK: i32 @llvm.x86.xbegin()
+ return _xbegin();
+}
+
+void
+test_xend(void) {
+ // CHECK: void @llvm.x86.xend()
+ _xend();
+}
+
+void
+test_xabort(void) {
+ // CHECK: void @llvm.x86.xabort(i8 2)
+ _xabort(2);
+}
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 0e48560b0869..400209fca291 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -1,8 +1,39 @@
// RUN: %clang_cc1 -ffreestanding -triple i386-apple-darwin9 -target-cpu pentium4 -target-feature +sse4.1 -g -emit-llvm %s -o - | FileCheck %s
+#include <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
+__m128 test_rsqrt_ss(__m128 x) {
+ // CHECK: define {{.*}} @test_rsqrt_ss
+ // CHECK: call <4 x float> @llvm.x86.sse.rsqrt.ss
+ // CHECK: extractelement <4 x float> {{.*}}, i32 0
+ // CHECK: extractelement <4 x float> {{.*}}, i32 1
+ // CHECK: extractelement <4 x float> {{.*}}, i32 2
+ // CHECK: extractelement <4 x float> {{.*}}, i32 3
+ return _mm_rsqrt_ss(x);
+}
+
+__m128 test_rcp_ss(__m128 x) {
+ // CHECK: define {{.*}} @test_rcp_ss
+ // CHECK: call <4 x float> @llvm.x86.sse.rcp.ss
+ // CHECK: extractelement <4 x float> {{.*}}, i32 0
+ // CHECK: extractelement <4 x float> {{.*}}, i32 1
+ // CHECK: extractelement <4 x float> {{.*}}, i32 2
+ // CHECK: extractelement <4 x float> {{.*}}, i32 3
+ return _mm_rcp_ss(x);
+}
+
+__m128 test_sqrt_ss(__m128 x) {
+ // CHECK: define {{.*}} @test_sqrt_ss
+ // CHECK: call <4 x float> @llvm.x86.sse.sqrt.ss
+ // CHECK: extractelement <4 x float> {{.*}}, i32 0
+ // CHECK: extractelement <4 x float> {{.*}}, i32 1
+ // CHECK: extractelement <4 x float> {{.*}}, i32 2
+ // CHECK: extractelement <4 x float> {{.*}}, i32 3
+ return _mm_sqrt_ss(x);
+}
+
__m128 test_loadl_pi(__m128 x, void* y) {
// CHECK: define {{.*}} @test_loadl_pi
// CHECK: load <2 x float>* {{.*}}, align 1{{$}}
diff --git a/test/CodeGen/statements.c b/test/CodeGen/statements.c
index e2bbb5a90a81..5affb9a83513 100644
--- a/test/CodeGen/statements.c
+++ b/test/CodeGen/statements.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -Wno-error=return-type %s -emit-llvm-only
+// REQUIRES: LP64
void test1(int x) {
switch (x) {
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index 3de7b6727bc2..d51817882283 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm < %s | FileCheck %s
void __attribute__((fastcall)) f1(void);
void __attribute__((stdcall)) f2(void);
@@ -48,3 +48,99 @@ void f8(void) {
f7(0);
// CHECK: call x86_stdcallcc void @f7(i32 0)
}
+
+void __attribute__((fastcall)) foo1(int y);
+void bar1(int y) {
+ // CHECK: define void @bar1
+ // CHECK: call x86_fastcallcc void @foo1(i32 inreg %
+ foo1(y);
+}
+
+struct S1 {
+ int x;
+};
+void __attribute__((fastcall)) foo2(struct S1 y);
+void bar2(struct S1 y) {
+ // CHECK: 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: call x86_fastcallcc void @foo3(i32* inreg %
+ foo3(y);
+}
+
+enum Enum {Eval};
+void __attribute__((fastcall)) foo4(enum Enum y);
+void bar4(enum Enum y) {
+ // CHECK: define void @bar4
+ // CHECK: call x86_fastcallcc void @foo4(i32 inreg %
+ foo4(y);
+}
+
+struct S2 {
+ int x1;
+ double x2;
+ double x3;
+};
+void __attribute__((fastcall)) foo5(struct S2 y);
+void bar5(struct S2 y) {
+ // CHECK: 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: 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: 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: 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: 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: 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: call x86_fastcallcc void @foo11(double %{{.*}}, i32 inreg %
+ foo11(y, x);
+}
+
+struct S3 {
+ float x;
+};
+void __attribute__((fastcall)) foo12(struct S3 y, int x);
+void bar12(struct S3 y, int x) {
+ // CHECK: define void @bar12
+ // CHECK: call x86_fastcallcc void @foo12(float %{{.*}}, i32 inreg %
+ foo12(y, x);
+}
diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp
index b9a68fe0eae1..93690361906b 100644
--- a/test/CodeGen/tbaa-for-vptr.cpp
+++ b/test/CodeGen/tbaa-for-vptr.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm -o - -O0 -fthread-sanitizer %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -O0 -fsanitize=thread %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -o - -O1 %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -o - -O1 -relaxed-aliasing -fthread-sanitizer %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 - -O2 -relaxed-aliasing %s | FileCheck %s --check-prefix=NOTBAA
@@ -21,7 +21,7 @@ void CallFoo(A *a) {
a->foo();
}
-// CHECK: %{{.*}} = load {{.*}} !tbaa !0
-// CHECK: store {{.*}} !tbaa !0
-// CHECK: = metadata !{metadata !"vtable pointer", metadata !{{.*}}}
+// CHECK: %{{.*}} = load {{.*}} !tbaa ![[NUM:[0-9]+]]
+// CHECK: store {{.*}} !tbaa ![[NUM]]
+// CHECK: [[NUM]] = metadata !{metadata !"vtable pointer", metadata !{{.*}}}
// NOTBAA-NOT: = metadata !{metadata !"Simple C/C++ TBAA"}
diff --git a/test/CodeGen/tbaa-struct.cpp b/test/CodeGen/tbaa-struct.cpp
new file mode 100644
index 000000000000..8b30aa0a495a
--- /dev/null
+++ b/test/CodeGen/tbaa-struct.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm -o - -O1 %s | FileCheck %s
+//
+// Check that we generate !tbaa.struct metadata for struct copies.
+struct A {
+ short s;
+ int i;
+ char c;
+ int j;
+};
+
+void copy(struct A *a, struct A *b) {
+ *a = *b;
+}
+
+// CHECK: target datalayout = "{{.*}}p:[[P:64|32]]
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i[[P]](i8* %{{.*}}, i8* %{{.*}}, i[[P]] 16, i32 4, i1 false), !tbaa.struct [[TS:!.*]]
+// CHECK: [[TS]] = metadata !{i64 0, i64 2, metadata !{{.*}}, i64 4, i64 4, metadata !{{.*}}, i64 8, i64 1, metadata !{{.*}}, i64 12, i64 4, metadata !{{.*}}}
diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c
index f52dad556485..bc8bc700636c 100644
--- a/test/CodeGen/trapv.c
+++ b/test/CodeGen/trapv.c
@@ -17,7 +17,8 @@ void test0() {
// CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 [[T2]])
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
// CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
- // CHECK-NEXT: br i1 [[T5]]
+ // CHECK-NEXT: [[T6:%.*]] = xor i1 [[T5]], true
+ // CHECK-NEXT: br i1 [[T6]]
// CHECK: call void @llvm.trap()
i = j + k;
}
@@ -31,7 +32,8 @@ void test1() {
// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
- // CHECK-NEXT: br i1 [[T4]]
+ // CHECK-NEXT: [[T5:%.*]] = xor i1 [[T4]], true
+ // CHECK-NEXT: br i1 [[T5]]
// CHECK: call void @llvm.trap()
}
@@ -44,6 +46,16 @@ void test2() {
// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T1]], i32 1)
// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
// CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
- // CHECK-NEXT: br i1 [[T4]]
+ // CHECK-NEXT: [[T5:%.*]] = xor i1 [[T4]], true
+ // CHECK-NEXT: br i1 [[T5]]
// CHECK: call void @llvm.trap()
}
+
+// CHECK: define void @test3(
+void test3(int a, int b, float c, float d) {
+ // CHECK-NOT: @llvm.trap
+ (void)(a / b);
+ (void)(a % b);
+ (void)(c / d);
+ // CHECK: }
+}
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index c588ca8e1b60..7a79cb6047a1 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fexceptions -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck -check-prefix NOEXC %s
+// 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
int opaque();
diff --git a/test/CodeGen/x86_64-arguments-nacl.c b/test/CodeGen/x86_64-arguments-nacl.c
new file mode 100644
index 000000000000..8f756caba757
--- /dev/null
+++ b/test/CodeGen/x86_64-arguments-nacl.c
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-nacl -emit-llvm -o - %s| FileCheck %s
+#include <stdarg.h>
+// Test for x86-64 structure representation (instead of pnacl representation),
+// in particular for unions. Also crib a few tests from x86 Linux.
+
+union PP_VarValue {
+ int as_int;
+ double as_double;
+ long long as_i64;
+};
+
+struct PP_Var {
+ int type;
+ int padding;
+ union PP_VarValue value;
+};
+
+// CHECK: define { i64, i64 } @f0()
+struct PP_Var f0() {
+ struct PP_Var result = { 0, 0, 0 };
+ return result;
+}
+
+// CHECK: 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()
+long double f5(void) {
+ return 0;
+}
+
+// CHECK: 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)
+union u8 {
+ long double a;
+ int b;
+};
+union u8 f8_1() { while (1) {} }
+void f8_2(union u8 a0) {}
+
+// CHECK: define i64 @f9()
+struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
+
+// CHECK: define void @f10(i64 %a0.coerce)
+struct s10 { int a; int b; int : 0; };
+void f10(struct s10 a0) {}
+
+// CHECK: 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)
+struct s12 { int a __attribute__((aligned(16))); };
+struct s12 f12_0(void) { while (1) {} }
+void f12_1(struct s12 a0) {}
+
+// Check that sret parameter is accounted for when checking available integer
+// registers.
+// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
+
+struct s13_0 { long long f0[3]; };
+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)
+struct __attribute__((aligned(32))) s20 {
+ int x;
+ int y;
+};
+void f20(struct s20 x) {}
+
+
+// CHECK: declare void @func(i64)
+typedef struct _str {
+ union {
+ long double a;
+ long c;
+ };
+} str;
+
+void func(str s);
+str ss;
+void f9122143()
+{
+ func(ss);
+}
+
+
+typedef struct {
+ int a;
+ int b;
+} s1;
+// CHECK: 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)
+s1 __attribute__((pnaclcall)) f49() { s1 s; s.a = s.b = 1; return s; }
+
+union simple_union {
+ int a;
+ char b;
+};
+// Unions should be passed as byval structs
+// CHECK: define void @f50(%union.simple_union* byval %s)
+void __attribute__((pnaclcall)) f50(union simple_union s) {}
+
+typedef struct {
+ int b4 : 4;
+ int b3 : 3;
+ int b8 : 8;
+} bitfield1;
+// Bitfields should be passed as byval structs
+// CHECK: define void @f51(%struct.bitfield1* byval %bf1)
+void __attribute__((pnaclcall)) f51(bitfield1 bf1) {}
diff --git a/test/CodeGenCUDA/address-spaces.cu b/test/CodeGenCUDA/address-spaces.cu
index 61d4d6b6ba48..9df7e3f4d262 100644
--- a/test/CodeGenCUDA/address-spaces.cu
+++ b/test/CodeGenCUDA/address-spaces.cu
@@ -20,5 +20,17 @@ __device__ void foo() {
// CHECK: load i32* bitcast (i32 addrspace(3)* @k to i32*)
k++;
+
+ static int li;
+ // CHECK: load i32 addrspace(1)* @_ZZ3foovE2li
+ li++;
+
+ __constant__ int lj;
+ // CHECK: load i32 addrspace(4)* @_ZZ3foovE2lj
+ lj++;
+
+ __shared__ int lk;
+ // CHECK: load i32 addrspace(3)* @_ZZ3foovE2lk
+ lk++;
}
diff --git a/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp b/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp
index 875c412c6b48..1c9d1202afb2 100644
--- a/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp
+++ b/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// REQUIRES: LP64
struct S {
int A[2];
diff --git a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
index 8361680546f3..7acc07d0c5b8 100644
--- a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
+++ b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fexceptions -emit-llvm %s -o - | FileCheck %s
int c(void) __attribute__((const));
int p(void) __attribute__((pure));
int t(void);
diff --git a/test/CodeGenCXX/assign-construct-memcpy.cpp b/test/CodeGenCXX/assign-construct-memcpy.cpp
new file mode 100644
index 000000000000..3d4205132409
--- /dev/null
+++ b/test/CodeGenCXX/assign-construct-memcpy.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -o - -std=c++11 %s -DPOD | FileCheck %s -check-prefix=CHECK-POD
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -o - -std=c++11 %s | FileCheck %s -check-prefix=CHECK-NONPOD
+
+// Declare the reserved placement operators.
+typedef __typeof__(sizeof(0)) size_t;
+void *operator new(size_t, void*) throw();
+void operator delete(void*, void*) throw();
+void *operator new[](size_t, void*) throw();
+void operator delete[](void*, void*) throw();
+template<typename T> T &&move(T&);
+
+struct foo {
+#ifndef POD
+ foo() {} // non-POD
+#endif
+ void *a, *b;
+ bool c;
+};
+
+// It is not legal to copy the tail padding in all cases, but if it is it can
+// yield better codegen.
+
+foo *test1(void *f, const foo &x) {
+ return new (f) foo(x);
+// CHECK-POD: test1
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test1
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+}
+
+foo *test2(const foo &x) {
+ return new foo(x);
+// CHECK-POD: test2
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test2
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+}
+
+foo test3(const foo &x) {
+ foo f = x;
+ return f;
+// CHECK-POD: test3
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test3
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+}
+
+foo *test4(foo &&x) {
+ return new foo(x);
+// CHECK-POD: test4
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test4
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+}
+
+void test5(foo &f, const foo &x) {
+ f = x;
+// CHECK-POD: test5
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test5
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 17, i32 8
+}
+
+extern foo globtest;
+
+void test6(foo &&x) {
+ globtest = move(x);
+// CHECK-POD: test6
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test6
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 17, i32 8
+}
+
+void byval(foo f);
+
+void test7(const foo &x) {
+ byval(x);
+// CHECK-POD: test7
+// CHECK-POD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+
+// CHECK-NONPOD: test7
+// CHECK-NONPOD: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 24, i32 8
+}
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 9e8740e54700..a0dd74860134 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -10,17 +10,21 @@ class C {
virtual void bar1() __attribute__((aligned(1)));
virtual void bar2() __attribute__((aligned(2)));
virtual void bar3() __attribute__((aligned(1024)));
+ void bar4() __attribute__((aligned(1024)));
} c;
-// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) nounwind align 2
+// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) unnamed_addr nounwind align 2
void C::bar1() { }
-// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) nounwind align 2
+// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) unnamed_addr nounwind align 2
void C::bar2() { }
-// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) nounwind align 1024
+// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) unnamed_addr nounwind align 1024
void C::bar3() { }
+// CHECK: define void @_ZN1C4bar4Ev(%class.C* %this) nounwind align 1024
+void C::bar4() { }
+
// PR6635
// CHECK: define i32 @_Z5test1v()
int test1() { return 10; }
diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp
index 4542563717a1..0629c31015c7 100644
--- a/test/CodeGenCXX/builtins.cpp
+++ b/test/CodeGenCXX/builtins.cpp
@@ -7,15 +7,3 @@ int main() {
// CHECK: call signext i8 @memmove()
return memmove();
}
-
-// <rdar://problem/10063539>
-
-template<int (*Compare)(const char *s1, const char *s2)>
-int equal(const char *s1, const char *s2) {
- return Compare(s1, s2) == 0;
-}
-
-// CHECK: define weak_odr i32 @_Z5equalIXadL_Z16__builtin_strcmpPKcS1_EEEiS1_S1_
-// CHECK: call i32 @strcmp
-template int equal<&__builtin_strcmp>(const char*, const char*);
-
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
new file mode 100644
index 000000000000..fd9e3d7278a7
--- /dev/null
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+// CHECK: @_Z17reference_binding
+void reference_binding(int *p) {
+ // C++ core issue 453: If an lvalue to which a reference is directly bound
+ // designates neither an existing object or function of an appropriate type,
+ // nor a region of storage of suitable size and alignment to contain an object
+ // of the reference's type, the behavior is undefined.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ int &r = *p;
+}
+
+struct S {
+ double d;
+ int a, b;
+ virtual int f();
+};
+
+// CHECK: @_Z13member_access
+void member_access(S *p) {
+ // (1a) Check 'p' is appropriately sized and aligned for member access.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 24
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 7
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+
+ // (1b) Check that 'p' actually points to an 'S'.
+
+ // CHECK: %[[VPTRADDR:.*]] = bitcast {{.*}} to i64*
+ // CHECK-NEXT: %[[VPTR:.*]] = load i64* %[[VPTRADDR]]
+ //
+ // hash_16_bytes:
+ //
+ // If this number changes, it indicates that either the mangled name of ::S
+ // has changed, or that LLVM's hashing function has changed. The latter case
+ // is OK if the hashing function is still stable.
+ //
+ // The two hash values are for 64- and 32-bit Clang binaries, respectively.
+ // FIXME: We should produce a 64-bit value either way.
+ //
+ // CHECK-NEXT: xor i64 {{-4030275160588942838|2562089159}}, %[[VPTR]]
+ // CHECK-NEXT: mul i64 {{.*}}, -7070675565921424023
+ // CHECK-NEXT: lshr i64 {{.*}}, 47
+ // CHECK-NEXT: xor i64
+ // CHECK-NEXT: xor i64 %[[VPTR]]
+ // CHECK-NEXT: mul i64 {{.*}}, -7070675565921424023
+ // CHECK-NEXT: lshr i64 {{.*}}, 47
+ // CHECK-NEXT: xor i64
+ // CHECK-NEXT: %[[HASH:.*]] = mul i64 {{.*}}, -7070675565921424023
+ //
+ // Check the hash against the table:
+ //
+ // CHECK-NEXT: %[[IDX:.*]] = and i64 %{{.*}}, 127
+ // CHECK-NEXT: getelementptr inbounds [128 x i64]* @__ubsan_vptr_type_cache, i32 0, i64 %[[IDX]]
+ // CHECK-NEXT: %[[CACHEVAL:.*]] = load i64*
+ // CHECK-NEXT: icmp eq i64 %[[CACHEVAL]], %[[HASH]]
+ // CHECK-NEXT: br i1
+
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}}, i64 %{{.*}}, i64 %[[HASH]])
+
+ // (2) Check 'p->b' is appropriately sized and aligned for a load.
+
+ // FIXME: Suppress this in the trivial case of a member access, because we
+ // know we've just checked the member access expression itself.
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ int k = p->b;
+
+ // (3a) Check 'p' is appropriately sized and aligned for member function call.
+
+ // CHECK: icmp ne {{.*}}, null
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-NEXT: icmp uge i64 %[[SIZE]], 24
+
+ // CHECK: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 7
+ // CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+
+ // (3b) Check that 'p' actually points to an 'S'
+
+ // CHECK: load i64*
+ // CHECK-NEXT: xor i64 {{-4030275160588942838|2562089159}},
+ // [...]
+ // CHECK: getelementptr inbounds [128 x i64]* @__ubsan_vptr_type_cache, i32 0, i64 %
+ // CHECK: br i1
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}}, i64 %{{.*}}, i64 %{{.*}})
+
+ k = p->f();
+}
+
+// CHECK: @_Z12lsh_overflow
+int lsh_overflow(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+
+ // This is present for C++11 but not for C: C++ core issue 1457 allows a '1'
+ // to be shifted into the sign bit, but not out of it.
+ // CHECK-NEXT: %[[SHIFTED_OUT_NOT_SIGN:.*]] = lshr i32 %[[SHIFTED_OUT]], 1
+
+ // CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT_NOT_SIGN]], 0
+ // CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
+
+ // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+ return a << b;
+}
+
+// CHECK: @_Z9no_return
+int no_return() {
+ // CHECK: call void @__ubsan_handle_missing_return(i8* bitcast ({{.*}}* @{{.*}} to i8*)) noreturn nounwind
+ // CHECK-NEXT: unreachable
+}
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
index 17a31149e13e..5df0ea587667 100644
--- a/test/CodeGenCXX/compound-literals.cpp
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
struct X {
X();
@@ -18,10 +18,10 @@ int f() {
// CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0
// CHECK-NEXT: store i32 17, i32* [[I]]
// CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 1
- // CHECK-NEXT: call void @_ZN1XC1EPKc({{.*}}[[X]]
+ // CHECK-NEXT: call %struct.X* @_ZN1XC1EPKc({{.*}}[[X]]
// CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 0
// CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = load i32*
- // CHECK-NEXT: call void @_ZN1YD1Ev
+ // CHECK-NEXT: call %struct.Y* @_ZN1YD1Ev
// CHECK-NEXT: ret i32 [[RESULT]]
return ((Y){17, "seventeen"}).i;
}
diff --git a/test/CodeGenCXX/const-global-linkage.cpp b/test/CodeGenCXX/const-global-linkage.cpp
index d0a055b49495..df78fdd0287c 100644
--- a/test/CodeGenCXX/const-global-linkage.cpp
+++ b/test/CodeGenCXX/const-global-linkage.cpp
@@ -2,12 +2,16 @@
const int x = 10;
const int y = 20;
+const volatile int z = 30;
// CHECK-NOT: @x
+// CHECK: @z = constant i32 30
// CHECK: @_ZL1y = internal constant i32 20
const int& b() { return y; }
const char z1[] = "asdf";
const char z2[] = "zxcv";
+const volatile char z3[] = "zxcv";
// CHECK-NOT: @z1
+// CHECK: @z3 = constant
// CHECK: @_ZL2z2 = internal constant
const char* b2() { return z2; }
diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp
index db1bb412606b..833adba8bae7 100644
--- a/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/test/CodeGenCXX/const-init-cxx11.cpp
@@ -432,11 +432,7 @@ namespace InitFromConst {
// CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
consume<const S&>(s);
- // FIXME CHECK-NOT: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
- // There's no lvalue-to-rvalue conversion here, so 'r' is odr-used, and
- // we're permitted to emit a load of it. This seems likely to be a defect
- // in the standard. If we start emitting a direct reference to 's', update
- // this test.
+ // CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
consume<const S&>(r);
// CHECK: call void @_ZN13InitFromConst7consumeIPKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
diff --git a/test/CodeGenCXX/conversion-operator-base.cpp b/test/CodeGenCXX/conversion-operator-base.cpp
index 8fbeadf14916..e62e225a201f 100644
--- a/test/CodeGenCXX/conversion-operator-base.cpp
+++ b/test/CodeGenCXX/conversion-operator-base.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only %s -verify
+// expected-no-diagnostics
// PR5730
struct A { operator int(); float y; };
diff --git a/test/CodeGenCXX/copy-assign-synthesis-3.cpp b/test/CodeGenCXX/copy-assign-synthesis-3.cpp
index ce4640a7eddb..5469d113357e 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-3.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
struct A {
A& operator=(A&);
diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp
index 9480cbfdbb3a..4ff877516b09 100644
--- a/test/CodeGenCXX/copy-constructor-elim-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
struct A { int x; A(int); ~A(); };
A f() { return A(0); }
@@ -66,7 +66,7 @@ namespace PR12139 {
// CHECK: define i32 @_ZN7PR121394testEv
int test() {
// CHECK: call void @_ZN7PR121391A5makeAEv
- // CHECK-NEXT: call void @_ZN7PR121391AC1ERKS0_i
+ // CHECK-NEXT: call %"struct.PR12139::A"* @_ZN7PR121391AC1ERKS0_i
A a(A::makeA(), 3);
// CHECK-NEXT: getelementptr inbounds
// CHECK-NEXT: load
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index ad6492f5bfdc..338159cd8258 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++11 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -fexceptions -fcxx-exceptions -std=c++11 -o - %s | FileCheck %s
struct non_trivial {
non_trivial();
diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp
index b773178e6b81..df689978a889 100644
--- a/test/CodeGenCXX/cxx0x-initializer-array.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
struct A { int a[1]; };
typedef A x[];
diff --git a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
index 48fbe85d0d7a..be5b44df1fec 100644
--- a/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-constructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
struct S {
S(int x) { }
diff --git a/test/CodeGenCXX/cxx0x-initializer-references.cpp b/test/CodeGenCXX/cxx0x-initializer-references.cpp
index 660b018460db..10586c11a7a7 100644
--- a/test/CodeGenCXX/cxx0x-initializer-references.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-references.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -S -triple armv7-none-eabi -emit-llvm -o - %s | FileCheck %s
namespace reference {
struct A {
@@ -64,10 +64,10 @@ namespace reference {
{
// Ensure lifetime extension.
- // CHECK: call void @_ZN9reference1BC1Ev
+ // CHECK: call %"struct.reference::B"* @_ZN9reference1BC1Ev
// CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
const B &rb{ B() };
- // CHECK: call void @_ZN9reference1BD1Ev
+ // CHECK: call %"struct.reference::B"* @_ZN9reference1BD1Ev
}
}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
index c533e453a5e4..209ee6513855 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
namespace std {
typedef decltype(sizeof(int)) size_t;
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 81ce55984466..8d9fce040fd7 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
namespace std {
typedef decltype(sizeof(int)) size_t;
diff --git a/test/CodeGenCXX/cxx11-special-members.cpp b/test/CodeGenCXX/cxx11-special-members.cpp
new file mode 100644
index 000000000000..59461f9e2f4b
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-special-members.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - -triple=i686-linux-gnu | FileCheck %s
+
+struct A {
+ A(const A&);
+ A &operator=(const A&);
+};
+
+struct B {
+ A a;
+ B(B&&) = default;
+ B &operator=(B&&) = default;
+};
+
+// CHECK: define {{.*}} @_Z2f1
+void f1(B &x) {
+ // CHECK-NOT: memcpy
+ // CHECK: call {{.*}} @_ZN1BC1EOS_(
+ B b(static_cast<B&&>(x));
+}
+
+// CHECK: define {{.*}} @_Z2f2
+void f2(B &x, B &y) {
+ // CHECK-NOT: memcpy
+ // CHECK: call {{.*}} @_ZN1BaSEOS_(
+ x = static_cast<B&&>(y);
+}
+
+// CHECK: define {{.*}} @_ZN1BaSEOS_(
+// CHECK: call {{.*}} @_ZN1AaSERKS_(
+
+// CHECK: define {{.*}} @_ZN1BC2EOS_(
+// CHECK: call {{.*}} @_ZN1AC1ERKS_(
diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp
index 35e5f2775fd7..ee9384979d30 100644
--- a/test/CodeGenCXX/debug-info-artificial-arg.cpp
+++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp
@@ -23,7 +23,7 @@ int main(int argc, char **argv) {
}
// FIXME: The numbers are truly awful.
-// CHECK: !16 = metadata !{i32 {{.*}}, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 64, metadata !17} ; [ DW_TAG_pointer_type ]
+// CHECK: !16 = metadata !{i32 786447, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !17} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from A]
// CHECK: !17 = metadata !{i32 {{.*}}, null, metadata !"A", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !18, i32 0, metadata !17, null} ; [ DW_TAG_class_type ]
// CHECK: metadata !17, metadata !"A", metadata !"A", metadata !"", metadata !6, i32 12, metadata !43, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !45, i32 12} ; [ DW_TAG_subprogram ]
// CHECK: metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !44, i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
diff --git a/test/CodeGenCXX/debug-info-blocks.cpp b/test/CodeGenCXX/debug-info-blocks.cpp
new file mode 100644
index 000000000000..5b20db582803
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-blocks.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -gline-tables-only -fblocks -S -emit-llvm -o - | FileCheck %s
+
+struct A {
+ A();
+ A(const A &);
+ ~A();
+};
+
+void test() {
+ __block A a;
+}
+
+// CHECK: [ DW_TAG_subprogram ] [line 10] [local] [def] [__Block_byref_object_copy_]
+// CHECK: [ DW_TAG_subprogram ] [line 10] [local] [def] [__Block_byref_object_dispose_]
diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp
index 151c5f90534c..062227a02382 100644
--- a/test/CodeGenCXX/debug-info-class.cpp
+++ b/test/CodeGenCXX/debug-info-class.cpp
@@ -1,12 +1,24 @@
-// RUN: %clang -emit-llvm -g -S %s -o - | grep HdrSize
-struct A {
+// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+struct foo;
+void func(foo *f) { // CHECK: DW_TAG_structure_type
+}
+class bar;
+void func(bar *f) { // CHECK: DW_TAG_class_type
+}
+union baz;
+void func(baz *f) { // CHECK: DW_TAG_union_type
+}
+struct A { // CHECK: DW_TAG_structure_type
int one;
- static const int HdrSize = 52;
+ static const int HdrSize = 52; // CHECK: HdrSize
int two;
A() {
int x = 1;
}
};
+class B { // CHECK: DW_TAG_class_type
+};
int main() {
A a;
+ B b;
}
diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp
index 6f88439b1eed..fd243abb2e84 100644
--- a/test/CodeGenCXX/debug-info-enum-class.cpp
+++ b/test/CodeGenCXX/debug-info-enum-class.cpp
@@ -12,4 +12,18 @@ D d;
// CHECK: metadata !{i32 {{.*}}, null, metadata !"A", metadata !4, i32 3, i64 32, i64 32, i32 0, i32 0, metadata !5, metadata !6, i32 0, i32 0} ; [ DW_TAG_enumeration_type ]
// CHECK: metadata !{i32 {{.*}}, null, metadata !"B", metadata !4, i32 4, i64 64, i64 64, i32 0, i32 0, metadata !9, metadata !10, i32 0, i32 0} ; [ DW_TAG_enumeration_type ]
// CHECK: metadata !{i32 {{.*}}, null, metadata !"C", metadata !4, i32 5, i64 32, i64 32, i32 0, i32 0, null, metadata !13, i32 0, i32 0} ; [ DW_TAG_enumeration_type ]
-// CHECK: metadata !{i32 {{.*}}, null, metadata !"D", metadata !4, i32 6, i64 16, i64 16, i32 0, i32 4, null, metadata !16, i32 0, i32 0} ; [ DW_TAG_enumeration_type ]
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"D", metadata !4, i32 6, i64 16, i64 16, i32 0, i32 4, null, null, i32 0} ; [ DW_TAG_enumeration_type ]
+
+namespace PR14029 {
+ // Make sure this doesn't crash/assert.
+ template <typename T> struct Test {
+ enum class Tag {
+ test = 0
+ };
+ Test() {
+ auto t = Tag::test;
+ }
+ Tag tag() const { return static_cast<Tag>(1); }
+ };
+ Test<int> t;
+}
diff --git a/test/CodeGenCXX/debug-info-fwd-ref.cpp b/test/CodeGenCXX/debug-info-fwd-ref.cpp
index e7f2ed19d79f..913503232051 100644
--- a/test/CodeGenCXX/debug-info-fwd-ref.cpp
+++ b/test/CodeGenCXX/debug-info-fwd-ref.cpp
@@ -16,11 +16,10 @@ int main(int argc, char** argv) {
return 0;
}
-// Make sure we have two DW_TAG_class_types for baz and bar and no forward
+// Make sure we have two DW_TAG_structure_types for baz and bar and no forward
// references.
-// FIXME: These should be struct types to match the declaration.
-// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !18, i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !21, i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_class_type ]
-// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !18, i32 0, null, null} ; [ DW_TAG_structure_type ]
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !21, i32 0, null, null} ; [ DW_TAG_structure_type ]
+// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_structure_type ]
+// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null} ; [ DW_TAG_structure_type ]
diff --git a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
new file mode 100644
index 000000000000..bdaf58c82703
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -g -fno-use-cxa-atexit -S -emit-llvm -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK-NOKEXT
+// RUN: %clang_cc1 %s -g -fno-use-cxa-atexit -fapple-kext -S -emit-llvm -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK-KEXT
+
+class A {
+ public:
+ A() {}
+ virtual ~A() {}
+};
+
+A glob;
+A array[2];
+
+void foo() {
+ static A stat;
+}
+
+// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 12] [local] [def] [__cxx_global_var_init]
+// 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 16] [local] [def] [__dtor__ZZ3foovE4stat]
+// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__I_a]
+
+// CHECK-KEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def] [_GLOBAL__D_a]
diff --git a/test/CodeGenCXX/debug-info-globalinit.cpp b/test/CodeGenCXX/debug-info-globalinit.cpp
index ff50fac4cfa3..b3891c148e3e 100644
--- a/test/CodeGenCXX/debug-info-globalinit.cpp
+++ b/test/CodeGenCXX/debug-info-globalinit.cpp
@@ -27,4 +27,4 @@ int main(void) {}
// CHECK-NOT: dbg
// CHECK: store i32 %[[C1]], i32* @_ZL1j, align 4
//
-// CHECK: ![[LINE]] = metadata !{i32 13, i32 16
+// CHECK: ![[LINE]] = metadata !{i32 13, i32
diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp
index a7abade3929f..612b6b500abc 100644
--- a/test/CodeGenCXX/debug-info-pubtypes.cpp
+++ b/test/CodeGenCXX/debug-info-pubtypes.cpp
@@ -1,5 +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: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S %s -o %t
// RUN: FileCheck %s < %t
// FIXME: This testcase shouldn't rely on assembly emission.
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
index f21718da5e67..6208c80aeb61 100644
--- a/test/CodeGenCXX/debug-info-template-member.cpp
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -17,5 +17,5 @@ private:
MyClass m;
// CHECK: metadata !{i32 {{.*}}, null, metadata !"MyClass", metadata {{.*}}, i32 {{.*}}, i64 8, i64 8, i32 0, i32 0, null, metadata [[C_MEM:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]]}
+// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]], metadata {{.*}}}
// CHECK: [[C_TEMP]] = metadata !{i32 {{.*}}, i32 0, metadata {{.*}}, metadata !"add<2>", metadata !"add<2>", metadata !"_ZN7MyClass3addILi2EEEii", metadata {{.*}}
diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp
index e5a9082c9c29..ffb1ca3849f1 100644
--- a/test/CodeGenCXX/debug-info-template-quals.cpp
+++ b/test/CodeGenCXX/debug-info-template-quals.cpp
@@ -20,4 +20,4 @@ void foo (const char *c) {
// CHECK: [[CH]] = metadata !{i32 {{.*}}, metadata !"char", {{.*}}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char]
// CHECK: metadata !{i32 {{.*}}, metadata !"_ZN12basic_stringIcE6assignEPKc", metadata !6, i32 7, metadata [[TYPE:.*]], i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, %struct.basic_string* (%struct.basic_string*, i8*)* @_ZN12basic_stringIcE6assignEPKc, null, metadata !18, metadata !1, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
// CHECK: [[TYPE]] = metadata !{i32 {{.*}}, null, metadata [[ARGS:.*]], i32 0, i32 0}
-// CHECK: [[ARGS]] = metadata !{metadata !15, metadata !23, metadata [[P]]}
+// CHECK: [[ARGS]] = metadata !{metadata !15, metadata !24, metadata [[P]]}
diff --git a/test/CodeGenCXX/debug-info-thunk.cpp b/test/CodeGenCXX/debug-info-thunk.cpp
new file mode 100644
index 000000000000..394ebd829188
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-thunk.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -g -S -emit-llvm -o - | FileCheck %s
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void f();
+};
+
+void C::f() { }
+
+// CHECK: [ DW_TAG_subprogram ] [line 15] [def] [_ZThn{{4|8}}_N1C1fEv]
diff --git a/test/CodeGenCXX/debug-info-user-def.cpp b/test/CodeGenCXX/debug-info-user-def.cpp
deleted file mode 100644
index ecd387870549..000000000000
--- a/test/CodeGenCXX/debug-info-user-def.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -std=c++11 %s -o - | FileCheck %s
-
-class A {
-};
-
-template <typename T> class B {
- T t;
-};
-
-A a;
-B<int> b;
-
-// Check that no subprograms are emitted into debug info.
-// CHECK-NOT: [ DW_TAG_subprogram ]
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
index 1c823990c1d9..430371f382c8 100644
--- a/test/CodeGenCXX/debug-lambda-expressions.cpp
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -31,39 +31,41 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// Back to D. -- 24
// CHECK: [[LAM_D:.*]] = metadata !{i32 {{.*}}, metadata [[D_FUNC]], metadata !"", metadata [[FILE]], i32 [[D_LINE]], i64 352, i64 32, i32 0, i32 0, null, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]}
+// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]}
// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 [[D_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 [[D_LINE]], i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
// CHECK: [[CON_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
// Back to C. -- 55
// CHECK: [[LAM_C:.*]] = metadata !{i32 {{.*}}, metadata [[C_FUNC]], metadata !"", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i32 0, i32 0, null, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]]}
+// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]}
// Ignoring the member type for now.
// CHECK: [[CAP_C]] = metadata !{i32 {{.*}}, metadata [[LAM_C]], metadata !"x", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ]
// CHECK: [[CON_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
// Back to B. -- 67
// CHECK: [[LAM_B:.*]] = metadata !{i32 {{.*}}, metadata [[B_FUNC]], metadata !"", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i32 0, i32 0, null, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]]}
+// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]}
// CHECK: [[CAP_B]] = metadata !{i32 {{.*}}, metadata [[LAM_B]], metadata !"x", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ]
// CHECK: [[CON_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
-
+// CHECK: [[DES_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
// Back to A. -- 78
// CHECK: [[LAM_A:.*]] = metadata !{i32 {{.*}}, metadata [[A_FUNC]], metadata !"", metadata [[FILE]], i32 [[A_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]]}
+// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]}
// CHECK: [[CON_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
-
+// CHECK: [[DES_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
// CVAR:
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ]
// CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}}
+// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
// VAR:
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ]
// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}}
+// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
diff --git a/test/CodeGenCXX/debug-lambda-this.cpp b/test/CodeGenCXX/debug-lambda-this.cpp
new file mode 100644
index 000000000000..7c37fbe35c6b
--- /dev/null
+++ b/test/CodeGenCXX/debug-lambda-this.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -g | FileCheck %s
+
+struct D {
+ D();
+ D(const D&);
+ int x;
+ int d(int x);
+};
+int D::d(int x) {
+ [=] {
+ return this->x;
+ }();
+}
+
+// CHECK: metadata !{i32 {{.*}}, metadata !"this", metadata !6, i32 11, i64 64, i64 64, i64 0, i32 1, metadata !37} ; [ DW_TAG_member ] [this] [line 11, size 64, align 64, offset 0] [private] [from ]
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 5a88f9f92437..7a91ca814637 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -113,12 +113,23 @@ namespace test4 {
// CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE
void global_delete_virtual(X *xp) {
- // CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])***
- // CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0
- // CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]]
- // CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]])
- // CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8*
- // CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind
+ // Load the offset-to-top from the vtable and apply it.
+ // This has to be done first because the dtor can mess it up.
+ // CHECK: [[T0:%.*]] = bitcast [[X:%.*]]* [[XP:%.*]] to i64**
+ // CHECK-NEXT: [[VTABLE:%.*]] = load i64** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i64* [[VTABLE]], i64 -2
+ // CHECK-NEXT: [[OFFSET:%.*]] = load i64* [[T0]], align 8
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[X]]* [[XP]] to i8*
+ // CHECK-NEXT: [[ALLOCATED:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+ // Load the complete-object destructor (not the deleting destructor)
+ // and call it.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[X:%.*]]* [[XP:%.*]] to void ([[X]]*)***
+ // CHECK-NEXT: [[VTABLE:%.*]] = load void ([[X]]*)*** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds void ([[X]]*)** [[VTABLE]], i64 0
+ // CHECK-NEXT: [[DTOR:%.*]] = load void ([[X]]*)** [[T0]]
+ // CHECK-NEXT: call void [[DTOR]]([[X]]* [[OBJ:%.*]])
+ // Call the global operator delete.
+ // CHECK-NEXT: call void @_ZdlPv(i8* [[ALLOCATED]]) nounwind
::delete xp;
}
}
diff --git a/test/CodeGenCXX/dependent-type-member-pointer.cpp b/test/CodeGenCXX/dependent-type-member-pointer.cpp
index 41bb5e29d58c..99b8ecd555c7 100644
--- a/test/CodeGenCXX/dependent-type-member-pointer.cpp
+++ b/test/CodeGenCXX/dependent-type-member-pointer.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
// PR7736
template <class scriptmemberptr> int InitMember(scriptmemberptr);
diff --git a/test/CodeGenCXX/destructor-debug-info.cpp b/test/CodeGenCXX/destructor-debug-info.cpp
index 385c86d9be19..f2e2a39bd6b6 100644
--- a/test/CodeGenCXX/destructor-debug-info.cpp
+++ b/test/CodeGenCXX/destructor-debug-info.cpp
@@ -19,4 +19,4 @@ void foo() {
}
}
// Check there is a line number entry for line 19 where b1 is destructed.
-// CHECK: i32 19, i32 3, metadata
+// CHECK: i32 19, i32 0, metadata
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
index 634bf84b416d..40f3cada7d46 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 %s -emit-llvm -o - | FileCheck %s
namespace Test1 {
struct A {
@@ -131,8 +131,7 @@ namespace Test7 {
// CHECK: alloca
// CHECK-NEXT: store
// CHECK-NEXT: load
- // CHECK-NEXT: bitcast
- // CHECK-NEXT: call {{.*}} @_ZN5Test73zed1fEv
+ // CHECK-NEXT: call i32 @_ZN5Test73zed1fEv
// CHECK-NEXT: ret
return static_cast<bar*>(z)->f();
}
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index 7ef4864c8367..52f1cd3fa236 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s
struct A {
virtual void f();
@@ -66,7 +66,7 @@ namespace test2 {
void f(bar *b) {
// CHECK: call void @_ZN5test23foo1fEv
- // CHECK: call void @_ZN5test23fooD1Ev
+ // CHECK: call %"struct.test2::foo"* @_ZN5test23fooD1Ev
b->foo::f();
b->foo::~foo();
}
diff --git a/test/CodeGenCXX/enum.cpp b/test/CodeGenCXX/enum.cpp
index cfcd264bd347..3985e96ab9fe 100644
--- a/test/CodeGenCXX/enum.cpp
+++ b/test/CodeGenCXX/enum.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
enum A { a } __attribute((packed));
int func(A x) { return x==a; }
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index 8c20c9e9ce21..723e8d1393c1 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -365,6 +365,7 @@ namespace test7 {
// CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_(
// CHECK: store i1 false, i1* [[OUTER_NEW]]
// CHECK: phi
+ // CHECK-NEXT: store [[B]]*
// Destroy the inner A object.
// CHECK-NEXT: load i1* [[INNER_A]]
diff --git a/test/CodeGenCXX/fastcall.cpp b/test/CodeGenCXX/fastcall.cpp
new file mode 100644
index 000000000000..c0a910667274
--- /dev/null
+++ b/test/CodeGenCXX/fastcall.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+void __attribute__((fastcall)) foo1(int &y);
+void bar1(int &y) {
+ // CHECK: define void @_Z4bar1Ri
+ // CHECK: call x86_fastcallcc void @_Z4foo1Ri(i32* inreg %
+ foo1(y);
+}
+
+struct S1 {
+ int x;
+ S1(const S1 &y);
+};
+
+void __attribute__((fastcall)) foo2(S1 a, int b);
+void bar2(S1 a, int b) {
+ // CHECK: 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 0f35dda737fe..926fe445a5ba 100644
--- a/test/CodeGenCXX/for-range.cpp
+++ b/test/CodeGenCXX/for-range.cpp
@@ -27,10 +27,8 @@ struct D {
B *end();
};
-namespace std {
- B *begin(C&);
- B *end(C&);
-}
+B *begin(C&);
+B *end(C&);
extern B array[5];
@@ -42,7 +40,7 @@ void for_array() {
// CHECK-NOT: 5begin
// CHECK-NOT: 3end
// CHECK: getelementptr {{.*}}, i32 0
- // CHECK: getelementptr {{.*}}, i64 5
+ // CHECK: getelementptr {{.*}}, i64 1, i64 0
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
@@ -69,8 +67,8 @@ void for_range() {
A a;
for (B b : C()) {
// CHECK: call void @_ZN1CC1Ev(
- // CHECK: = call %struct.B* @_ZSt5beginR1C(
- // CHECK: = call %struct.B* @_ZSt3endR1C(
+ // CHECK: = call %struct.B* @_Z5beginR1C(
+ // CHECK: = call %struct.B* @_Z3endR1C(
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
index 8bc84a534b36..8a3a422e0ba8 100644
--- a/test/CodeGenCXX/implicit-copy-constructor.cpp
+++ b/test/CodeGenCXX/implicit-copy-constructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -std=c++11 | FileCheck %s
struct A {
A();
@@ -80,3 +80,29 @@ namespace test3 {
y = x;
}
}
+
+namespace test4 {
+ // When determining whether to implement an array copy as a memcpy, look at
+ // whether the *selected* constructor is trivial.
+ struct S {
+ int arr[5][5];
+ S(S &);
+ S(const S &) = default;
+ };
+ // CHECK: @_ZN5test42f1
+ void f1(S a) {
+ // CHECK-NOT: memcpy
+ // CHECK: call void @_ZN5test41SC1ERS0_
+ // CHECK-NOT: memcpy
+ S b(a);
+ // CHECK: }
+ }
+ // CHECK: @_ZN5test42f2
+ void f2(const S a) {
+ // CHECK-NOT: call void @_ZN5test41SC1ERS0_
+ // CHECK: memcpy
+ // CHECK-NOT: call void @_ZN5test41SC1ERS0_
+ S b(a);
+ // CHECK: }
+ }
+}
diff --git a/test/CodeGenCXX/incomplete-types.cpp b/test/CodeGenCXX/incomplete-types.cpp
index 1d4f430e5cb5..802ed4628d9e 100644
--- a/test/CodeGenCXX/incomplete-types.cpp
+++ b/test/CodeGenCXX/incomplete-types.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// expected-no-diagnostics
// PR5489
template<typename E>
diff --git a/test/CodeGenCXX/init-priority-attr.cpp b/test/CodeGenCXX/init-priority-attr.cpp
new file mode 100644
index 000000000000..ef9343ceade9
--- /dev/null
+++ b/test/CodeGenCXX/init-priority-attr.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// PR
+
+void foo(int);
+
+class A {
+public:
+ A() { foo(1); }
+};
+
+class A1 {
+public:
+ A1() { foo(2); }
+};
+
+class B {
+public:
+ B() { foo(3); }
+};
+
+class C {
+public:
+ static A a;
+ C() { foo(4); }
+};
+
+
+A C::a = A();
+
+// CHECK: @llvm.global_ctors = appending global [3 x { i32, void ()* }] [{ i32, void ()* } { i32 200, void ()* @_GLOBAL__I_000200 }, { i32, void ()* } { i32 300, void ()* @_GLOBAL__I_000300 }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
+
+// CHECK: _GLOBAL__I_000200()
+// CHECK_NEXT: _Z3fooi(i32 3)
+
+// CHECK: _GLOBAL__I_000300()
+// CHECK_NEXT: _Z3fooi(i32 2)
+// CHECK_NEXT: _Z3fooi(i32 1)
+
+// CHECK: _GLOBAL__I_a()
+// CHECK_NEXT: _Z3fooi(i32 1)
+// CHECK_NEXT: _Z3fooi(i32 4)
+
+C c;
+A1 a1 __attribute__((init_priority (300)));
+A a __attribute__((init_priority (300)));
+B b __attribute__((init_priority (200)));
diff --git a/test/CodeGenCXX/instantiate-init-list.cpp b/test/CodeGenCXX/instantiate-init-list.cpp
index 49c6f51c7751..e498d2476c01 100644
--- a/test/CodeGenCXX/instantiate-init-list.cpp
+++ b/test/CodeGenCXX/instantiate-init-list.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// expected-no-diagnostics
struct F {
void (*x)();
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index e872cc494bc6..cee4f172a000 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -71,6 +71,15 @@ void f() {
int (*fp)(int, int) = [](int x, int y){ return x + y; };
}
+static int k;
+int g() {
+ int &r = k;
+ // CHECK: define internal i32 @"_ZZ1gvENK3$_6clEv"(
+ // CHECK-NOT: }
+ // CHECK: load i32* @_ZL1k,
+ return [] { return r; } ();
+};
+
// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index 30da4fbbcdf9..2d7a883526db 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -190,4 +190,11 @@ namespace test4 {
// CHECK: void @_ZN5test43tf3INS_1XEEEvDTnw_T_ilLi1EEE
template void tf3<X>(X*);
+
+}
+
+namespace test5 {
+ template <typename T> void a(decltype(noexcept(T()))) {}
+ template void a<int>(decltype(noexcept(int())));
+ // CHECK: void @_ZN5test51aIiEEvDTnxcvT__EE(
}
diff --git a/test/CodeGenCXX/mangle-extern-local.cpp b/test/CodeGenCXX/mangle-extern-local.cpp
index ed91da4e2e37..1394c8f2a132 100644
--- a/test/CodeGenCXX/mangle-extern-local.cpp
+++ b/test/CodeGenCXX/mangle-extern-local.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - | FileCheck %s
// CHECK: @var1 = external global i32
// CHECK: @_ZN1N4var2E = external global i32
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
index 16ddf4838ea7..0bd5ad2a02ca 100644
--- a/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -172,6 +172,33 @@ template<typename...T> int PR12917<T...>::n[3] = {
PR12917<int, char, double> pr12917;
int *pr12917_p = PR12917<int, int>::n;
+namespace std {
+ struct type_info;
+}
+namespace PR12123 {
+ struct A { virtual ~A(); } g;
+ struct B {
+ void f(const std::type_info& x = typeid([]()->A& { return g; }()));
+ void h();
+ };
+ void B::h() { f(); }
+}
+// CHECK: define linkonce_odr %"struct.PR12123::A"* @_ZZN7PR121231B1fERKSt9type_infoEd_NKUlvE_clEv
+
+namespace PR12808 {
+ template <typename> struct B {
+ int a;
+ template <typename L> constexpr B(L&& x) : a(x()) { }
+ };
+ template <typename> void b(int) {
+ [&]{ (void)B<int>([&]{ return 1; }); }();
+ }
+ void f() {
+ b<int>(1);
+ }
+ // CHECK: define linkonce_odr void @_ZZN7PR128081bIiEEviENKS0_IiEUlvE_clEv
+ // CHECK: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKS0_IiEUlvE_clEvENKUlvE_clEv
+}
// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
new file mode 100644
index 000000000000..0ac9b3f121f3
--- /dev/null
+++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+void foo(const unsigned int) {}
+// CHECK: "\01?foo@@YAXI@Z"
+
+void foo(const double) {}
+// CHECK: "\01?foo@@YAXN@Z"
+
+void bar(const volatile double) {}
+// CHECK: "\01?bar@@YAXN@Z"
+
+void foo_pad(char * x) {}
+// CHECK: "\01?foo_pad@@YAXPAD@Z"
+
+void foo_pbd(const char * x) {}
+// CHECK: "\01?foo_pbd@@YAXPBD@Z"
+
+void foo_pcd(volatile char * x) {}
+// CHECK: "\01?foo_pcd@@YAXPCD@Z"
+
+void foo_qad(char * const x) {}
+// CHECK: "\01?foo_qad@@YAXQAD@Z"
+
+void foo_rad(char * volatile x) {}
+// CHECK: "\01?foo_rad@@YAXRAD@Z"
+
+void foo_sad(char * const volatile x) {}
+// CHECK: "\01?foo_sad@@YAXSAD@Z"
+
+void foo_papad(char ** x) {}
+// CHECK: "\01?foo_papad@@YAXPAPAD@Z"
+
+void foo_papbd(char const ** x) {}
+// CHECK: "\01?foo_papbd@@YAXPAPBD@Z"
+
+void foo_papcd(char volatile ** x) {}
+// CHECK: "\01?foo_papcd@@YAXPAPCD@Z"
+
+void foo_pbqad(char * const* x) {}
+// CHECK: "\01?foo_pbqad@@YAXPBQAD@Z"
+
+void foo_pcrad(char * volatile* x) {}
+// CHECK: "\01?foo_pcrad@@YAXPCRAD@Z"
+
+void foo_qapad(char ** const x) {}
+// CHECK: "\01?foo_qapad@@YAXQAPAD@Z"
+
+void foo_rapad(char ** volatile x) {}
+// CHECK: "\01?foo_rapad@@YAXRAPAD@Z"
+
+void foo_pbqbd(const char * const* x) {}
+// CHECK: "\01?foo_pbqbd@@YAXPBQBD@Z"
+
+void foo_pbqcd(volatile char * const* x) {}
+// CHECK: "\01?foo_pbqcd@@YAXPBQCD@Z"
+
+void foo_pcrbd(const char * volatile* x) {}
+// CHECK: "\01?foo_pcrbd@@YAXPCRBD@Z"
+
+void foo_pcrcd(volatile char * volatile* x) {}
+// CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z"
+
+typedef double Vector[3];
+
+void foo(Vector*) {}
+// CHECK: "\01?foo@@YAXPAY02N@Z"
+
+void foo(Vector) {}
+// CHECK: "\01?foo@@YAXQAN@Z"
+
+void foo_const(const Vector) {}
+// CHECK: "\01?foo_const@@YAXQBN@Z"
+
+void foo_volatile(volatile Vector) {}
+// CHECK: "\01?foo_volatile@@YAXQCN@Z"
+
+void foo(Vector*, const Vector, const double) {}
+// CHECK: "\01?foo@@YAXPAY02NQBNN@Z"
diff --git a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp
index a5d03b343526..63bc4a9eb3c6 100644
--- a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp
+++ b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp
@@ -167,7 +167,4 @@ function_pointer* g3() { return 0; }
// CHECK: "\01?g3@@YAPAP6AHH@ZXZ"
const function_pointer* g4() { return 0; }
-// The mangling of g4 is currently "\01?g4@@YAPQ6AHH@ZXZ" which is wrong.
-// This looks related to http://llvm.org/PR13444
-// FIXME: replace CHECK-NOT with CHECK once it is fixed.
-// CHECK-NOT: "\01?g4@@YAPBQ6AHH@ZXZ"
+// CHECK: "\01?g4@@YAPBQ6AHH@ZXZ"
diff --git a/test/CodeGenCXX/mangle-ms-template-callback.cpp b/test/CodeGenCXX/mangle-ms-template-callback.cpp
new file mode 100644
index 000000000000..687814875132
--- /dev/null
+++ b/test/CodeGenCXX/mangle-ms-template-callback.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+template<typename Signature>
+class C;
+
+template<typename Ret>
+class C<Ret(void)> {};
+typedef C<void(void)> C0;
+
+template<typename Ret, typename Arg1>
+class C<Ret(Arg1)> {};
+
+template<typename Ret, typename Arg1, typename Arg2>
+class C<Ret(Arg1, Arg2)> {};
+
+C0 callback_void;
+// CHECK: "\01?callback_void@@3V?$C@$$A6AXXZ@@A"
+
+volatile C0 callback_void_volatile;
+// CHECK: "\01?callback_void_volatile@@3V?$C@$$A6AXXZ@@C"
+
+class Type {};
+
+C<int(void)> callback_int;
+// CHECK: "\01?callback_int@@3V?$C@$$A6AHXZ@@A"
+C<Type(void)> callback_Type;
+// CHECK: "\01?callback_Type@@3V?$C@$$A6A?AVType@@XZ@@A"
+
+C<void(int)> callback_void_int;
+// CHECK: "\01?callback_void_int@@3V?$C@$$A6AXH@Z@@A"
+C<int(int)> callback_int_int;
+// CHECK: "\01?callback_int_int@@3V?$C@$$A6AHH@Z@@A"
+C<void(Type)> callback_void_Type;
+// CHECK: "\01?callback_void_Type@@3V?$C@$$A6AXVType@@@Z@@A"
+
+void foo(C0 c) {}
+// CHECK: "\01?foo@@YAXV?$C@$$A6AXXZ@@@Z"
+
+// Here be dragons!
+// Let's face the magic of template partial specialization...
+
+void function(C<void(void)>) {}
+// CHECK: "\01?function@@YAXV?$C@$$A6AXXZ@@@Z"
+
+template<typename Ret> class C<Ret(*)(void)> {};
+void function_pointer(C<void(*)(void)>) {}
+// CHECK: "\01?function_pointer@@YAXV?$C@P6AXXZ@@@Z"
+
+// Block equivalent to the previous definitions.
+template<typename Ret> class C<Ret(^)(void)> {};
+void block(C<void(^)(void)>) {}
+// CHECK: "\01?block@@YAXV?$C@P_EAXXZ@@@Z"
+// FYI blocks are not present in MSVS, so we're free to choose the spec.
+
+template<typename T> class C<void (T::*)(void)> {};
+class Z {
+ public:
+ void method() {}
+};
+void member_pointer(C<void (Z::*)(void)>) {}
+// CHECK: "\01?member_pointer@@YAXV?$C@P8Z@@AEXXZ@@@Z"
+
+template<typename T> void bar(T) {}
+
+void call_bar() {
+ bar<int (*)(int)>(0);
+// CHECK: "\01??$bar@P6AHH@Z@@YAXP6AHH@Z@Z"
+
+ bar<int (^)(int)>(0);
+// CHECK: "\01??$bar@P_EAHH@Z@@YAXP_EAHH@Z@Z"
+// FYI blocks are not present in MSVS, so we're free to choose the spec.
+}
diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp
index 977ef353dabc..e16fe936bc2e 100644
--- a/test/CodeGenCXX/mangle-ms-templates.cpp
+++ b/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -48,12 +48,24 @@ void template_mangling() {
// CHECK: call {{.*}} @"\01??0?$BoolTemplate@$00@@QAE@XZ"
// CHECK: call {{.*}} @"\01??$Foo@H@?$BoolTemplate@$00@@QAEXH@Z"
+ IntTemplate<0> zero;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0A@@@QAE@XZ"
+
IntTemplate<5> five;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$04@@QAE@XZ"
IntTemplate<11> eleven;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0L@@@QAE@XZ"
+ IntTemplate<256> _256;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0BAA@@@QAE@XZ"
+
+ IntTemplate<513> _513;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0CAB@@@QAE@XZ"
+
+ IntTemplate<1026> _1026;
+// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0EAC@@@QAE@XZ"
+
IntTemplate<65535> ffff;
// CHECK: call {{.*}} @"\01??0?$IntTemplate@$0PPPP@@@QAE@XZ"
}
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index f392c1701edd..0edb4b4339aa 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -1,4 +1,5 @@
// 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"
@@ -7,16 +8,17 @@
// CHECK: @"\01?e@foo@@1JC"
// CHECK: @"\01?f@foo@@2DD"
// CHECK: @"\01?g@bar@@2HA"
-// CHECK: @"\01?h@@3QAHA"
+// 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"
-// FIXME: The following three tests currently fail, see PR13182.
+// FIXME: The following three tests currently fail, see http://llvm.org/PR13182
// Replace "CHECK-NOT" with "CHECK" when it is fixed.
-// CHECK-NOT: @"\01?color2@@3QBNB"
// CHECK-NOT: @"\01?color3@@3QAY02$$CBNA"
// CHECK-NOT: @"\01?color4@@3QAY02$$CBNA"
@@ -87,7 +89,8 @@ const volatile char foo::f = 'C';
int bar::g;
-extern int * const h = &a;
+extern int * const h1 = &a;
+extern const int * const h2 = &a;
int i[10][20];
@@ -107,6 +110,7 @@ bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) {
}
// CHECK: @"\01?alpha@@YGXMN@Z"
+// X64: @"\01?alpha@@YAXMN@Z"
// Make sure tag-type mangling works.
void gamma(class foo, struct bar, union baz, enum quux) {}
@@ -128,6 +132,10 @@ void zeta(int (*)(int, int)) {}
void eta(int (^)(int, int)) {}
// CHECK: @"\01?eta@@YAXP_EAHHH@Z@Z"
+typedef int theta_arg(int,int);
+void theta(theta_arg^ block) {}
+// CHECK: @"\01?theta@@YAXP_EAHHH@Z@Z"
+
void operator_new_delete() {
char *ptr = new char;
// CHECK: @"\01??2@YAPAXI@Z"
@@ -147,7 +155,7 @@ void (redundant_parens)();
void redundant_parens_use() { redundant_parens(); }
// CHECK: @"\01?redundant_parens@@YAXXZ"
-// PR13182, PR13047
+// PR13047
typedef double RGB[3];
RGB color1;
extern const RGB color2 = {};
@@ -162,3 +170,24 @@ E fooE() { return E(); }
class X {};
// CHECK: "\01?fooX@@YA?AVX@@XZ"
X fooX() { return X(); }
+
+namespace PR13182 {
+ extern char s0[];
+ // CHECK: @"\01?s0@PR13182@@3PADA"
+ extern char s1[42];
+ // CHECK: @"\01?s1@PR13182@@3PADA"
+ extern const char s2[];
+ // CHECK: @"\01?s2@PR13182@@3QBDB"
+ extern const char s3[42];
+ // CHECK: @"\01?s3@PR13182@@3QBDB"
+ extern volatile char s4[];
+ // CHECK: @"\01?s4@PR13182@@3RCDC"
+ extern const volatile char s5[];
+ // CHECK: @"\01?s5@PR13182@@3SDDD"
+ extern const char* const* s6;
+ // CHECK: @"\01?s6@PR13182@@3PBQBDB"
+
+ char foo() {
+ return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0];
+ }
+}
diff --git a/test/CodeGenCXX/mangle-nullptr-arg.cpp b/test/CodeGenCXX/mangle-nullptr-arg.cpp
index 393de0b0ece9..07bf52fc9067 100644
--- a/test/CodeGenCXX/mangle-nullptr-arg.cpp
+++ b/test/CodeGenCXX/mangle-nullptr-arg.cpp
@@ -11,3 +11,6 @@ template<int X::*pm> struct PM {};
// CHECK: define void @_Z5test22PMILM1Xi0EE
void test2(PM<nullptr>) { }
+// CHECK: define void @_Z5test316DependentTypePtrIPiLS0_0EE
+template<typename T, T x> struct DependentTypePtr {};
+void test3(DependentTypePtr<int*,nullptr>) { }
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index 05c3a5851e4a..15a85c7bd2e5 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -162,11 +162,23 @@ namespace test12 {
void use() {
// CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
test<int(), &f>();
- // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv(
+ // CHECK: define internal void @_ZN6test124testIRFivELZNS_L1fEvEEEvv(
test<int(&)(), f>();
// CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
test<const int*, &n>();
- // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv(
+ // CHECK: define internal void @_ZN6test124testIRKiLZNS_L1nEEEEvv(
test<const int&, n>();
}
}
+
+// rdar://problem/12072531
+// Test the boundary condition of minimal signed integers.
+namespace test13 {
+ template <char c> char returnChar() { return c; }
+ template char returnChar<-128>();
+ // CHECK: @_ZN6test1310returnCharILcn128EEEcv()
+
+ template <short s> short returnShort() { return s; }
+ template short returnShort<-32768>();
+ // CHECK: @_ZN6test1311returnShortILsn32768EEEsv()
+}
diff --git a/test/CodeGenCXX/mangle-valist.cpp b/test/CodeGenCXX/mangle-valist.cpp
new file mode 100644
index 000000000000..73fd58e75e8a
--- /dev/null
+++ b/test/CodeGenCXX/mangle-valist.cpp
@@ -0,0 +1,44 @@
+#include "stdarg.h"
+
+namespace test1 {
+ void test1(const char *fmt, va_list ap) {
+ }
+}
+
+class Test2 {
+public:
+ void test2(const char *fmt, va_list ap);
+};
+
+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
+// 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
+// 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
+// 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
+// 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
+// CHECK-MANGLE-X86-64: @_ZN5test15test1EPKcP13__va_list_tag
+// CHECK-MANGLE-X86-64: @_ZN5Test25test2EPKcP13__va_list_tag
diff --git a/test/CodeGenCXX/member-alignment.cpp b/test/CodeGenCXX/member-alignment.cpp
index 8e120f712507..78026d4e0419 100644
--- a/test/CodeGenCXX/member-alignment.cpp
+++ b/test/CodeGenCXX/member-alignment.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
-// XFAIL: arm,powerpc
// rdar://7268289
diff --git a/test/CodeGenCXX/member-call-parens.cpp b/test/CodeGenCXX/member-call-parens.cpp
index 2054137fe941..3def43ebc05d 100644
--- a/test/CodeGenCXX/member-call-parens.cpp
+++ b/test/CodeGenCXX/member-call-parens.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
struct A { int a(); };
typedef int B;
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
index b95763c0ffac..1310eb08d3d1 100644
--- a/test/CodeGenCXX/member-functions.cpp
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -35,6 +35,9 @@ struct S {
static void g() { }
static void f();
+
+ // RUN: grep "define linkonce_odr void @_ZN1S1vEv.*unnamed_addr" %t
+ virtual void v() {}
};
// RUN: grep "define void @_ZN1S1fEv" %t
diff --git a/test/CodeGenCXX/member-init-assignment.cpp b/test/CodeGenCXX/member-init-assignment.cpp
index 84c4a36fe2db..acc708467002 100644
--- a/test/CodeGenCXX/member-init-assignment.cpp
+++ b/test/CodeGenCXX/member-init-assignment.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - | FileCheck %s
// PR7291
struct Foo {
diff --git a/test/CodeGenCXX/member-init-struct.cpp b/test/CodeGenCXX/member-init-struct.cpp
index 688d92d74b8e..d509b0ebac28 100644
--- a/test/CodeGenCXX/member-init-struct.cpp
+++ b/test/CodeGenCXX/member-init-struct.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// expected-no-diagnostics
struct A {int a;};
struct B {float a;};
diff --git a/test/CodeGenCXX/member-init-union.cpp b/test/CodeGenCXX/member-init-union.cpp
index 2c50e18b6ffa..be171a365b01 100644
--- a/test/CodeGenCXX/member-init-union.cpp
+++ b/test/CodeGenCXX/member-init-union.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// expected-no-diagnostics
union x {
int a;
diff --git a/test/CodeGenCXX/microsoft-abi-constructors.cpp b/test/CodeGenCXX/microsoft-abi-constructors.cpp
index ac27f13308d8..89731ff38e97 100644
--- a/test/CodeGenCXX/microsoft-abi-constructors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-constructors.cpp
@@ -9,13 +9,16 @@ class A {
void no_contstructor_destructor_infinite_recursion() {
A a;
-// Make sure that the constructor doesn't call itself:
-// CHECK: define {{.*}} @"\01??0A@@QAE@XZ"
-// CHECK-NOT: call void @"\01??0A@@QAE@XZ"
-// CHECK: ret
+// CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"(%class.A* %this)
+// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %class.A*, align 4
+// CHECK-NEXT: store %class.A* %this, %class.A** [[THIS_ADDR]], align 4
+// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %class.A** [[THIS_ADDR]]
+// CHECK-NEXT: ret %class.A* [[T1]]
+// CHECK-NEXT: }
// Make sure that the destructor doesn't call itself:
// CHECK: define {{.*}} @"\01??1A@@QAE@XZ"
// CHECK-NOT: call void @"\01??1A@@QAE@XZ"
// CHECK: ret
}
+
diff --git a/test/CodeGenCXX/microsoft-abi-default-cc.cpp b/test/CodeGenCXX/microsoft-abi-default-cc.cpp
new file mode 100644
index 000000000000..d0d25ce5efb1
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck -check-prefix GCABI %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -DMS_ABI -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck -check-prefix MSABI %s
+
+#ifdef MS_ABI
+# define METHOD_CC __thiscall
+#else
+# define METHOD_CC __attribute__ ((cdecl))
+#endif
+
+// Test that it's OK to have multiple function declarations with the default CC
+// both mentioned explicitly and implied.
+void foo();
+void __cdecl foo();
+void __cdecl foo() {}
+// GCABI: define void @_Z3foov()
+// MSABI: define void @"\01?foo@@YAXXZ"
+
+void __cdecl bar();
+void bar();
+void bar() {}
+// GCABI: define void @_Z3barv()
+// MSABI: define void @"\01?bar@@YAXXZ"
+
+// Test that it's OK to mark either the method declaration or method definition
+// with a default CC explicitly.
+class A {
+public:
+ void baz();
+ void METHOD_CC qux();
+
+ void static_baz();
+ void __cdecl static_qux();
+};
+
+void METHOD_CC A::baz() {}
+// GCABI: define void @_ZN1A3bazEv
+// MSABI: define x86_thiscallcc void @"\01?baz@A@@QAEXXZ"
+void A::qux() {}
+// GCABI: define void @_ZN1A3quxEv
+// MSABI: define x86_thiscallcc void @"\01?qux@A@@QAEXXZ"
+
+void __cdecl static_baz() {}
+// GCABI: define void @_Z10static_bazv
+// MSABI: define void @"\01?static_baz@@YAXXZ"
+void static_qux() {}
+// GCABI: define void @_Z10static_quxv
+// MSABI: define void @"\01?static_qux@@YAXXZ"
diff --git a/test/CodeGenCXX/microsoft-abi-methods.cpp b/test/CodeGenCXX/microsoft-abi-methods.cpp
index 6b7f00495d2b..c996ba5b8473 100644
--- a/test/CodeGenCXX/microsoft-abi-methods.cpp
+++ b/test/CodeGenCXX/microsoft-abi-methods.cpp
@@ -71,8 +71,8 @@ void constructors() {
Child c;
// Make sure that the Base constructor call in the Child constructor uses
// the right calling convention:
-// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Child@@QAE@XZ"
-// CHECK: call x86_thiscallcc void @"\01??0Base@@QAE@XZ"
+// CHECK: define linkonce_odr x86_thiscallcc %class.Child* @"\01??0Child@@QAE@XZ"
+// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ"
// CHECK: ret
// Make sure that the Base destructor call in the Child denstructor uses
@@ -85,5 +85,5 @@ void constructors() {
// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1Base@@QAE@XZ"
// Make sure that the Base constructor definition uses the right CC:
-// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Base@@QAE@XZ"
+// CHECK: define linkonce_odr x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ"
}
diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index d8b789943a43..448f1eeeb91f 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -6,7 +6,7 @@ struct S {
} s;
// CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind
-// CHECK: call x86_thiscallcc void @"\01??0S@@QAE@XZ"
+// 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: ret void
@@ -34,11 +34,11 @@ void force_usage() {
}
// CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind
-// CHECK: call x86_thiscallcc void @"\01??0A@@QAE@XZ"
+// 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: ret void
-// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0A@@QAE@XZ"
+// CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ"
diff --git a/test/CodeGenCXX/microsoft-interface.cpp b/test/CodeGenCXX/microsoft-interface.cpp
new file mode 100644
index 000000000000..0b44bab73854
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-interface.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++11 -fms-extensions -Wno-microsoft -triple=i386-pc-win32 -emit-llvm %s -o - | FileCheck %s
+
+__interface I {
+ int test() {
+ return 1;
+ }
+};
+
+struct S : I {
+ virtual int test() override {
+ return I::test();
+ }
+};
+
+int fn() {
+ S s;
+ return s.test();
+}
+
+// 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: 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: call void @_ZN1SC2Ev(%struct.S* %{{[.0-9A-Z_a-z]+}})
+
+// CHECK: 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: ret i32 1
+
+// CHECK: 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: 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*)
diff --git a/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp b/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
new file mode 100644
index 000000000000..4f68aa34772c
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-uuidof-unsupported-target.cpp
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 000000000000..8eeb4490ac11
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-uuidof.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
+
+typedef struct _GUID
+{
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+} GUID;
+
+struct __declspec(uuid("12345678-1234-1234-1234-1234567890ab")) S1 { } s1;
+struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { };
+
+// This gets initialized in a static initializer.
+// CHECK: @g = global %struct._GUID zeroinitializer, align 4
+GUID g = __uuidof(S1);
+
+// 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
+const GUID& gr = __uuidof(S1);
+
+// CHECK: @gp = global %struct._GUID* @__uuid_12345678-1234-1234-1234-1234567890ab, align 4
+const GUID* gp = &__uuidof(S1);
+
+// Special case: _uuidof(0)
+// CHECK: @zeroiid = constant %struct._GUID* @__uuid_00000000-0000-0000-0000-000000000000, 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!" }
+
+// 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)
+
+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: [[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)
+ 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)
+ 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)
+ GUID s1_3 = __uuidof(s1);
+}
+
+void gun() {
+ // CHECK: %s2_1 = alloca %struct._GUID, align 4
+ // CHECK: %s2_2 = alloca %struct._GUID, align 4
+ // 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
+ const GUID& r = __uuidof(S2);
+ // CHECK: store %struct._GUID* @__uuid_87654321-4321-4321-4321-ba0987654321, %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
+ const GUID& zeroiid = __uuidof(0);
+}
diff --git a/test/CodeGenCXX/new-operator-phi.cpp b/test/CodeGenCXX/new-operator-phi.cpp
index 49859acf4fa6..641734d223ad 100644
--- a/test/CodeGenCXX/new-operator-phi.cpp
+++ b/test/CodeGenCXX/new-operator-phi.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
// PR5454
#include <stddef.h>
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 8d9f641ba1cc..e0523909a3db 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -250,3 +250,13 @@ namespace PR11757 {
// CHECK-NEXT: call void @_ZN7PR117571XC1Ev({{.*}}* [[CASTED]])
// CHECK-NEXT: ret {{.*}} [[CASTED]]
}
+
+namespace PR13380 {
+ struct A { A() {} };
+ struct B : public A { int x; };
+ // CHECK: 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](); }
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 2feaf682413c..8ff7dd7d0909 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
// Test code generation for the named return value optimization.
class X {
diff --git a/test/CodeGenCXX/override-layout.cpp b/test/CodeGenCXX/override-layout.cpp
index d432885c5848..aba4c9179a6d 100644
--- a/test/CodeGenCXX/override-layout.cpp
+++ b/test/CodeGenCXX/override-layout.cpp
@@ -1,7 +1,7 @@
// 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: diff %t.before %t.after
+// RUN: diff -u %t.before %t.after
// RUN: FileCheck %s < %t.after
// If not explicitly disabled, set PACKED to the packed attribute.
@@ -54,11 +54,24 @@ struct PACKED X4 {
X4();
};
+// CHECK: Type: struct X5
+struct PACKED X5 {
+ union {
+ long a;
+ long b;
+ };
+ short l;
+ short r;
+};
+
void use_structs() {
X0 x0s[sizeof(X0)];
X1 x1s[sizeof(X1)];
X2 x2s[sizeof(X2)];
X3 x3s[sizeof(X3)];
X4 x4s[sizeof(X4)];
+ X5 x5s[sizeof(X5)];
x4s[1].a = 1;
+ x5s[1].a = 17;
}
+
diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp
index a9920c073388..f3f2ec417e39 100644
--- a/test/CodeGenCXX/pr12251.cpp
+++ b/test/CodeGenCXX/pr12251.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -fstrict-enums -std=c++11 -o - | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -std=c++11 -o - | FileCheck --check-prefix=NO-STRICT-ENUMS %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -O1 -relaxed-aliasing -fstrict-enums -std=c++11 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -O1 -relaxed-aliasing -std=c++11 -o - | FileCheck --check-prefix=NO-STRICT-ENUMS %s
bool f(bool *x) {
return *x;
diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp
index 11a38c1d5fb9..0640d4244eba 100644
--- a/test/CodeGenCXX/pragma-visibility.cpp
+++ b/test/CodeGenCXX/pragma-visibility.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
#pragma GCC visibility push(hidden)
struct x {
diff --git a/test/CodeGenCXX/reference-bind-default-argument.cpp b/test/CodeGenCXX/reference-bind-default-argument.cpp
index acce962b1953..5cf279f62a18 100644
--- a/test/CodeGenCXX/reference-bind-default-argument.cpp
+++ b/test/CodeGenCXX/reference-bind-default-argument.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// expected-no-diagnostics
struct A {};
struct B : A {};
diff --git a/test/CodeGenCXX/reference-init.cpp b/test/CodeGenCXX/reference-init.cpp
index 9469c84eb5d0..d47b1f37489c 100644
--- a/test/CodeGenCXX/reference-init.cpp
+++ b/test/CodeGenCXX/reference-init.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
struct XPTParamDescriptor {};
struct nsXPTParamInfo {
diff --git a/test/CodeGenCXX/regparm.cpp b/test/CodeGenCXX/regparm.cpp
index f0ebd2be4167..2196c798bf3e 100644
--- a/test/CodeGenCXX/regparm.cpp
+++ b/test/CodeGenCXX/regparm.cpp
@@ -4,3 +4,35 @@
// CHECK: _Z3fooRi(i32* inreg
void __attribute__ ((regparm (1))) foo(int &a) {
}
+
+struct S1 {
+ int x;
+ S1(const S1 &y);
+};
+
+void __attribute__((regparm(3))) foo2(S1 a, int b);
+// CHECK: declare void @_Z4foo22S1i(%struct.S1* inreg, i32 inreg)
+void bar2(S1 a, int b) {
+ foo2(a, b);
+}
+
+struct S2 {
+ int x;
+};
+
+void __attribute__((regparm(3))) foo3(struct S2 a, int b);
+// CHECK: declare void @_Z4foo32S2i(i32 inreg, i32 inreg)
+void bar3(struct S2 a, int b) {
+ foo3(a, b);
+}
+
+struct S3 {
+ struct {
+ struct {} b[0];
+ } a;
+};
+__attribute((regparm(2))) void foo4(S3 a, int b);
+// CHECK: declare void @_Z4foo42S3i(%struct.S3* byval align 4, i32 inreg)
+void bar3(S3 a, int b) {
+ foo4(a, b);
+}
diff --git a/test/CodeGenCXX/reinterpret-cast.cpp b/test/CodeGenCXX/reinterpret-cast.cpp
index dafa67529f77..63c5a2adc64d 100644
--- a/test/CodeGenCXX/reinterpret-cast.cpp
+++ b/test/CodeGenCXX/reinterpret-cast.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++11
+// REQUIRES: LP64
+
void *f1(unsigned long l) {
return reinterpret_cast<void *>(l);
}
diff --git a/test/CodeGenCXX/return.cpp b/test/CodeGenCXX/return.cpp
new file mode 100644
index 000000000000..43d40ae986ee
--- /dev/null
+++ b/test/CodeGenCXX/return.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O -o - %s | FileCheck %s --check-prefix=CHECK-OPT
+
+// CHECK: @_Z9no_return
+// CHECK-OPT: @_Z9no_return
+int no_return() {
+ // CHECK: call void @llvm.trap
+ // CHECK-NEXT: unreachable
+
+ // CHECK-OPT-NOT: call void @llvm.trap
+ // CHECK-OPT: unreachable
+}
diff --git a/test/CodeGenCXX/static-assert.cpp b/test/CodeGenCXX/static-assert.cpp
index 53dc9a73805f..ff82f6dc5490 100644
--- a/test/CodeGenCXX/static-assert.cpp
+++ b/test/CodeGenCXX/static-assert.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -std=c++11 -verify
+// expected-no-diagnostics
static_assert(true, "");
diff --git a/test/CodeGenCXX/static-init-2.cpp b/test/CodeGenCXX/static-init-2.cpp
index 768e6de92c0f..354fcd4dda53 100644
--- a/test/CodeGenCXX/static-init-2.cpp
+++ b/test/CodeGenCXX/static-init-2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
// Make sure we don't crash generating y; its value is constant, but the
// initializer has side effects, so EmitConstantExpr should fail.
diff --git a/test/CodeGenCXX/switch-case-folding-2.cpp b/test/CodeGenCXX/switch-case-folding-2.cpp
index 7c0283fa2a52..930bfeb64d8d 100644
--- a/test/CodeGenCXX/switch-case-folding-2.cpp
+++ b/test/CodeGenCXX/switch-case-folding-2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// CHECK that we don't crash.
extern int printf(const char*, ...);
diff --git a/test/CodeGenCXX/throw-expression-cleanup.cpp b/test/CodeGenCXX/throw-expression-cleanup.cpp
index 0c41bc65bc3c..e1ecd3804679 100644
--- a/test/CodeGenCXX/throw-expression-cleanup.cpp
+++ b/test/CodeGenCXX/throw-expression-cleanup.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-none-linux-gnu -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s
// PR13359
struct X {
diff --git a/test/CodeGenCXX/throw-expression-dtor.cpp b/test/CodeGenCXX/throw-expression-dtor.cpp
index 0de6683f88d1..cb4a6c69bddd 100644
--- a/test/CodeGenCXX/throw-expression-dtor.cpp
+++ b/test/CodeGenCXX/throw-expression-dtor.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm-only -verify -fcxx-exceptions -fexceptions
+// expected-no-diagnostics
// PR7281
class A {
diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp
index 2515acb48ee7..f04185b23f1b 100644
--- a/test/CodeGenCXX/throw-expressions.cpp
+++ b/test/CodeGenCXX/throw-expressions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only -verify %s -Wno-unreachable-code
+// expected-no-diagnostics
int val = 42;
int& test1() {
diff --git a/test/CodeGenCXX/thunk-linkonce-odr.cpp b/test/CodeGenCXX/thunk-linkonce-odr.cpp
index 4f4d61d5a9a8..82f2148e0b55 100644
--- a/test/CodeGenCXX/thunk-linkonce-odr.cpp
+++ b/test/CodeGenCXX/thunk-linkonce-odr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - | FileCheck %s
// <rdar://problem/7929157> & <rdar://problem/8104369>
struct A {
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index 04d0820da7a3..0659259c1799 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -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 - | 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
namespace Test1 {
@@ -301,6 +301,47 @@ namespace Test12 {
// CHECK: getelementptr inbounds i8* {{.*}}, i64 8
}
+// PR13832
+namespace Test13 {
+ struct B1 {
+ virtual B1 &foo1();
+ };
+ struct Pad1 {
+ virtual ~Pad1();
+ };
+ struct Proxy1 : Pad1, B1 {
+ virtual ~Proxy1();
+ };
+ struct D : virtual Proxy1 {
+ virtual ~D();
+ virtual D &foo1();
+ };
+ D& D::foo1() {
+ return *this;
+ }
+ // CHECK: define {{.*}} @_ZTcvn8_n32_v8_n24_N6Test131D4foo1Ev
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -32
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -24
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
+ // CHECK: ret %"struct.Test13::D"*
+}
+
+namespace Test14 {
+ class A {
+ virtual void f();
+ };
+ class B {
+ virtual void f();
+ };
+ class C : public A, public B {
+ virtual void f();
+ };
+ void C::f() {
+ }
+ // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) {{.*}} uwtable
+}
+
/**** The following has to go at the end of the file ****/
// This is from Test5:
diff --git a/test/CodeGenCXX/typeid-cxx11.cpp b/test/CodeGenCXX/typeid-cxx11.cpp
index 940274e96575..4e32d2dcb5a5 100644
--- a/test/CodeGenCXX/typeid-cxx11.cpp
+++ b/test/CodeGenCXX/typeid-cxx11.cpp
@@ -18,13 +18,15 @@ struct A { virtual ~A(); };
struct B : virtual A {};
struct C { int n; };
-// FIXME: check we produce a constant array for this, once we support IRGen of
-// folded structs and arrays.
+// CHECK: @_ZN5Test1L5itemsE = internal constant [4 x {{.*}}] [{{.*}} @_ZTIN5Test11AE {{.*}}, {{.*}}, {{.*}} @_ZN5Test19make_implINS_1AEEEPvv }, {{.*}} @_ZTIN5Test11BE {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} @_ZTIN5Test11CE {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} @_ZTIi {{.*}} @_ZN5Test19make_implIiEEPvv }]
constexpr Item items[] = {
item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
};
-// CHECK: @_ZN5Test11xE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8
+// CHECK: @_ZN5Test11xE = constant %"class.std::type_info"* bitcast ({{.*}}* @_ZTIN5Test11AE to %"class.std::type_info"*), align 8
constexpr auto &x = items[0].ti;
+// CHECK: @_ZN5Test11yE = constant %"class.std::type_info"* bitcast ({{.*}}* @_ZTIN5Test11BE to %"class.std::type_info"*), align 8
+constexpr auto &y = typeid(B{});
+
}
diff --git a/test/CodeGenCXX/unary-type-trait.cpp b/test/CodeGenCXX/unary-type-trait.cpp
index a11c67e12890..3c6f9c03aa41 100644
--- a/test/CodeGenCXX/unary-type-trait.cpp
+++ b/test/CodeGenCXX/unary-type-trait.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// expected-no-diagnostics
bool a() { return __is_pod(int); }
diff --git a/test/CodeGenCXX/virtual-operator-call.cpp b/test/CodeGenCXX/virtual-operator-call.cpp
index 42d38e55a04f..72d49c230093 100644
--- a/test/CodeGenCXX/virtual-operator-call.cpp
+++ b/test/CodeGenCXX/virtual-operator-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - | FileCheck %s
struct A {
virtual int operator-() = 0;
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index 2bb13485e922..8519c8ced895 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
// The trickery with optimization in the run line is to get IR
// generation to emit available_externally function bodies, but not
@@ -126,3 +126,12 @@ namespace test3 {
// CHECK: define linkonce_odr hidden void @_ZN5test33fooEv
// CHECK: define linkonce_odr hidden void @_ZN5test33zedIiEEvv
}
+
+namespace test4 {
+ extern inline __attribute__ ((__gnu_inline__))
+ void foo() {}
+ void bar() {
+ foo();
+ }
+ // CHECK: define available_externally void @_ZN5test43fooE
+}
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index d7644b98ae09..1e831d2d8349 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -43,6 +43,7 @@
// RUN: FileCheck --check-prefix=CHECK-42 %s < %t
// RUN: FileCheck --check-prefix=CHECK-43 %s < %t
// RUN: FileCheck --check-prefix=CHECK-44 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-45 %s < %t
// For now, just verify this doesn't crash.
namespace test0 {
@@ -1727,3 +1728,23 @@ namespace Test38 {
void *B::foo() { return 0; }
}
+
+namespace Test39 {
+ struct A {
+ virtual void foo() = delete;
+ };
+
+ // CHECK-45: Vtable for 'Test39::B' (4 entries).
+ // CHECK-45-NEXT: 0 | offset_to_top (0)
+ // CHECK-45-NEXT: 1 | Test39::B RTTI
+ // CHECK-45-NEXT: -- (Test39::A, 0) vtable address --
+ // 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()
+ struct B: A {
+ virtual void foo2();
+ };
+
+ void B::foo2() {
+ }
+}
diff --git a/test/CodeGenCXX/vtt-layout.cpp b/test/CodeGenCXX/vtt-layout.cpp
index ace7b74b2dee..abc2477f5b13 100644
--- a/test/CodeGenCXX/vtt-layout.cpp
+++ b/test/CodeGenCXX/vtt-layout.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - | FileCheck %s
// Test1::B should just have a single entry in its VTT, which points to the vtable.
namespace Test1 {
@@ -58,7 +58,29 @@ namespace Test4 {
D d;
}
+namespace Test5 {
+ struct A {
+ virtual void f() = 0;
+ virtual void anchor();
+ };
+
+ void A::anchor() {
+ }
+}
+
+namespace Test6 {
+ struct A {
+ virtual void f() = delete;
+ virtual void anchor();
+ };
+
+ void A::anchor() {
+ }
+}
+
// CHECK: @_ZTTN5Test11BE = unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ([4 x i8*]* @_ZTVN5Test11BE, i64 0, i64 3) to i8*)]
+// CHECK: @_ZTVN5Test51AE = unnamed_addr constant [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test51AE to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void (%"struct.Test5::A"*)* @_ZN5Test51A6anchorEv to i8*)]
+// CHECK: @_ZTVN5Test61AE = unnamed_addr constant [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTIN5Test61AE to i8*), i8* bitcast (void ()* @__cxa_deleted_virtual to i8*), i8* bitcast (void (%"struct.Test6::A"*)* @_ZN5Test61A6anchorEv to i8*)]
// CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr constant [19 x i8*] [i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 12) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 18) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 17) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 20) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 10) to i8*)]
// CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr constant [13 x i8*] [i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 5) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 6) to i8*)]
// CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*)]
diff --git a/test/CodeGenObjC/2008-10-3-EhValue.m b/test/CodeGenObjC/2008-10-3-EhValue.m
index 0ed0d8993977..bc4dfdbae05a 100644
--- a/test/CodeGenObjC/2008-10-3-EhValue.m
+++ b/test/CodeGenObjC/2008-10-3-EhValue.m
@@ -1,4 +1,4 @@
-// RUN: %clang -fexceptions -S -emit-llvm %s -o /dev/null
+// RUN: %clang -fexceptions -fobjc-exceptions -S -emit-llvm %s -o /dev/null
@interface Object {
@public
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index 23da3be2a5dd..2ab8cb6ef562 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -13,8 +13,24 @@ void test1(void) {
// CHECK-NEXT: call void asm sideeffect "mov\09r7, r7
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]],
- // CHECK-NEXT: load
- // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: call void @objc_storeStrong(
// CHECK-NEXT: ret void
id x = test1_helper();
}
+
+// rdar://problem/12133032
+@class A;
+A *test2(void) {
+ extern A *test2_helper(void);
+ // CHECK: [[T0:%.*]] = call arm_aapcscc [[A:%.*]]* @test2_helper()
+ // CHECK-NEXT: ret [[A]]* [[T0]]
+ return test2_helper();
+}
+
+id test3(void) {
+ extern A *test3_helper(void);
+ // CHECK: [[T0:%.*]] = call arm_aapcscc [[A:%.*]]* @test3_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+ // CHECK-NEXT: ret i8* [[T1]]
+ return test3_helper();
+}
diff --git a/test/CodeGenObjC/arc-block-ivar-layout.m b/test/CodeGenObjC/arc-block-ivar-layout.m
deleted file mode 100644
index 6c82f2969823..000000000000
--- a/test/CodeGenObjC/arc-block-ivar-layout.m
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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
-// rdar://8991729
-
-__weak id wid;
-void x(id y) {}
-void y(int a) {}
-
-extern id opaque_id();
-
-void f() {
- __block int byref_int = 0;
- char ch = 'a';
- char ch1 = 'b';
- char ch2 = 'c';
- short sh = 2;
- const id bar = (id) opaque_id();
- id baz = 0;
- __strong id strong_void_sta;
- __block id byref_bab = (id)0;
- __block id bl_var1;
- int i; double dob;
-
-// The patterns here are a sequence of bytes, each saying first how
-// many sizeof(void*) chunks to skip (high nibble) and then how many
-// to scan (low nibble). A zero byte says that we've reached the end
-// of the pattern.
-//
-// All of these patterns start with 01 3x because the block header on
-// LP64 consists of an isa pointer (which we're supposed to scan for
-// some reason) followed by three words (2 ints, a function pointer,
-// and a descriptor pointer).
-
-// Test 1
-// byref int, short, char, char, char, id, id, strong id, byref id
-// 01 35 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
- void (^b)() = ^{
- byref_int = sh + ch+ch1+ch2 ;
- x(bar);
- x(baz);
- x((id)strong_void_sta);
- x(byref_bab);
- };
- b();
-
-// Test 2
-// byref int, short, char, char, char, id, id, strong id, byref void*, byref id
-// 01 36 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
- void (^c)() = ^{
- byref_int = sh + ch+ch1+ch2 ;
- x(bar);
- x(baz);
- x((id)strong_void_sta);
- x(wid);
- bl_var1 = 0;
- x(byref_bab);
- };
-}
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index 2326bce2be25..e77651714e55 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT %s
// This shouldn't crash.
void test0(id (^maker)(void)) {
@@ -41,6 +42,24 @@ void test2(id x) {
// CHECK-NEXT: ret void
extern void test2_helper(id (^)(void));
test2_helper(^{ return x; });
+
+// CHECK: define internal void @__copy_helper_block_
+// CHECK: [[T0:%.*]] = load i8**
+// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
+// CHECK-NEXT: [[T0:%.*]] = load i8**
+// CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: ret void
+
+// CHECK: 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
+// CHECK-NEXT: [[T3:%.*]] = load i8** [[T2]]
+// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// CHECK-NEXT: ret void
}
void test3(void (^sink)(id*)) {
@@ -99,8 +118,8 @@ void test4(void) {
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 -1040187392,
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: store i8* [[T0]], i8**
// CHECK: call void @test4_helper(
@@ -151,8 +170,8 @@ void test5(void) {
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x40000000 - has signature but no copy/dispose
- // CHECK: store i32 1073741824, i32*
+ // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 -1073741824, i32*
// CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
// CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
@@ -179,8 +198,8 @@ void test6(void) {
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 -1040187392,
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: store i8* [[T0]], i8**
// CHECK: call void @test6_helper(
@@ -228,8 +247,8 @@ void test7(void) {
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 -1040187392,
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
@@ -359,7 +378,7 @@ void test10a(void) {
// 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
-// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8
+// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]]
// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T4]])
// CHECK-NEXT: ret void
@@ -532,3 +551,99 @@ void test16() {
// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8
}
+
+// rdar://12151005
+//
+// This is an intentional exception to our conservative jump-scope
+// checking for full-expressions containing block literals with
+// non-trivial cleanups: if the block literal appears in the operand
+// of a return statement, there's no need to extend its lifetime.
+id (^test17(id self, int which))(void) {
+ switch (which) {
+ case 1: return ^{ return self; };
+ case 0: return ^{ return self; };
+ }
+ return (void*) 0;
+}
+// CHECK: define i8* ()* @test17(
+// CHECK: [[RET:%.*]] = alloca i8* ()*, align
+// CHECK-NEXT: [[SELF:%.*]] = alloca i8*,
+// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align
+// CHECK: [[B1:%.*]] = alloca [[BLOCK]], align
+// CHECK: [[T0:%.*]] = call i8* @objc_retain(i8*
+// CHECK-NEXT: store i8* [[T0]], i8** [[SELF]], align
+// CHECK-NOT: objc_retain
+// CHECK-NOT: objc_release
+// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5
+// CHECK-NOT: objc_retain
+// CHECK-NOT: objc_release
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: store i8* [[T2]], i8** [[T0]],
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B0]] to i8* ()*
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()*
+// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]]
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: store i32
+// CHECK-NEXT: br label
+// CHECK-NOT: objc_retain
+// CHECK-NOT: objc_release
+// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5
+// CHECK-NOT: objc_retain
+// CHECK-NOT: objc_release
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: store i8* [[T2]], i8** [[T0]],
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B1]] to i8* ()*
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()*
+// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]]
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: store i32
+// CHECK-NEXT: br label
+
+void test18(id x) {
+// CHECK-UNOPT: define void @test18(
+// CHECK-UNOPT: [[X:%.*]] = alloca i8*,
+// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK-UNOPT-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-UNOPT-NEXT: store i8* [[PARM]], i8** [[X]]
+// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** [[X]],
+// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]],
+// CHECK-UNOPT-NEXT: bitcast
+// CHECK-UNOPT-NEXT: call void @test18_helper(
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) nounwind
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) nounwind
+// CHECK-UNOPT-NEXT: ret void
+ extern void test18_helper(id (^)(void));
+ test18_helper(^{ return x; });
+
+// CHECK-UNOPT: 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**
+// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
+// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5
+// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[DST]], i32 0, i32 5
+// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8** [[T0]]
+// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]]
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) nounwind
+// CHECK-UNOPT-NEXT: ret void
+
+// CHECK-UNOPT: 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
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
+// CHECK-UNOPT-NEXT: ret void
+}
diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
new file mode 100644
index 000000000000..6c72138f93e1
--- /dev/null
+++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
@@ -0,0 +1,425 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck --input-file=%t-64.s %s
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __weak id wid;
+ __block int byref_int = 0;
+ char ch = 'a';
+ char ch1 = 'b';
+ char ch2 = 'c';
+ short sh = 2;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+ int i; double dob;
+
+// The patterns here are a sequence of bytes, each saying first how
+// many sizeof(void*) chunks to skip (high nibble) and then how many
+// to scan (low nibble). A zero byte says that we've reached the end
+// of the pattern.
+//
+// All of these patterns start with 01 3x because the block header on
+// LP64 consists of an isa pointer (which we're supposed to scan for
+// some reason) followed by three words (2 ints, a function pointer,
+// and a descriptor pointer).
+
+// Test 1
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_BYREF:1, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"@2@\00"
+ void (^b)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(byref_bab);
+ };
+ b();
+
+// Test 2
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_WEAK:1, BL_BYREF:2, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"@2PA\00"
+ void (^c)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(wid);
+ bl_var1 = 0;
+ x(byref_bab);
+ };
+}
+
+@class NSString, NSNumber;
+void g() {
+ NSString *foo;
+ NSNumber *bar;
+ unsigned int bletch;
+ __weak id weak_delegate;
+ unsigned int i;
+ NSString *y;
+ NSString *z;
+// block variable layout: BL_STRONG:2, BL_WEAK:1, BL_STRONG:2, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"!1P1\00"
+ void (^c)() = ^{
+ int j = i + bletch;
+ x(foo);
+ x(bar);
+ x(weak_delegate);
+ x(y);
+ x(z);
+ };
+ c();
+}
+
+// Test 5 (unions/structs and their nesting):
+void h() {
+ struct S5 {
+ int i1;
+ __unsafe_unretained id o1;
+ struct V {
+ int i2;
+ __unsafe_unretained id o2;
+ } v1;
+ int i3;
+ union UI {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+ };
+
+ union U {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+
+ struct S5 s2;
+ union U u2;
+ __block id block_id;
+
+/**
+block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1, BL_NON_OBJECT_WORD:1,
+ BL_UNRETAINE:1, BL_NON_OBJECT_WORD:3, BL_BYREF:1, BL_OPERATOR:0
+*/
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [7 x i8] c" ` `\22@\00"
+ void (^c)() = ^{
+ x(s2.ui.o1);
+ x(u2.o1);
+ block_id = 0;
+ };
+ c();
+}
+
+// Test for array of stuff.
+void arr1() {
+ struct S {
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test2 for array of stuff.
+void arr2() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c" c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test3 for array of stuff.
+void arr3() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[0];
+ } imported_s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ void (^c)() = ^{
+ int i = imported_s.a;
+ };
+
+ c();
+}
+
+
+// Test4 for array of stuff.
+@class B;
+void arr4() {
+ struct S {
+ struct s0 {
+ __unsafe_unretained id s_f0;
+ __unsafe_unretained id s_f1;
+ } f0;
+
+ __unsafe_unretained id f1;
+
+ struct s1 {
+ int *f0;
+ __unsafe_unretained B *f1;
+ } f4[2][2];
+ } captured_s;
+
+/**
+block variable layout: BL_UNRETAINE:3,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_OPERATOR:0
+*/
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [10 x i8]
+ void (^c)() = ^{
+ id i = captured_s.f0.s_f1;
+ };
+
+ c();
+}
+
+// Test1 bitfield in cpatured aggregate.
+void bf1() {
+ struct S {
+ int flag : 25;
+ int flag1: 7;
+ int flag2 :1;
+ int flag3: 7;
+ int flag4: 24;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test2 bitfield in cpatured aggregate.
+void bf2() {
+ struct S {
+ int flag : 1;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test3 bitfield in cpatured aggregate.
+void bf3() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+// Test4 unnamed bitfield
+void bf4() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+
+ unsigned long long : 64;
+
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+
+
+// Test5 unnamed bitfield.
+void bf5() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 32;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+
+// Test6 0 length bitfield.
+void bf6() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 0;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+// Test7 large number of captured variables.
+void Test7() {
+ __weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ const id bar = (id) opaque_id();
+//block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"0_\00"
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ };
+}
+
+
+// Test 8 very large number of captured variables.
+void Test8() {
+__weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ __weak id w1, w2, w3, w4;
+ __weak id w5, w6, w7, w8;
+ __weak id w9, w10, w11, w12;
+ __weak id w13, w14, w15, w16;
+ const id bar = (id) opaque_id();
+// block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8]
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ x(w1);
+ x(w2);
+ x(w3);
+ x(w4);
+ x(w5);
+ x(w6);
+ x(w7);
+ x(w8);
+ x(w9);
+ x(w10);
+ x(w11);
+ x(w12);
+ x(w13);
+ x(w14);
+ x(w15);
+ x(w16);
+ x(wid);
+ };
+}
diff --git a/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
new file mode 100644
index 000000000000..b93073711c2f
--- /dev/null
+++ b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
@@ -0,0 +1,112 @@
+// 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 i386-apple-darwin -O0 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-i386 %s
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __block int byref_int = 0;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+
+// Inline instruction for block variable layout: 0x0100
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 256 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 256 }
+ void (^b)() = ^{
+ x(bar);
+ };
+
+// Inline instruction for block variable layout: 0x0210
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 528 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 528 }
+ void (^c)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ };
+
+// Inline instruction for block variable layout: 0x0230
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 560 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 560 }
+ void (^d)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ };
+
+// Inline instruction for block variable layout: 0x0231
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 561 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 561 }
+ __weak id wid;
+ id (^e)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x0235
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 565 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 565 }
+ __weak id wid1, wid2, wid3, wid4;
+ id (^f)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x035
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 53 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 53 }
+ id (^g)() = ^{
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x01
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 1 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 1 }
+ id (^h)() = ^{
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x020
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 32 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 32 }
+ void (^ii)() = ^{
+ byref_int = 1;
+ byref_bab = 0;
+ };
+
+// Inline instruction for block variable layout: 0x0102
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 258 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 258 }
+ void (^jj)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ };
+}
diff --git a/test/CodeGenObjC/arc-captured-block-var-layout.m b/test/CodeGenObjC/arc-captured-block-var-layout.m
new file mode 100644
index 000000000000..77f042e7c2ea
--- /dev/null
+++ b/test/CodeGenObjC/arc-captured-block-var-layout.m
@@ -0,0 +1,425 @@
+// 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
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __weak id wid;
+ __block int byref_int = 0;
+ char ch = 'a';
+ char ch1 = 'b';
+ char ch2 = 'c';
+ short sh = 2;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+ int i; double dob;
+
+// The patterns here are a sequence of bytes, each saying first how
+// many sizeof(void*) chunks to skip (high nibble) and then how many
+// to scan (low nibble). A zero byte says that we've reached the end
+// of the pattern.
+//
+// All of these patterns start with 01 3x because the block header on
+// LP64 consists of an isa pointer (which we're supposed to scan for
+// some reason) followed by three words (2 ints, a function pointer,
+// and a descriptor pointer).
+
+// Test 1
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_BYREF:1, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"@2@\00"
+ void (^b)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(byref_bab);
+ };
+ b();
+
+// Test 2
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_WEAK:1, BL_BYREF:2, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"@2PA\00"
+ void (^c)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(wid);
+ bl_var1 = 0;
+ x(byref_bab);
+ };
+}
+
+@class NSString, NSNumber;
+void g() {
+ NSString *foo;
+ NSNumber *bar;
+ unsigned int bletch;
+ __weak id weak_delegate;
+ unsigned int i;
+ NSString *y;
+ NSString *z;
+// block variable layout: BL_STRONG:2, BL_WEAK:1, BL_STRONG:2, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"1P1\00"
+ void (^c)() = ^{
+ int j = i + bletch;
+ x(foo);
+ x(bar);
+ x(weak_delegate);
+ x(y);
+ x(z);
+ };
+ c();
+}
+
+// Test 5 (unions/structs and their nesting):
+void h() {
+ struct S5 {
+ int i1;
+ __unsafe_unretained id o1;
+ struct V {
+ int i2;
+ __unsafe_unretained id o2;
+ } v1;
+ int i3;
+ union UI {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+ };
+
+ union U {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+
+ struct S5 s2;
+ union U u2;
+ __block id block_id;
+
+/**
+block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1, BL_NON_OBJECT_WORD:1,
+ BL_UNRETAINE:1, BL_NON_OBJECT_WORD:3, BL_BYREF:1, BL_OPERATOR:0
+*/
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [7 x i8] c" ` `\22@\00"
+ void (^c)() = ^{
+ x(s2.ui.o1);
+ x(u2.o1);
+ block_id = 0;
+ };
+ c();
+}
+
+// Test for array of stuff.
+void arr1() {
+ struct S {
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test2 for array of stuff.
+void arr2() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c" c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test3 for array of stuff.
+void arr3() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[0];
+ } imported_s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ void (^c)() = ^{
+ int i = imported_s.a;
+ };
+
+ c();
+}
+
+
+// Test4 for array of stuff.
+@class B;
+void arr4() {
+ struct S {
+ struct s0 {
+ __unsafe_unretained id s_f0;
+ __unsafe_unretained id s_f1;
+ } f0;
+
+ __unsafe_unretained id f1;
+
+ struct s1 {
+ int *f0;
+ __unsafe_unretained B *f1;
+ } f4[2][2];
+ } captured_s;
+
+/**
+block variable layout: BL_UNRETAINE:3,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_OPERATOR:0
+*/
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [10 x i8]
+ void (^c)() = ^{
+ id i = captured_s.f0.s_f1;
+ };
+
+ c();
+}
+
+// Test1 bitfield in cpatured aggregate.
+void bf1() {
+ struct S {
+ int flag : 25;
+ int flag1: 7;
+ int flag2 :1;
+ int flag3: 7;
+ int flag4: 24;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test2 bitfield in cpatured aggregate.
+void bf2() {
+ struct S {
+ int flag : 1;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test3 bitfield in cpatured aggregate.
+void bf3() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+// Test4 unnamed bitfield
+void bf4() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+
+ unsigned long long : 64;
+
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+
+
+// Test5 unnamed bitfield.
+void bf5() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 32;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+
+// Test6 0 length bitfield.
+void bf6() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 0;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+// Test7 large number of captured variables.
+void Test7() {
+ __weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ const id bar = (id) opaque_id();
+//block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"0_\00"
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ };
+}
+
+
+// Test 8 very large number of captured variables.
+void Test8() {
+__weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ __weak id w1, w2, w3, w4;
+ __weak id w5, w6, w7, w8;
+ __weak id w9, w10, w11, w12;
+ __weak id w13, w14, w15, w16;
+ const id bar = (id) opaque_id();
+// block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8]
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ x(w1);
+ x(w2);
+ x(w3);
+ x(w4);
+ x(w5);
+ x(w6);
+ x(w7);
+ x(w8);
+ x(w9);
+ x(w10);
+ x(w11);
+ x(w12);
+ x(w13);
+ x(w14);
+ x(w15);
+ x(w16);
+ x(wid);
+ };
+}
diff --git a/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m
index 5ef5ababe695..63945e3a1b49 100644
--- a/test/CodeGenObjC/arc-exceptions.m
+++ b/test/CodeGenObjC/arc-exceptions.m
@@ -20,9 +20,8 @@ void test0(void) {
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
-// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind
// CHECK-NEXT: call void @objc_end_catch() nounwind
void test1_helper(void);
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index 67fad4d9b04a..b8d2d30ab40a 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -67,8 +67,7 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
// CHECK-LP64: call void @use_block(
-// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]]
-// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null)
// CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
@@ -79,9 +78,8 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
// Destroy 'array'.
-// CHECK-LP64: [[T0:%.*]] = load [[ARRAY_T]]** [[ARRAY]]
-// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[T0]] to i8*
-// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-LP64: [[T0:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8**
+// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
// CHECK-LP64-NEXT: ret void
// CHECK-LP64: define internal void @__test0_block_invoke
diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m
index 7f58a0cad3bd..90683149d5bb 100644
--- a/test/CodeGenObjC/arc-ivar-layout.m
+++ b/test/CodeGenObjC/arc-ivar-layout.m
@@ -1,5 +1,6 @@
// 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
+// REQUIRES: x86-64-registered-target
// rdar://8991729
@interface NSObject {
diff --git a/test/CodeGenObjC/arc-no-runtime.m b/test/CodeGenObjC/arc-no-runtime.m
index 3c85e8783cb8..f5f5b90ea52b 100644
--- a/test/CodeGenObjC/arc-no-runtime.m
+++ b/test/CodeGenObjC/arc-no-runtime.m
@@ -1,9 +1,13 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -emit-llvm %s -o - | FileCheck %s
// rdar://problem/9224855
+id make(void) __attribute__((ns_returns_retained));
void test0() {
+ make();
id x = 0;
// CHECK: call void @objc_release(
+ // CHECK: call void @objc_storeStrong(
}
// CHECK: declare extern_weak void @objc_release(
+// CHECK: declare extern_weak void @objc_storeStrong(
diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
index 6c5180b1c347..db00e369cfd1 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -11,5 +11,77 @@ void test0(Test0 *t0, id value) {
// CHECK: call i8* @objc_retain(
// CHECK: call i8* @objc_retain(
// CHECK: @objc_msgSend
-// CHECK: call void @objc_release(
-// CHECK: call void @objc_release(
+// CHECK: call void @objc_storeStrong(
+// CHECK: call void @objc_storeStrong(
+
+struct S1 { Class isa; };
+@interface Test1
+@property (nonatomic, strong) __attribute__((NSObject)) struct S1 *pointer;
+@end
+@implementation Test1
+@synthesize pointer;
+@end
+// The getter should be a simple load.
+// CHECK: define internal [[S1:%.*]]* @"\01-[Test1 pointer]"(
+// CHECK: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test1.pointer"
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST1:%.*]]* {{%.*}} to i8*
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[S1]]**
+// CHECK-NEXT: [[T3:%.*]] = load [[S1]]** [[T2]], align 8
+// CHECK-NEXT: ret [[S1]]* [[T3]]
+
+// The setter should be using objc_setProperty.
+// CHECK: define internal void @"\01-[Test1 setPointer:]"(
+// CHECK: [[T0:%.*]] = bitcast [[TEST1]]* {{%.*}} to i8*
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test1.pointer"
+// CHECK-NEXT: [[T1:%.*]] = load [[S1]]** {{%.*}}
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S1]]* [[T1]] to i8*
+// CHECK-NEXT: call void @objc_setProperty(i8* [[T0]], i8* {{%.*}}, i64 [[OFFSET]], i8* [[T2]], i1 zeroext false, i1 zeroext false)
+// CHECK-NEXT: ret void
+
+
+// rdar://problem/12039404
+@interface Test2 {
+@private
+ Class _theClass;
+}
+@property (copy) Class theClass;
+@end
+
+static Class theGlobalClass;
+@implementation Test2
+@synthesize theClass = _theClass;
+- (void) test {
+ _theClass = theGlobalClass;
+}
+@end
+// CHECK: define internal void @"\01-[Test2 test]"(
+// CHECK: [[T0:%.*]] = load i8** @theGlobalClass, align 8
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST2:%.*]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2._theClass"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST2]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[OFFSET]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T4]], i8* [[T0]]) nounwind
+// CHECK-NEXT: ret void
+
+// CHECK: define internal i8* @"\01-[Test2 theClass]"(
+// CHECK: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2._theClass"
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_getProperty(i8* {{.*}}, i8* {{.*}}, i64 [[OFFSET]], i1 zeroext true)
+// CHECK-NEXT: ret i8* [[T0]]
+
+// CHECK: define internal void @"\01-[Test2 setTheClass:]"(
+// CHECK: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8*
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2._theClass"
+// CHECK-NEXT: [[T1:%.*]] = load i8** {{%.*}}
+// CHECK-NEXT: call void @objc_setProperty(i8* [[T0]], i8* {{%.*}}, i64 [[OFFSET]], i8* [[T1]], i1 zeroext true, i1 zeroext true)
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void @"\01-[Test2 .cxx_destruct]"(
+// CHECK: [[T0:%.*]] = load [[TEST2]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2._theClass"
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8* [[T1]], i64 [[OFFSET]]
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T3]], i8* null) nounwind
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
index f73aa5049f5c..ee0a41dd00b4 100644
--- a/test/CodeGenObjC/arc-related-result-type.m
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -20,11 +20,9 @@ void test0(Test0 *val) {
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
// CHECK-NEXT: store [[TEST0]]* [[T2]], [[TEST0]]** [[X]]
-// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[X]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]])
-// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[VAL]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]** [[X]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]** [[VAL]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 66a6a2f54b77..8e38019de54c 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -602,7 +602,10 @@ void test22(_Bool cond) {
// rdar://problem/8922540
// Note that we no longer emit .release_ivars flags.
-// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 134,
+// rdar://problem/12492434
+// Note that we set the flag saying that we need destruction *and*
+// the flag saying that we don't also need construction.
+// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 390,
@interface Test23 { id x; } @end
@implementation Test23 @end
@@ -1358,9 +1361,9 @@ void test59(void) {
// CHECK: define void @test59()
// CHECK: [[T0:%.*]] = call i8* @test59_getlock()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: call void @objc_sync_enter(i8* [[T1]])
+ // CHECK-NEXT: call i32 @objc_sync_enter(i8* [[T1]])
// CHECK-NEXT: call void @test59_body()
- // CHECK-NEXT: call void @objc_sync_exit(i8* [[T1]])
+ // CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T1]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
index 978299b45a6d..878255b0fb3f 100644
--- a/test/CodeGenObjC/atomic-aggregate-property.m
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -1,6 +1,7 @@
// 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
// rdar: // 7849824
+// <rdar://problem/12547611>
struct s {
double a, b, c, d;
@@ -12,16 +13,20 @@ struct s1 {
id k;
};
+struct s2 {};
+
@interface A
@property (readwrite) double x;
@property (readwrite) struct s y;
@property (nonatomic, readwrite) struct s1 z;
+@property (readwrite) struct s2 a;
@end
@implementation A
@synthesize x;
@synthesize y;
@synthesize z;
+@synthesize a;
@end
// CHECK-LP64: define internal double @"\01-[A x]"(
// CHECK-LP64: load atomic i64* {{%.*}} unordered, align 8
@@ -40,3 +45,9 @@ struct s1 {
// CHECK-LP64: define internal void @"\01-[A setZ:]"(
// CHECK-LP64: call i8* @objc_memmove_collectable(
+
+// CHECK-LP64: define internal void @"\01-[A a]"(
+// (do nothing)
+
+// CHECK-LP64: define internal void @"\01-[A setA:]"(
+// (do nothing)
diff --git a/test/CodeGenObjC/attr-minsize.m b/test/CodeGenObjC/attr-minsize.m
new file mode 100644
index 000000000000..f46107eca61e
--- /dev/null
+++ b/test/CodeGenObjC/attr-minsize.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+@interface Test
+- (void)test;
+@end
+
+@implementation Test
+- (void)test __attribute__((minsize)) {
+ // CHECK: define{{.*}}Test test
+ // CHECK: minsize
+}
+@end
diff --git a/test/CodeGenObjC/block-var-layout.m b/test/CodeGenObjC/block-var-layout.m
index c8065be88c76..71b14dab24bd 100644
--- a/test/CodeGenObjC/block-var-layout.m
+++ b/test/CodeGenObjC/block-var-layout.m
@@ -90,7 +90,7 @@ void f() {
// Test 4
// struct S (int, id, int, id, int, id)
-// 01 41 11 11
+// 01 41 11 11 00
// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\11\00"
struct S s2;
void (^e)() = ^{
@@ -128,8 +128,8 @@ void Test5() {
union U u2;
// struct s2 (int, id, int, id, int, id?), union u2 (id?)
-// 01 41 11 12 70 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [6 x i8] c"\01A\11\12p\00"
+// 01 41 11 12 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\12\00"
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
diff --git a/test/CodeGenObjC/builtin-memfns.m b/test/CodeGenObjC/builtin-memfns.m
new file mode 100644
index 000000000000..bb425c037c64
--- /dev/null
+++ b/test/CodeGenObjC/builtin-memfns.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -emit-llvm -o - %s | FileCheck %s
+
+void *memcpy(void *restrict s1, const void *restrict s2, unsigned long n);
+
+// PR13697
+void test1(int *a, id b) {
+ // CHECK: @test1
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 1, i1 false)
+ memcpy(a, b, 8);
+}
diff --git a/test/CodeGenObjC/category-super-class-meth.m b/test/CodeGenObjC/category-super-class-meth.m
index 6f02aff96de1..5ba7adff8bbe 100644
--- a/test/CodeGenObjC/category-super-class-meth.m
+++ b/test/CodeGenObjC/category-super-class-meth.m
@@ -1,19 +1,29 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-
-@interface BASE
-+ (int) BaseMeth;
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -o - | FileCheck %s
+// rdar://12459358
+@interface NSObject
+-(id)copy;
++(id)copy;
@end
-@interface Child: BASE
-@end
+@interface Sub1 : NSObject @end
-@interface Child (Categ)
-+ (int) flushCache2;
+@implementation Sub1
+-(id)copy { return [super copy]; } // ok: instance method in class
++(id)copy { return [super copy]; } // ok: class method in class
@end
-@implementation Child @end
+@interface Sub2 : NSObject @end
+
+@interface Sub2 (Category) @end
-@implementation Child (Categ)
-+ (int) flushCache2 { [super BaseMeth]; }
+@implementation Sub2 (Category)
+-(id)copy { return [super copy]; } // ok: instance method in category
++(id)copy { return [super copy]; } // BAD: class method in category
@end
+// CHECK: define internal i8* @"\01+[Sub2(Category) copy]
+// CHECK: [[ONE:%.*]] = load %struct._class_t** @"\01L_OBJC_CLASSLIST_SUP_REFS_$_3"
+// CHECK: [[TWO:%.*]] = bitcast %struct._class_t* [[ONE]] to i8*
+// CHECK: [[THREE:%.*]] = getelementptr inbounds %struct._objc_super* [[OBJC_SUPER:%.*]], i32 0, i32 1
+// CHECK: store i8* [[TWO]], i8** [[THREE]]
+// CHECK: [[FOUR:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
diff --git a/test/CodeGenObjC/debug-info-crash-2.m b/test/CodeGenObjC/debug-info-crash-2.m
index a2acd9dc9170..7d05f535c9af 100644
--- a/test/CodeGenObjC/debug-info-crash-2.m
+++ b/test/CodeGenObjC/debug-info-crash-2.m
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -g -S %s -o -
+// REQUIRES: x86-64-registered-target
+
@class Bar;
@interface Foo
@property (strong, nonatomic) Bar *window;
diff --git a/test/CodeGenObjC/debug-info-fwddecl.m b/test/CodeGenObjC/debug-info-fwddecl.m
index ebdc5f290a57..8f2860c7d85d 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: metadata !{i32 {{.*}}, null, metadata !"ForwardObjcClass", metadata !{{.*}}, i32 2, i32 0, i32 0, i32 0, i32 4, null, null, i32 16} ; [ DW_TAG_structure_type ]
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"ForwardObjcClass", metadata !{{.*}}, i32 2, i64 0, i64 0, i32 0, i32 4, null, null, i32 16} ; [ DW_TAG_structure_type ]
diff --git a/test/CodeGenObjC/debug-info-impl.m b/test/CodeGenObjC/debug-info-impl.m
index 8ad590357b0d..a8450dd5808e 100644
--- a/test/CodeGenObjC/debug-info-impl.m
+++ b/test/CodeGenObjC/debug-info-impl.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -S -emit-llvm %s -o - | FileCheck %s
-// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"Circle", metadata {{.*}}, i32 11, i64 64, i64 64, i32 0, i32 512, null, metadata {{.*}}, i32 16, i32 0} ; [ DW_TAG_structure_type ]
+// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"Circle", metadata {{.*}}, i32 11, i64 64, i64 64, i32 0, i32 512, null, metadata {{.*}}, i32 16, i32 0, i32 0} ; [ DW_TAG_structure_type ]
@interface NSObject {
struct objc_object *isa;
}
diff --git a/test/CodeGenObjC/debug-info-ivars.m b/test/CodeGenObjC/debug-info-ivars.m
new file mode 100644
index 000000000000..24705e1ad658
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+__attribute((objc_root_class)) @interface NSObject {
+ id isa;
+}
+@end
+
+@interface BaseClass : NSObject
+{
+ int i;
+ unsigned flag_1 : 9;
+ unsigned flag_2 : 9;
+ unsigned : 1;
+ unsigned flag_3 : 9;
+}
+@end
+
+@implementation BaseClass
+@end
+
+// CHECK: metadata !{i32 786445, metadata !{{[0-9]*}}, metadata !"i", metadata !{{[0-9]*}}, i32 10, i64 32, i64 32, i64 0, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [i] [line 10, size 32, align 32, offset 0] [protected] [from int]
+// CHECK: metadata !{i32 786445, metadata !{{[0-9]*}}, metadata !"flag_1", metadata !{{[0-9]*}}, i32 11, i64 9, i64 32, i64 0, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [flag_1] [line 11, size 9, align 32, offset 0] [protected] [from unsigned int]
+// CHECK: metadata !{i32 786445, metadata !{{[0-9]*}}, metadata !"flag_2", metadata !{{[0-9]*}}, i32 12, i64 9, i64 32, i64 1, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [flag_2] [line 12, size 9, align 32, offset 1] [protected] [from unsigned int]
+// CHECK: metadata !{i32 786445, metadata !{{[0-9]*}}, metadata !"flag_3", metadata !{{[0-9]*}}, i32 14, i64 9, i64 32, i64 3, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [flag_3] [line 14, size 9, align 32, offset 3] [protected] [from unsigned int] \ No newline at end of file
diff --git a/test/CodeGenObjC/debug-info-pubtypes.m b/test/CodeGenObjC/debug-info-pubtypes.m
index 658430d9307b..91d9cd1995ad 100644
--- a/test/CodeGenObjC/debug-info-pubtypes.m
+++ b/test/CodeGenObjC/debug-info-pubtypes.m
@@ -1,7 +1,7 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -emit-llvm %s -o - | FileCheck %s
-// CHECK: !5 = metadata !{i32 {{.*}}, metadata !6, metadata !"H", metadata !6, i32 6, i64 0, i64 8, i32 0, i32 512, null, metadata !2, i32 16, i32 0} ; [ DW_TAG_structure_type ]
+// CHECK: !5 = metadata !{i32 {{.*}}, metadata !6, metadata !"H", metadata !6, i32 6, i64 0, i64 8, i32 0, i32 512, null, metadata !2, i32 16, i32 0, i32 0} ; [ DW_TAG_structure_type ]
@interface H
-(void) foo;
diff --git a/test/CodeGenObjC/debug-info-self.m b/test/CodeGenObjC/debug-info-self.m
index 9146ab3973c6..9f234353da06 100644
--- a/test/CodeGenObjC/debug-info-self.m
+++ b/test/CodeGenObjC/debug-info-self.m
@@ -1,8 +1,12 @@
-// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_AT_artificial | count 3
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
// self and _cmd are marked as DW_AT_artificial.
-// abbrev code emits another DT_artificial comment.
// myarg is not marked as DW_AT_artificial.
+// CHECK: metadata !{i32 {{.*}}, metadata !9, metadata !"self", metadata !15, i32 16777232, metadata !30, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [self] [line 16]
+// CHECK: metadata !{i32 {{.*}}, metadata !9, metadata !"_cmd", metadata !15, i32 33554448, metadata !33, i32 64, i32 0} ; [ DW_TAG_arg_variable ] [_cmd] [line 16]
+// CHECK: metadata !{i32 {{.*}}, metadata !9, metadata !"myarg", metadata !6, i32 50331664, metadata !24, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [myarg] [line 16]
+
+
@interface MyClass {
}
- (id)init:(int) myarg;
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 25780fd518fe..551e67c2e6ca 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -149,8 +149,8 @@ void f4() {
// finally.call-exit: Predecessors are the @try and @catch fallthroughs
// as well as the no-match case in the catch mechanism. The i1 is whether
// to rethrow and should be true only in the last case.
- // CHECK: phi i1
- // CHECK-NEXT: phi i8*
+ // CHECK: phi i8*
+ // CHECK-NEXT: phi i1
// CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* [[EXNDATA]])
// CHECK-NEXT: call void @f4_help(i32 2)
// CHECK-NEXT: br i1
diff --git a/test/CodeGenObjC/gnu-exceptions.m b/test/CodeGenObjC/gnu-exceptions.m
index 141747ec8d3d..b7d0adbc6d64 100644
--- a/test/CodeGenObjC/gnu-exceptions.m
+++ b/test/CodeGenObjC/gnu-exceptions.m
@@ -20,7 +20,7 @@ void test0() {
// CHECK: call void @log(i32 0)
- // CHECK: call void @objc_exception_throw
+ // CHECK: resume
log(0);
}
diff --git a/test/CodeGenObjC/ivar-layout-64.m b/test/CodeGenObjC/ivar-layout-64.m
index ea4cdce4b8b2..91a8375e6365 100644
--- a/test/CodeGenObjC/ivar-layout-64.m
+++ b/test/CodeGenObjC/ivar-layout-64.m
@@ -1,15 +1,5 @@
-// RUNX: llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t
-// RUNX: llvm-gcc -ObjC++ -m64 -fobjc-gc -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"A\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\11q\\10\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"!q\\00"' %t
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_.*" = internal global .* c"\\01\\14\\00"' %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
/*
@@ -43,6 +33,11 @@ __weak B *f2;
@property int p3;
@end
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"C\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"\11p\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"!`\00"
+
+
@implementation C
@synthesize p3 = _p3;
@end
@@ -53,8 +48,10 @@ __weak B *f2;
@property (assign) __weak id p2;
@end
-// FIXME: Check layout for this class, once it is clear what the right
-// answer is.
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"A\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"\11q\10\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"!q\00"
+
@implementation A
@synthesize p0 = _p0;
@synthesize p1 = _p1;
@@ -65,8 +62,10 @@ __weak B *f2;
@property int p3;
@end
-// FIXME: Check layout for this class, once it is clear what the right
-// answer is.
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"D\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"\11p\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"!`\00"
+
@implementation D
@synthesize p3 = _p3;
@end
@@ -90,5 +89,26 @@ typedef unsigned int FSCatalogInfoBitmap;
}
@end
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"NSFileLocationComponent\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"\01\14\00"
+
@implementation NSFileLocationComponent @end
+@interface NSObject {
+ id isa;
+}
+@end
+
+@interface Foo : NSObject {
+ id ivar;
+
+ unsigned long bitfield :31;
+ unsigned long bitfield2 :1;
+ unsigned long bitfield3 :32;
+}
+@end
+
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"Foo\00"
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global {{.*}} c"\02\10\00"
+
+@implementation Foo @end
diff --git a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
new file mode 100644
index 000000000000..f1e02ddf5d65
--- /dev/null
+++ b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -O0 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fblocks -triple i386-apple-darwin -O0 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-i386 %s
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+__weak id wid;
+
+void f() {
+ __block int byref_int = 0;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+
+// block variable layout: BL_UNRETAINED:1, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"`\00"
+// CHECK-i386: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"`\00"
+ void (^b)() = ^{
+ x(bar);
+ };
+
+// block variable layout: BL_UNRETAINED:2, BL_BYREF:1, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"a@\00"
+// CHECK-i386: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"a@\00"
+ void (^c)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ };
+
+// block variable layout: BL_UNRETAINED:2, BL_BYREF:3, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"aB\00
+// CHECK-i386: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"aB\00
+ void (^d)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ };
+
+// block variable layout: BL_UNRETAINED:2, BL_BYREF:3, BL_OPERATOR:0
+// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"aB\00"
+// CHECK-i386: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"aB\00"
+ id (^e)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x020
+// CHECK: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i64 32 }
+// CHECK-i386: i8* getelementptr inbounds ([6 x i8]* {{@.*}}, i32 0, i32 0), i32 32 }
+ void (^ii)() = ^{
+ byref_int = 1;
+ byref_bab = 0;
+ };
+}
diff --git a/test/CodeGenObjC/newproperty-nested-synthesis-1.m b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
index 4831c22463b8..aa0c8c923971 100644
--- a/test/CodeGenObjC/newproperty-nested-synthesis-1.m
+++ b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
+// REQUIRES: LP64
@interface Object
- (id) new;
diff --git a/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m
index 892491630e6e..71339c7085a4 100644
--- a/test/CodeGenObjC/objc-arc-container-subscripting.m
+++ b/test/CodeGenObjC/objc-arc-container-subscripting.m
@@ -13,9 +13,8 @@ id func() {
// CHECK: [[call:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
// CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind
-// CHECK: [[ARRAY:%.*]] = load %0**
-// CHECK: [[ARRAY_CASTED:%.*]] = bitcast{{.*}}[[ARRAY]] to i8*
-// CHECK: call void @objc_release(i8* [[ARRAY_CASTED]])
+// CHECK: [[ARRAY_CASTED:%.*]] = bitcast %0** {{%.*}} to i8**
+// CHECK: call void @objc_storeStrong(i8** [[ARRAY_CASTED]], i8* null)
// CHECK: [[EIGHT:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind
// CHECK: ret i8* [[EIGHT]]
diff --git a/test/CodeGenObjC/objc2-ivar-assign.m b/test/CodeGenObjC/objc2-ivar-assign.m
index af768007212b..05a7b353cfeb 100644
--- a/test/CodeGenObjC/objc2-ivar-assign.m
+++ b/test/CodeGenObjC/objc2-ivar-assign.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -fobjc-gc -emit-llvm -o %t %s
// RUN: grep objc_assign_ivar %t | count 6
+// PR13820
+// REQUIRES: LP64
+
@interface I @end
typedef I TI;
diff --git a/test/CodeGenObjC/optimized-setter-ios-device.m b/test/CodeGenObjC/optimized-setter-ios-device.m
new file mode 100644
index 000000000000..6fa322ab0f5f
--- /dev/null
+++ b/test/CodeGenObjC/optimized-setter-ios-device.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -fobjc-runtime=ios-6.0.0 -triple thumbv7-apple-ios6.0.0 -o - | FileCheck %s
+// rdar://11915017
+
+@interface I
+// void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, NO)
+@property (nonatomic, retain) id nonatomicProperty;
+
+// void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, YES)
+@property (nonatomic, copy) id nonatomicPropertyCopy;
+
+// void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, NO)
+@property (retain) id atomicProperty;
+
+// void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, YES)
+@property (copy) id atomicPropertyCopy;
+@end
+
+@implementation I
+@synthesize nonatomicProperty;
+@synthesize nonatomicPropertyCopy;
+@synthesize atomicProperty;
+@synthesize atomicPropertyCopy;
+@end
+
+// CHECK: call arm_aapcscc void @objc_setProperty_nonatomic
+// CHECK: call arm_aapcscc void @objc_setProperty_nonatomic_copy
+// CHECK: call arm_aapcscc void @objc_setProperty_atomic
+// CHECK: call arm_aapcscc void @objc_setProperty_atomic_copy
+
diff --git a/test/CodeGenObjC/optimized-setter.m b/test/CodeGenObjC/optimized-setter.m
index 0e1b38859519..6f5cfb126332 100644
--- a/test/CodeGenObjC/optimized-setter.m
+++ b/test/CodeGenObjC/optimized-setter.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-macosx10.8.0 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -fobjc-runtime=macosx-10.8 -triple x86_64-apple-macosx10.8.0 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -fobjc-runtime=ios-6.0.0 -triple x86_64-apple-ios6.0.0 -o - | FileCheck %s
// rdar://10179974
@interface I
diff --git a/test/CodeGenObjC/prop-metadata-gnu.m b/test/CodeGenObjC/prop-metadata-gnu.m
new file mode 100644
index 000000000000..c15d978775c1
--- /dev/null
+++ b/test/CodeGenObjC/prop-metadata-gnu.m
@@ -0,0 +1,15 @@
+// RUN: %clang -S -emit-llvm %s -o - -x objective-c -fobjc-runtime=gcc | FileCheck --check-prefix=GCC %s
+// RUN: %clang -S -emit-llvm %s -o - -x objective-c -fobjc-runtime=gnustep-1.5 | FileCheck --check-prefix=GCC %s
+// RUN: %clang -S -emit-llvm %s -o - -x objective-c -fobjc-runtime=gnustep-1.6 | FileCheck --check-prefix=GNUSTEP %s
+//
+@interface helloclass {
+@private int varName;
+}
+@property (readwrite,assign) int propName;
+@end
+
+@implementation helloclass
+@synthesize propName = varName;
+@end
+// GCC-NOT: Ti,VvarName
+// GNUSTEP: Ti,VvarName
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index 16881d608bf2..aab7c73ad069 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// PR13820
+// REQUIRES: LP64
// TODO: actually test most of this instead of just emitting it
diff --git a/test/CodeGenObjC/synchronized.m b/test/CodeGenObjC/synchronized.m
index 1f012820f9ba..e927882b3f73 100644
--- a/test/CodeGenObjC/synchronized.m
+++ b/test/CodeGenObjC/synchronized.m
@@ -11,7 +11,7 @@
// CHECK: define internal void @"\01-[MyClass method]"
- (void)method
{
- // CHECK: call void @objc_sync_enter
+ // CHECK: call i32 @objc_sync_enter
// CHECK: call void @objc_exception_try_enter
// CHECK: call i32 @_setjmp
@synchronized(self) {
@@ -26,21 +26,21 @@ void foo(id a) {
// CHECK: [[SYNC:%.*]] = alloca i8*
// CHECK: store i8* [[AVAL:%.*]], i8** [[A]]
- // CHECK-NEXT: call void @objc_sync_enter(i8* [[AVAL]])
+ // CHECK-NEXT: call i32 @objc_sync_enter(i8* [[AVAL]])
// CHECK-NEXT: store i8* [[AVAL]], i8** [[SYNC]]
// CHECK-NEXT: call void @objc_exception_try_enter
// CHECK: call i32 @_setjmp
@synchronized(a) {
// This is unreachable, but the optimizers can't know that.
// CHECK: call void asm sideeffect "", "=*m,=*m,=*m"(i8** [[A]], i8** [[SYNC]]
- // CHECK: call void @objc_sync_exit
+ // CHECK: call i32 @objc_sync_exit
// CHECK: call i8* @objc_exception_extract
// CHECK: call void @objc_exception_throw
// CHECK: unreachable
// CHECK: call void @objc_exception_try_exit
// CHECK: [[T:%.*]] = load i8** [[SYNC]]
- // CHECK-NEXT: call void @objc_sync_exit
+ // CHECK-NEXT: call i32 @objc_sync_exit
// CHECK: ret void
return;
}
diff --git a/test/CodeGenObjC/synthesize_ivar-cont-class.m b/test/CodeGenObjC/synthesize_ivar-cont-class.m
index 6bc7ac8170ef..98227023318e 100644
--- a/test/CodeGenObjC/synthesize_ivar-cont-class.m
+++ b/test/CodeGenObjC/synthesize_ivar-cont-class.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
// RUN: grep '@"OBJC_IVAR_$_XCOrganizerDeviceNodeInfo.viewController"' %t
+// PR13820
+// REQUIRES: LP64
+
@interface XCOrganizerNodeInfo
@property (readonly, retain) id viewController;
@end
diff --git a/test/CodeGenObjC/synthesize_ivar.m b/test/CodeGenObjC/synthesize_ivar.m
index e4fbe101a648..92f6096b7e4d 100644
--- a/test/CodeGenObjC/synthesize_ivar.m
+++ b/test/CodeGenObjC/synthesize_ivar.m
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
+// PR13820
+// REQUIRES: LP64
+
@interface I
@property int IP;
@end
diff --git a/test/CodeGenObjC/undefined-protocol.m b/test/CodeGenObjC/undefined-protocol.m
index e5a72ab602f0..78cf8da336c3 100644
--- a/test/CodeGenObjC/undefined-protocol.m
+++ b/test/CodeGenObjC/undefined-protocol.m
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -emit-llvm-only -fobjc-runtime=gcc %s
+// PR13820
+// REQUIRES: LP64
+
@protocol MadeUpProtocol;
@interface Object <MadeUpProtocol> @end
diff --git a/test/CodeGenObjC/unoptimized-setter.m b/test/CodeGenObjC/unoptimized-setter.m
new file mode 100644
index 000000000000..adcf08701603
--- /dev/null
+++ b/test/CodeGenObjC/unoptimized-setter.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -emit-llvm -fobjc-runtime=macosx-10.6.0 -triple x86_64-apple-macosx10.6.0 -o - | FileCheck %s
+// rdar://11858187
+
+@interface I
+// void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, NO)
+@property (nonatomic, retain) id nonatomicProperty;
+
+// void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, YES)
+@property (nonatomic, copy) id nonatomicPropertyCopy;
+
+// void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, NO)
+@property (retain) id atomicProperty;
+
+// void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, YES)
+@property (copy) id atomicPropertyCopy;
+@end
+
+@implementation I
+@synthesize nonatomicProperty;
+@synthesize nonatomicPropertyCopy;
+@synthesize atomicProperty;
+@synthesize atomicPropertyCopy;
+@end
+
+// CHECK-NOT: call void @objc_setProperty_nonatomic
+// CHECK-NOT: call void @objc_setProperty_nonatomic_copy
+// CHECK-NOT: call void @objc_setProperty_atomic
+// CHECK-NOT: call void @objc_setProperty_atomic_copy
diff --git a/test/CodeGenObjCXX/address-safety-attr.mm b/test/CodeGenObjCXX/address-safety-attr.mm
index a54ca998f818..a3824b99aeff 100644
--- a/test/CodeGenObjCXX/address-safety-attr.mm
+++ b/test/CodeGenObjCXX/address-safety-attr.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -faddress-sanitizer | FileCheck -check-prefix ASAN %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix ASAN %s
@interface MyClass
+ (int) addressSafety:(int*)a;
diff --git a/test/CodeGenObjCXX/arc-exceptions.mm b/test/CodeGenObjCXX/arc-exceptions.mm
index b1fa8ca2403b..fb5300d15e4c 100644
--- a/test/CodeGenObjCXX/arc-exceptions.mm
+++ b/test/CodeGenObjCXX/arc-exceptions.mm
@@ -20,9 +20,8 @@ void test0(void) {
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
-// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind
// CHECK-NEXT: call void @objc_end_catch() nounwind
void test1_helper(void);
@@ -60,9 +59,8 @@ void test2(void) {
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
-// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) nounwind
// CHECK-NEXT: call void @__cxa_end_catch() nounwind
void test3_helper(void);
diff --git a/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
index a778bcad8fa7..ce7eb3deb141 100644
--- a/test/CodeGenObjCXX/arc-new-delete.mm
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -35,7 +35,7 @@ void test_new(id invalue) {
// CHECK: call i8* @objc_initWeak
new __weak id(invalue);
- // CHECK: call void @objc_release
+ // CHECK: call void @objc_storeStrong
// CHECK: ret void
}
@@ -76,8 +76,7 @@ void test_array_delete(__strong id *sptr, __weak id *wptr) {
// CHECK-NEXT: icmp eq i8** [[BEGIN]], [[END]]
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]],
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null)
// CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK: call void @_ZdaPv
delete [] sptr;
diff --git a/test/CodeGenObjCXX/arc-references.mm b/test/CodeGenObjCXX/arc-references.mm
index 954c02abf23a..121077435da3 100644
--- a/test/CodeGenObjCXX/arc-references.mm
+++ b/test/CodeGenObjCXX/arc-references.mm
@@ -10,7 +10,7 @@ void callee();
// CHECK: define void @_Z5test0v()
void test0() {
// CHECK: call i8* @_Z9getObjectv
- // CHECK-NEXT:: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
const __strong id &ref1 = getObject();
// CHECK: call void @_Z6calleev
callee();
diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm
index 421a9fedffac..0b34538d13ef 100644
--- a/test/CodeGenObjCXX/arc-special-member-functions.mm
+++ b/test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -111,7 +111,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// Implicitly-generated destructor for ObjCBlockMember
// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev
-// CHECK: call void @objc_release(i8*
+// CHECK: call void @objc_storeStrong(i8*
// CHECK: ret
// Implicitly-generated default constructor for ObjCBlockMember
@@ -134,8 +134,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK-NEXT: br label
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null)
// CHECK-NEXT: [[T1:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[T1]],
// CHECK: ret void
@@ -154,7 +153,7 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// Implicitly-generated destructor for ObjCMember
// CHECK: define linkonce_odr void @_ZN10ObjCMemberD2Ev
-// CHECK: call void @objc_release
+// CHECK: call void @objc_storeStrong
// CHECK: ret void
// Implicitly-generated default constructor for ObjCMember
diff --git a/test/CodeGenObjCXX/block-var-layout.mm b/test/CodeGenObjCXX/block-var-layout.mm
index 00dd2c00ef57..f8b6b9c8868c 100644
--- a/test/CodeGenObjCXX/block-var-layout.mm
+++ b/test/CodeGenObjCXX/block-var-layout.mm
@@ -80,7 +80,7 @@ void (^d)() = ^{
// Test4
// struct S (int, id, int, id, int, id)
-// 01 41 11 11
+// 01 41 11 11 00
// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\11\00"
struct S s2;
void (^e)() = ^{
@@ -118,8 +118,8 @@ void Test5() {
union U u2;
// struct s2 (int, id, int, id, int, id?), union u2 (id?)
-// 01 41 11 12 70 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [6 x i8] c"\01A\11\12p\00"
+// 01 41 11 12 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\12\00"
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
diff --git a/test/CodeGenObjCXX/implementation-in-extern-c.mm b/test/CodeGenObjCXX/implementation-in-extern-c.mm
new file mode 100644
index 000000000000..4c1ee256f42f
--- /dev/null
+++ b/test/CodeGenObjCXX/implementation-in-extern-c.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// rdar://12581683
+
+extern "C" {
+@interface RetainBucket
++ (id) sharedRetainBucket;
+@end
+
+@implementation RetainBucket
++ (id) sharedRetainBucket
+{
+ static id sharedBucket = (id)0;
+ return sharedBucket;
+}
+@end
+}
+
diff --git a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
index 29ec9acd381d..a5ce78960914 100644
--- a/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
+++ b/test/CodeGenObjCXX/implicit-copy-assign-operator.mm
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -fobjc-runtime=macosx-fragile-10.5 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -fobjc-runtime=macosx-fragile-10.5 -o - %s | FileCheck %s -check-prefix=CHECK-OBJ
+// RUN: %clang_cc1 -x c++ -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s -check-prefix=CHECK-CPP
+#ifdef __OBJC__
struct A {
A &operator=(const A&);
A &operator=(A&);
@@ -41,17 +43,82 @@ void test_D(D d1, D d2) {
d1 = d2;
}
-// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_
-// CHECK: {{call.*_ZN1AaSERS_}}
-// CHECK: {{call.*_ZN1BaSERS_}}
-// CHECK: {{call.*_ZN1CaSERKS_}}
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
-// CHECK: {{call.*_ZN1BaSERS_}}
-// CHECK: br
-// CHECK: {{call.*_ZN1CaSERKS_}}
-// CHECK: {{call.*@objc_memmove_collectable}}
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
-// CHECK: call void @_ZN11CopyByValueC1ERKS_
-// CHECK: {{call.*_ZN11CopyByValueaSES_}}
-// CHECK: ret
+// CHECK-OBJ: define linkonce_odr %struct.D* @_ZN1DaSERS_
+// CHECK-OBJ: {{call.*_ZN1AaSERS_}}
+// CHECK-OBJ: {{call.*_ZN1BaSERS_}}
+// CHECK-OBJ: {{call.*_ZN1CaSERKS_}}
+// CHECK-OBJ: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK-OBJ: {{call.*_ZN1BaSERS_}}
+// CHECK-OBJ: br
+// CHECK-OBJ: {{call.*_ZN1CaSERKS_}}
+// CHECK-OBJ: {{call.*@objc_memmove_collectable}}
+// CHECK-OBJ: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK-OBJ: call void @_ZN11CopyByValueC1ERKS_
+// CHECK-OBJ: {{call.*_ZN11CopyByValueaSES_}}
+// CHECK-OBJ: ret
+#endif
+namespace PR13329 {
+#ifndef __OBJC__
+ typedef void* id;
+#endif
+ struct POD {
+ id i;
+ short s;
+ };
+
+ struct NonPOD {
+ id i;
+ short s;
+
+ NonPOD();
+ };
+
+ struct DerivedNonPOD: NonPOD {
+ char c;
+ };
+
+ struct DerivedPOD: POD {
+ char c;
+ };
+
+ void testPOD() {
+ POD a;
+ POD b;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 16
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 16
+ b = a;
+ }
+
+ void testNonPOD() {
+ NonPOD a;
+ NonPOD b;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 10
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 10
+ b = a;
+ }
+
+ void testDerivedNonPOD() {
+ DerivedNonPOD a;
+ NonPOD b;
+ DerivedNonPOD c;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 10
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 10
+ (NonPOD&) a = b;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 11
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 11
+ a = c;
+ };
+
+ void testDerivedPOD() {
+ DerivedPOD a;
+ POD b;
+ DerivedPOD c;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 16
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 16
+ (POD&) a = b;
+ // CHECK-OBJ: @objc_memmove_collectable{{.*}}i64 17
+ // CHECK-CPP: @llvm.memcpy{{.*}}i64 17
+ a = c;
+ };
+}
diff --git a/test/CodeGenObjCXX/property-objects.mm b/test/CodeGenObjCXX/property-objects.mm
index 6dfcc27f1921..a3c2ed37466e 100644
--- a/test/CodeGenObjCXX/property-objects.mm
+++ b/test/CodeGenObjCXX/property-objects.mm
@@ -1,8 +1,4 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
-// CHECK-NOT: callq _objc_msgSend_stret
-// CHECK: call void @_ZN1SC1ERKS_
-// CHECK: call %class.S* @_ZN1SaSERKS_
-// CHECK: call %struct.CGRect* @_ZN6CGRectaSERKS_
class S {
public:
@@ -19,13 +15,14 @@ struct CGRect {
S position;
CGRect bounds;
}
+
@property(assign, nonatomic) S position;
@property CGRect bounds;
@property CGRect frame;
- (void)setFrame:(CGRect)frameRect;
- (CGRect)frame;
- (void) initWithOwner;
-- (struct CGRect)extent;
+- (CGRect)extent;
- (void)dealloc;
@end
@@ -33,6 +30,11 @@ struct CGRect {
@synthesize position;
@synthesize bounds;
@synthesize frame;
+
+// CHECK: define internal void @"\01-[I setPosition:]"
+// CHECK: call %class.S* @_ZN1SaSERKS_
+// CHECK-NEXT: ret void
+
- (void)setFrame:(CGRect)frameRect {}
- (CGRect)frame {return bounds;}
@@ -42,14 +44,20 @@ struct CGRect {
labelLayerFrame = self.bounds;
_labelLayer.frame = labelLayerFrame;
}
+
// rdar://8366604
- (void)dealloc
{
CGRect cgrect = self.extent;
}
- (struct CGRect)extent {return bounds;}
+
@end
+// CHECK: 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
int main() {
I *i;
S s1;
@@ -59,7 +67,9 @@ int main() {
// rdar://8379892
// CHECK: define void @_Z1fP1A
-// CHECK: @objc_msgSend to void
+// 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]])
struct X {
X();
X(const X&);
diff --git a/test/CodeGenOpenCL/single-precision-constant.cl b/test/CodeGenOpenCL/single-precision-constant.cl
index 62b37c136137..6ff7bd1bde2d 100644
--- a/test/CodeGenOpenCL/single-precision-constant.cl
+++ b/test/CodeGenOpenCL/single-precision-constant.cl
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
float fn(float f) {
- // CHECK: fmul float
- // CHECK: fadd float
+ // CHECK: tail call float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
return f*2. + 1.;
}
diff --git a/test/Coverage/targets.c b/test/Coverage/targets.c
index 7c05122e6b4f..14b895ea1519 100644
--- a/test/Coverage/targets.c
+++ b/test/Coverage/targets.c
@@ -17,4 +17,3 @@
// <rdar://problem/7181838> clang 1.0 fails to compile Python 2.6
// RUN: %clang -target x86_64-apple-darwin9 -### -S %s -mmacosx-version-min=10.4
-
diff --git a/test/Driver/B-opt.c b/test/Driver/B-opt.c
new file mode 100644
index 000000000000..a0b9a11162dd
--- /dev/null
+++ b/test/Driver/B-opt.c
@@ -0,0 +1,22 @@
+// Check -B driver option.
+//
+// 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"
+//
+// 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"
+//
+// 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"
+//
+// 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"
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o b/test/Driver/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld
index e69de29bb2d1..e69de29bb2d1 100644..100755
--- a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_dynamic.o
+++ b/test/Driver/Inputs/B_opt_tree/dir1/i386-unknown-linux-ld
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o b/test/Driver/Inputs/B_opt_tree/dir1/ld
index e69de29bb2d1..e69de29bb2d1 100644..100755
--- a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_so.o
+++ b/test/Driver/Inputs/B_opt_tree/dir1/ld
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o b/test/Driver/Inputs/B_opt_tree/dir2/ld
index e69de29bb2d1..e69de29bb2d1 100644..100755
--- a/test/Driver/Inputs/basic_android_tree/usr/lib/crtbegin_static.o
+++ b/test/Driver/Inputs/B_opt_tree/dir2/ld
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o b/test/Driver/Inputs/B_opt_tree/dir3/prefix-ld
index e69de29bb2d1..e69de29bb2d1 100644..100755
--- a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_android.o
+++ b/test/Driver/Inputs/B_opt_tree/dir3/prefix-ld
diff --git a/test/PCH/badpch-dir.h.gch/.keep b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep
index e69de29bb2d1..e69de29bb2d1 100644
--- a/test/PCH/badpch-dir.h.gch/.keep
+++ b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/bin/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep
index e69de29bb2d1..e69de29bb2d1 100644
--- a/test/Driver/Inputs/basic_android_tree/usr/lib/crtend_so.o
+++ b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/include/c++/4.4.3/.keep
diff --git a/test/PCH/badpch-empty.h.gch b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep
index e69de29bb2d1..e69de29bb2d1 100644
--- a/test/PCH/badpch-empty.h.gch
+++ b/test/Driver/Inputs/basic_android_tree/arm-linux-androideabi/lib/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbegin.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginT.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginT.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtbeginT.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtend.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/arm-linux-androideabi/4.4.3/crtendS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbegin.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtbeginT.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtend.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtend.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtendS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtendS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/crtendS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbegin.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbegin.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtbeginT.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtend.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtend.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtendS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtendS.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/mipsel-linux-android/4.4.3/mips-r2/crtendS.o
diff --git a/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/bin/.keep b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/bin/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/bin/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/include/c++/4.4.3/.keep b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/include/c++/4.4.3/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/include/c++/4.4.3/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/lib/.keep b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/mipsel-linux-android/lib/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_dynamic.o b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_dynamic.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_dynamic.o
diff --git a/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_so.o b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_so.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_so.o
diff --git a/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_static.o b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_static.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtbegin_static.o
diff --git a/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_android.o b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_android.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_android.o
diff --git a/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_so.o b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_so.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/sysroot/usr/lib/crtend_so.o
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtfastmath.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/lib/.keep b/test/Driver/Inputs/debian_6_mips_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/lib/.keep
diff --git a/test/Driver/Inputs/debian_6_mips_tree/lib32/.keep b/test/Driver/Inputs/debian_6_mips_tree/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/lib32/.keep
diff --git a/test/Driver/Inputs/debian_6_mips_tree/lib64/.keep b/test/Driver/Inputs/debian_6_mips_tree/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/lib64/.keep
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crt1.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crti.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/crti.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/64/crtbegin.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/crtbegin.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib/gcc/mipsel-linux-gnu/4.4/n32/crtbegin.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crt1.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crt1.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crti.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib32/crti.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crt1.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crt1.o
diff --git a/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crti.o b/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_6_mips_tree/usr/lib64/crti.o
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/lib64/.keep b/test/Driver/Inputs/freescale_ppc64_tree/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/lib64/.keep
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crt1.o b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crt1.o
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crti.o b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crti.o
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crtn.o b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/crtn.o
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtbegin.o
diff --git a/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc64_tree/usr/lib64/powerpc64-fsl-linux/4.6.2/crtend.o
diff --git a/test/Driver/Inputs/freescale_ppc_tree/lib/.keep b/test/Driver/Inputs/freescale_ppc_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/lib/.keep
diff --git a/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crt1.o b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crti.o b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crti.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crti.o
diff --git a/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crtn.o b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crtn.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtbegin.o
diff --git a/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtend.o b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtend.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/freescale_ppc_tree/usr/lib/powerpc-fsl-linux/4.6.2/crtend.o
diff --git a/test/Driver/Wp-args.c b/test/Driver/Wp-args.c
index 0ab85b4c9c76..1d1af24804a1 100644
--- a/test/Driver/Wp-args.c
+++ b/test/Driver/Wp-args.c
@@ -11,3 +11,11 @@
// CHECK: "-MT"
//
// PR4062
+
+// RUN: %clang --target i386-pc-linux-gnu -### \
+// RUN: -Wp,-MMD -fsyntax-only %s 2> %t
+// RUN: FileCheck -check-prefix MMD < %t %s
+
+// MMD: "-cc1"
+// MMD-NOT: -MMD
+// MMD: "-dependency-file" "Wp-args.d"
diff --git a/test/Driver/altivec.cpp b/test/Driver/altivec.cpp
index a8936360a3db..4e6fbe597272 100644
--- a/test/Driver/altivec.cpp
+++ b/test/Driver/altivec.cpp
@@ -1,15 +1,15 @@
// Check that we error when -faltivec is specified on non-ppc platforms.
-// RUN: %clang -ccc-clang-archs powerpc -target powerpc-unk-unk -faltivec -fsyntax-only %s
-// RUN: %clang -ccc-clang-archs powerpc64 -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
-// RUN: %clang -ccc-clang-archs powerpc64 -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
+// RUN: %clang -target powerpc-unk-unk -faltivec -fsyntax-only %s
+// RUN: %clang -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
+// RUN: %clang -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
// RUN: %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 -ccc-clang-archs mips -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -ccc-clang-archs mips64 -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -ccc-clang-archs sparc -target sparc-unknown-solaris -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
// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64'
diff --git a/test/Driver/android-standalone.cpp b/test/Driver/android-standalone.cpp
new file mode 100644
index 000000000000..dc41ed7559a2
--- /dev/null
+++ b/test/Driver/android-standalone.cpp
@@ -0,0 +1,65 @@
+// Test header and library paths when Clang is used with Android standalone
+// toolchain.
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi \
+// RUN: -B%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck %s
+// CHECK: {{.*}}clang{{.*}}" "-cc1"
+// CHECK: "-internal-isystem" "{{.*}}/arm-linux-androideabi/include/c++/4.4.3"
+// CHECK: "-internal-isystem" "{{.*}}/arm-linux-androideabi/include/c++/4.4.3/arm-linux-androideabi"
+// CHECK: "-internal-externc-isystem" "{{.*}}/sysroot/include"
+// CHECK: "-internal-externc-isystem" "{{.*}}/sysroot/usr/include"
+// CHECK: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK: "-L{{.*}}/lib/gcc/arm-linux-androideabi/4.4.3"
+// CHECK: "-L{{.*}}/lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/lib"
+// CHECK: "-L{{.*}}/sysroot/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target mipsel-linux-android \
+// RUN: -mips32 \
+// RUN: -B%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS %s
+// CHECK-MIPS: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-MIPS: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3"
+// CHECK-MIPS: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3/mipsel-linux-android"
+// CHECK-MIPS: "-internal-externc-isystem" "{{.*}}/sysroot/include"
+// CHECK-MIPS: "-internal-externc-isystem" "{{.*}}/sysroot/usr/include"
+// CHECK-MIPS: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-MIPS: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3"
+// CHECK-MIPS: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3/../../../../mipsel-linux-android/lib"
+// CHECK-MIPS: "-L{{.*}}/sysroot/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target mipsel-linux-android \
+// RUN: -march=mips32 -mips32r2 \
+// RUN: -B%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-MIPSR2 %s
+// CHECK-MIPSR2: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-MIPSR2: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3"
+// CHECK-MIPSR2: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3/mipsel-linux-android"
+// CHECK-MIPSR2: "-internal-externc-isystem" "{{.*}}/sysroot/include"
+// CHECK-MIPSR2: "-internal-externc-isystem" "{{.*}}/sysroot/usr/include"
+// CHECK-MIPSR2: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-MIPSR2: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3/mips-r2"
+// CHECK-MIPSR2: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3/../../../../mipsel-linux-android/lib"
+// CHECK-MIPSR2: "-L{{.*}}/sysroot/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target mipsel-linux-android \
+// RUN: -mips32 -march=mips32r2 \
+// RUN: -B%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-MIPSR2-A %s
+// CHECK-MIPSR2-A: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-MIPSR2-A: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3"
+// CHECK-MIPSR2-A: "-internal-isystem" "{{.*}}/mipsel-linux-android/include/c++/4.4.3/mipsel-linux-android"
+// CHECK-MIPSR2-A: "-internal-externc-isystem" "{{.*}}/sysroot/include"
+// CHECK-MIPSR2-A: "-internal-externc-isystem" "{{.*}}/sysroot/usr/include"
+// CHECK-MIPSR2-A: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-MIPSR2-A: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3/mips-r2"
+// CHECK-MIPSR2-A: "-L{{.*}}/lib/gcc/mipsel-linux-android/4.4.3/../../../../mipsel-linux-android/lib"
+// CHECK-MIPSR2-A: "-L{{.*}}/sysroot/usr/lib"
diff --git a/test/Driver/apple-kext-i386.cpp b/test/Driver/apple-kext-i386.cpp
deleted file mode 100644
index eb9f9578e9cb..000000000000
--- a/test/Driver/apple-kext-i386.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Check that we transparently fallback to llvm-gcc for i386 kexts, we don't
-// support the ABI they use (yet).
-
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK < %t %s
-
-// CHECK: cc1plus"
-// CHECK: "-fapple-kext"
-
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -mkernel -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-MKERNEL < %t %s
-
-// CHECK-MKERNEL: cc1plus"
-// CHECK-MKERNEL: "-mkernel"
-
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -Wno-self-assign -Wc++11-extensions -Wno-microsoft -Wmicrosoft -Wvla \
-// RUN: -faltivec -mthumb -mcpu=G4 -mlongcall -mno-longcall -msoft-float \
-// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED < %t %s
-
-// CHECK-UNSUPPORTED: cc1plus"
-// CHECK-UNSUPPORTED-NOT: "-Wno-self-assign"
-// CHECK-UNSUPPORTED-NOT: "-Wc++11-extensions"
-// CHECK-UNSUPPORTED-NOT: "-Wno-microsoft"
-// CHECK-UNSUPPORTED-NOT: "-Wmicrosoft"
-// CHECK-UNSUPPORTED-NOT: "-Wvla"
-// CHECK-UNSUPPORTED-NOT: "-faltivec"
-// CHECK-UNSUPPORTED-NOT: "-mthumb"
-// CHECK-UNSUPPORTED-NOT: "-mlongcall"
-// CHECK-UNSUPPORTED: "-mno-longcall"
-// CHECK-UNSUPPORTED: "-msoft-float"
-
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -Wconstant-logical-operand -save-temps \
-// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED2 < %t %s
-
-// CHECK-UNSUPPORTED2: cc1plus"
-// CHECK-UNSUPPORTED2-NOT: "-Wconstant-logical-operand"
-
-// Check that -serialize-diagnostics does not cause an "argument unused" error.
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -Wall -fapple-kext -### -serialize-diagnostics %t.dia -c %s 2>&1 | \
-// RUN: FileCheck --check-prefix=CHECK-UNUSED %s
-
-// Check that --serialize-diagnostics does not cause an "argument unused" error.
-// RUN: %clang -target i386-apple-darwin10 \
-// RUN: -Wall -fapple-kext -### --serialize-diagnostics %t.dia -c %s 2>&1 | \
-// RUN: FileCheck --check-prefix=CHECK-UNUSED %s
-
-// CHECK-UNUSED-NOT: argument unused
-// CHECK-UNUSED: cc1plus
diff --git a/test/Driver/arc.c b/test/Driver/arc.c
index 5a5720c04aee..4c99e5773acc 100644
--- a/test/Driver/arc.c
+++ b/test/Driver/arc.c
@@ -8,10 +8,10 @@
// Just to test clang is working.
# foo
-// CHECK: error: -fobjc-arc is not supported with legacy abi
+// CHECK: error: -fobjc-arc is not supported on platforms using the legacy runtime
// CHECK-NOT: invalid preprocessing directive
-// NOTOBJC-NOT: error: -fobjc-arc is not supported with legacy abi
+// NOTOBJC-NOT: error: -fobjc-arc is not supported on platforms using the legacy runtime
// NOTOBJC: invalid preprocessing directive
-// UNSUPPORTED: error: -fobjc-arc is not supported on current deployment target
+// UNSUPPORTED: error: -fobjc-arc is not supported on versions of OS X prior to 10.6
diff --git a/test/Driver/arm-darwin-builtin.c b/test/Driver/arm-darwin-builtin.c
index 41f13f3f7c23..be50b6898729 100644
--- a/test/Driver/arm-darwin-builtin.c
+++ b/test/Driver/arm-darwin-builtin.c
@@ -8,7 +8,7 @@
// RUX: not grep -- "-fno-builtin-strcat" %t &&
// RUX: not grep -- "-fno-builtin-strcpy" %t &&
-// RUN: %clang -ccc-no-clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t
+// RUN: %clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t
// RUN: not grep -- "-fno-builtin-strcat" %t
// RUN: not grep -- "-fno-builtin-strcpy" %t
diff --git a/test/Driver/asan-ld.c b/test/Driver/asan-ld.c
index daf046b53716..59dbda15c88d 100644
--- a/test/Driver/asan-ld.c
+++ b/test/Driver/asan-ld.c
@@ -4,6 +4,12 @@
// RUN: -target i386-unknown-linux -faddress-sanitizer \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LINUX %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX %s
+//
// CHECK-LINUX: "{{.*}}ld{{(.exe)?}}"
// CHECK-LINUX-NOT: "-lc"
// CHECK-LINUX: libclang_rt.asan-i386.a"
@@ -13,19 +19,32 @@
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -faddress-sanitizer \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// 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-androideabi -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
+//
// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}"
// CHECK-ANDROID-NOT: "-lc"
-// CHECK-ANDROID: "-u" "__asan_preinit" "-lasan"
-// CHECK-ANDROID: "-lasan_preload" "-ldl"
+// CHECK-ANDROID: libclang_rt.asan-arm-android.so"
+// CHECK-ANDROID-NOT: "-lpthread"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -faddress-sanitizer \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -shared \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SHARED %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SHARED %s
+//
// CHECK-ANDROID-SHARED: "{{.*}}ld{{(.exe)?}}"
// CHECK-ANDROID-SHARED-NOT: "-lc"
-// CHECK-ANDROID-SHARED-NOT: "-lasan"
-// CHECK-ANDROID-SHARED: "-lasan_preload" "-ldl"
+// CHECK-ANDROID-SHARED: libclang_rt.asan-arm-android.so"
+// CHECK-ANDROID-SHARED-NOT: "-lpthread"
diff --git a/test/Driver/asan.c b/test/Driver/asan.c
index 4c9a1b6c4423..c9b3796b4436 100644
--- a/test/Driver/asan.c
+++ b/test/Driver/asan.c
@@ -2,6 +2,7 @@
// RUN: %clang -O1 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -O2 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -O3 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -target i386-unknown-unknown -fsanitize=address %s -S -emit-llvm -o - | FileCheck %s
// Verify that -faddress-sanitizer invokes asan instrumentation.
int foo(int *a) { return *a; }
diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c
index a7cda19bcb3f..d25fc8f8afd6 100644
--- a/test/Driver/bindings.c
+++ b/test/Driver/bindings.c
@@ -1,49 +1,25 @@
// Basic binding.
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings %s 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
-// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
-// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings %s 2>&1 | FileCheck %s --check-prefix=CHECK01
+// CHECK01: "clang", inputs: ["{{.*}}bindings.c"], output: "{{.*}}.s"
+// CHECK01: "gcc::Assemble", inputs: ["{{.*}}.s"], output: "{{.*}}.o"
+// CHECK01: "gcc::Link", inputs: ["{{.*}}.o"], output: "a.out"
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang %s 2> %t
-// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
-// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
-// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
-
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -no-integrated-cpp %s 2> %t
-// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t
-// RUN: grep '"gcc::Compile", inputs: \[".*\.i"\], output: ".*\.s"' %t
-// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
-// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
+// Clang control options
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -x c-header %s 2> %t
-// RUN: grep '"gcc::Precompile", inputs: \[".*bindings.c"\], output: ".*bindings.c.gch' %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK05
+// CHECK05: "clang", inputs: ["{{.*}}bindings.c"], output: (nothing)
-// Clang control options
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -fsyntax-only -x c++ %s 2>&1 | FileCheck %s --check-prefix=CHECK08
+// CHECK08: "clang", inputs: ["{{.*}}bindings.c"], output: (nothing)
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -fsyntax-only %s 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -fsyntax-only %s 2> %t
-// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cxx -fsyntax-only -x c++ %s 2> %t
-// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-clang-cxx -fsyntax-only -x c++ %s 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cpp -fsyntax-only -no-integrated-cpp %s 2> %t
-// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t
-// RUN: grep '"clang", inputs: \[".*\.i"\], output: (nothing)' %t
-// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs i386 %s -S -arch ppc 2> %t
-// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
-// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs powerpc %s -S -arch ppc 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings %s -S -arch ppc 2>&1 | FileCheck %s --check-prefix=CHECK11
+// CHECK11: "clang", inputs: ["{{.*}}bindings.c"], output: "bindings.s"
-// RUN: %clang -target powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "" %s -S 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
-// RUN: %clang -target powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "i386" %s -S 2> %t
-// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
+// RUN: %clang -target powerpc-unknown-unknown -ccc-print-bindings %s -S 2>&1 | FileCheck %s --check-prefix=CHECK12
+// CHECK12: "clang", inputs: ["{{.*}}bindings.c"], output: "bindings.s"
// Darwin bindings
-// RUN: %clang -target i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2> %t
-// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
-// RUN: grep '"darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
-// RUN: grep '"darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t
-
+// RUN: %clang -target i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2>&1 | FileCheck %s --check-prefix=CHECK14
+// CHECK14: "clang", inputs: ["{{.*}}bindings.c"], output: "{{.*}}.s"
+// CHECK14: "darwin::Assemble", inputs: ["{{.*}}.s"], output: "{{.*}}.o"
+// CHECK14: "darwin::Link", inputs: ["{{.*}}.o"], output: "a.out"
diff --git a/test/Driver/bitrig.c b/test/Driver/bitrig.c
new file mode 100644
index 000000000000..876a9cdb9eae
--- /dev/null
+++ b/test/Driver/bitrig.c
@@ -0,0 +1,29 @@
+// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-C %s
+// CHECK-LD-C: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-LD-C: ld{{.*}}" {{.*}} "-lc" "-lclang_rt.amd64"
+
+// RUN: %clangxx -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-CXX %s
+// CHECK-LD-CXX: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-LD-CXX: ld{{.*}}" {{.*}} "-lstdc++" "-lm" "-lc" "-lclang_rt.amd64"
+
+// RUN: %clangxx -stdlib=libc++ -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-CXX-STDLIB %s
+// CHECK-LD-CXX-STDLIB: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-LD-CXX-STDLIB: ld{{.*}}" {{.*}} "-lc++" "-lcxxrt" "-lgcc" "-lm" "-lc" "-lclang_rt.amd64"
+
+// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -pthread %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PTHREAD %s
+// CHECK-PTHREAD: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-PTHREAD: ld{{.*}}" {{.*}} "{{.*}}crtbegin.o" {{.*}}.o" "-lpthread" "-lc" "-lclang_rt.amd64" "{{.*}}crtend.o"
+
+// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -pg -pthread %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PG-PTHREAD %s
+// CHECK-PG-PTHREAD: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-PG-PTHREAD: ld{{.*}}" {{.*}} "{{.*}}crtbegin.o" {{.*}}.o" "-lpthread_p" "-lc_p" "-lclang_rt.amd64" "{{.*}}crtend.o"
+
+// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -shared -pg -pthread %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PG-PTHREAD-SHARED %s
+// CHECK-PG-PTHREAD-SHARED: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
+// CHECK-PG-PTHREAD-SHARED: ld{{.*}}" {{.*}} "{{.*}}crtbeginS.o" {{.*}}.o" "-lpthread" "-lclang_rt.amd64" "{{.*}}crtendS.o"
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index 76196da9fc3d..3ddb189eb10d 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -1,22 +1,27 @@
-// RUN: %clang -target i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables -fvisibility=hidden 2> %t.log
-// RUN: grep '"-triple" "i386-unknown-unknown"' %t.log
-// RUN: grep '"-S"' %t.log
-// RUN: grep '"-disable-free"' %t.log
-// RUN: grep '"-mrelocation-model" "static"' %t.log
-// RUN: grep '"-mdisable-fp-elim"' %t.log
-// RUN: grep '"-munwind-tables"' %t.log
-// RUN: grep '"-Os"' %t.log
-// RUN: grep '"-o" .*clang-translation.*' %t.log
-// RUN: grep '"-masm-verbose"' %t.log
-// RUN: grep '"-fvisibility" "hidden"' %t.log
-// RUN: %clang -target i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log
-// RUN: grep '"-target-cpu" "yonah"' %t.log
-// RUN: %clang -target x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log
-// RUN: grep '"-target-cpu" "core2"' %t.log
+// RUN: %clang -target i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables -fvisibility=hidden 2>&1 | FileCheck -check-prefix=I386 %s
+// I386: "-triple" "i386-unknown-unknown"
+// I386: "-S"
+// I386: "-disable-free"
+// I386: "-mrelocation-model" "static"
+// I386: "-mdisable-fp-elim"
+// I386: "-masm-verbose"
+// I386: "-munwind-tables"
+// I386: "-Os"
+// I386: "-fvisibility"
+// I386: "hidden"
+// I386: "-o"
+// I386: clang-translation
+// RUN: %clang -target i386-apple-darwin9 -### -S %s -o %t.s 2>&1 | \
+// RUN: FileCheck -check-prefix=YONAH %s
+// YONAH: "-target-cpu"
+// YONAH: "yonah"
+// RUN: %clang -target x86_64-apple-darwin9 -### -S %s -o %t.s 2>&1 | \
+// RUN: FileCheck -check-prefix=CORE2 %s
+// CORE2: "-target-cpu"
+// CORE2: "core2"
-// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
-// RUN: -arch armv7
-// RUN: FileCheck -check-prefix=ARMV7_DEFAULT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s -arch armv7 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMV7_DEFAULT %s
// ARMV7_DEFAULT: clang
// ARMV7_DEFAULT: "-cc1"
// ARMV7_DEFAULT-NOT: "-msoft-float"
@@ -24,9 +29,8 @@
// ARMV7_DEFAULT-NOT: "-msoft-float"
// ARMV7_DEFAULT: "-x" "c"
-// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
-// RUN: -arch armv7 -msoft-float
-// RUN: FileCheck -check-prefix=ARMV7_SOFTFLOAT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s -arch armv7 \
+// RUN: -msoft-float 2>&1 | FileCheck -check-prefix=ARMV7_SOFTFLOAT %s
// ARMV7_SOFTFLOAT: clang
// ARMV7_SOFTFLOAT: "-cc1"
// ARMV7_SOFTFLOAT: "-msoft-float"
@@ -35,9 +39,8 @@
// ARMV7_SOFTFLOAT: "-neon"
// ARMV7_SOFTFLOAT: "-x" "c"
-// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
-// RUN: -arch armv7 -mhard-float
-// RUN: FileCheck -check-prefix=ARMV7_HARDFLOAT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s -arch armv7 \
+// RUN: -mhard-float 2>&1 | FileCheck -check-prefix=ARMV7_HARDFLOAT %s
// ARMV7_HARDFLOAT: clang
// ARMV7_HARDFLOAT: "-cc1"
// ARMV7_HARDFLOAT-NOT: "-msoft-float"
@@ -45,32 +48,60 @@
// ARMV7_HARDFLOAT-NOT: "-msoft-float"
// ARMV7_HARDFLOAT: "-x" "c"
-// RUN: %clang -target arm-linux -### -S %s 2> %t.log \
-// RUN: -march=armv5e
-// RUN: FileCheck -check-prefix=ARMV5E %s < %t.log
+// RUN: %clang -target arm-linux -### -S %s -march=armv5e 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMV5E %s
// ARMV5E: clang
// ARMV5E: "-cc1"
// ARMV5E: "-target-cpu" "arm1022e"
-// RUN: %clang -ccc-clang-archs powerpc64 \
-// RUN: -target powerpc64-unknown-linux-gnu -### -S %s 2> %t.log \
-// RUN: -mcpu=G5
-// RUN: FileCheck -check-prefix=PPCG5 %s < %t.log
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=G5 2>&1 | FileCheck -check-prefix=PPCG5 %s
// PPCG5: clang
// PPCG5: "-cc1"
// PPCG5: "-target-cpu" "g5"
-// RUN: %clang -ccc-clang-archs powerpc64 \
-// RUN: -target powerpc64-unknown-linux-gnu -### -S %s 2> %t.log \
-// RUN: -mcpu=power7
-// RUN: FileCheck -check-prefix=PPCPWR7 %s < %t.log
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power7 2>&1 | FileCheck -check-prefix=PPCPWR7 %s
// PPCPWR7: clang
// PPCPWR7: "-cc1"
// PPCPWR7: "-target-cpu" "pwr7"
-// RUN: %clang -ccc-clang-archs powerpc64 \
-// RUN: -target powerpc64-unknown-linux-gnu -### -S %s 2> %t.log
-// RUN: FileCheck -check-prefix=PPC64NS %s < %t.log
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s 2>&1 | FileCheck -check-prefix=PPC64NS %s
// PPC64NS: clang
// PPC64NS: "-cc1"
// PPC64NS: "-target-cpu" "ppc64"
+
+// RUN: %clang -target powerpc-fsl-linux -### -S %s \
+// RUN: -mcpu=e500mc 2>&1 | FileCheck -check-prefix=PPCE500MC %s
+// PPCE500MC: clang
+// PPCE500MC: "-cc1"
+// PPCE500MC: "-target-cpu" "e500mc"
+
+// RUN: %clang -target powerpc64-fsl-linux -### -S \
+// RUN: %s -mcpu=e5500 2>&1 | FileCheck -check-prefix=PPCE5500 %s
+// PPCE5500: clang
+// PPCE5500: "-cc1"
+// PPCE5500: "-target-cpu" "e5500"
+
+// RUN: %clang -target amd64-unknown-openbsd5.2 -### -S %s 2>&1 | \
+// RUN: FileCheck -check-prefix=AMD64 %s
+// AMD64: clang
+// AMD64: "-cc1"
+// AMD64: "-triple"
+// AMD64: "amd64-unknown-openbsd5.2"
+// AMD64: "-munwind-tables"
+
+// RUN: %clang -target amd64--mingw32 -### -S %s 2>&1 | \
+// RUN: FileCheck -check-prefix=AMD64-MINGW %s
+// AMD64-MINGW: clang
+// AMD64-MINGW: "-cc1"
+// AMD64-MINGW: "-triple"
+// AMD64-MINGW: "amd64--mingw32"
+// AMD64-MINGW: "-munwind-tables"
+
+// RUN: %clang -target i386-linux-android -### -S %s 2>&1 \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=ANDROID-X86 %s
+// ANDROID-X86: clang
+// ANDROID-X86: "-target-cpu" "core2"
diff --git a/test/Driver/cpath.c b/test/Driver/cpath.c
index bd7c8d0ab5f0..ea6ba49d6d51 100644
--- a/test/Driver/cpath.c
+++ b/test/Driver/cpath.c
@@ -1,8 +1,8 @@
// RUN: mkdir -p %T/test1 %T/test2 %T/test3
// RUN: env "CPATH=%T/test1%{pathsep}%T/test2" %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
-// CPATH: -I {{.*}}/test1
-// CPATH: -I {{.*}}/test2
+// CPATH: -I{{.*}}/test1
+// CPATH: -I{{.*}}/test2
// CPATH: search starts here
// CPATH: test1
// CPATH: test2
diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c
index 7adaf42a2c95..bfcd5732b33d 100644
--- a/test/Driver/crash-report.c
+++ b/test/Driver/crash-report.c
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: env TMPDIR=%t TEMP=%t TMP=%t %clang -fsyntax-only %s \
+// RUN: 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/ \
@@ -25,3 +25,4 @@ FOO
// CHECKSH-NOT: -iwithprefixbefore /tmp/
// CHECKSH-NOT: -internal-isystem /tmp/
// CHECKSH-NOT: -internal-externc-isystem /tmp/
+// CHECKSH-NOT: -dwarf-debug-flags
diff --git a/test/Driver/darwin-arch-default.c b/test/Driver/darwin-arch-default.c
new file mode 100644
index 000000000000..60bf61de8a34
--- /dev/null
+++ b/test/Driver/darwin-arch-default.c
@@ -0,0 +1,7 @@
+// Check that the name of the arch we bind is "ppc" not "powerpc".
+//
+// RUN: %clang -target powerpc-apple-darwin8 -### \
+// RUN: -ccc-print-phases %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-POWERPC < %t %s
+//
+// CHECK-POWERPC: bind-arch, "ppc"
diff --git a/test/Driver/darwin-asan-nofortify.c b/test/Driver/darwin-asan-nofortify.c
new file mode 100644
index 000000000000..7f325e097b38
--- /dev/null
+++ b/test/Driver/darwin-asan-nofortify.c
@@ -0,0 +1,6 @@
+// Make sure AddressSanitizer disables _FORTIFY_SOURCE on Darwin.
+
+// RUN: %clang -faddress-sanitizer %s -E -dM -target x86_64-darwin - | FileCheck %s
+// RUN: %clang -fsanitize=address %s -E -dM -target x86_64-darwin - | FileCheck %s
+
+// CHECK: #define _FORTIFY_SOURCE 0
diff --git a/test/Driver/darwin-cc.c b/test/Driver/darwin-cc.c
deleted file mode 100644
index 85cdf12fb19f..000000000000
--- a/test/Driver/darwin-cc.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang -ccc-no-clang -target i386-apple-darwin10 -m32 -### -MD -g -fast -Q -dA -mkernel -ansi -aFOO -S -o /tmp/OUTPUTNAME -g0 -gfull -O2 -Werror -pedantic -Wmost -w -std=c99 -trigraphs -v -pg -fFOO -undef -Qn --param a=b -fmudflap -coverage -save-temps -nostdinc -I ARG0 -F ARG1 -I ARG2 -P -MF ARG3 -MG -MP -remap -g3 -H -D ARG4 -U ARG5 -A ARG6 -D ARG7 -U ARG8 -A ARG9 -include ARG10 -pthread %s 2> %t.log
-// RUN: FileCheck %s < %t.log
-// CHECK: {{ ".*cc1.*" "-E" "-nostdinc" "-v" "-I" "ARG0" "-FARG1" "-I" "ARG2" "-P" "-MD" "[^"]*/OUTPUTNAME.d" "-MF" "ARG3" "-MG" "-MP" "-MQ" "[^"]*/OUTPUTNAME" "-remap" "-dD" "-H" "-D__STATIC__" "-D_REENTRANT" "-D" "ARG4" "-U" "ARG5" "-A" "ARG6" "-D" "ARG7" "-U" "ARG8" "-A" "ARG9" "-include" "ARG10" ".*darwin-cc.c" "-D_MUDFLAP" "-include" "mf-runtime.h" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-std=c99" "-trigraphs" "-Werror" "-pedantic" "-Wmost" "-w" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-O2" "-undef" "-fpch-preprocess" "-o" ".*darwin-cc.i"}}
-// CHECK: {{ ".*cc1.*" "-fpreprocessed" ".*darwin-cc.i" "-O3" "-dumpbase" ".*darwin-cc.c" "-dA" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-aFOO" "-auxbase-strip" "[^"]*/OUTPUTNAME" "-g" "-g0" "-g" "-g3" "-O2" "-Werror" "-pedantic" "-Wmost" "-w" "-ansi" "-std=c99" "-trigraphs" "-version" "-p" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-undef" "-fno-ident" "-o" "[^"]*/OUTPUTNAME" "--param" "a=b" "-fno-builtin" "-fno-merge-constants" "-fprofile-arcs" "-ftest-coverage"}}
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 4cda37f9b2e3..cd511e034f13 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -80,7 +80,7 @@
// LINK_OLDER_NODEMANGLE-NOT: "-demangle"
// LINK_OLDER_NODEMANGLE: "-lSystem"
-// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %s \
// RUN: -mlinker-version=117 -flto 2> %t.log
// RUN: cat %t.log
// RUN: FileCheck -check-prefix=LINK_OBJECT_LTO_PATH %s < %t.log
@@ -122,6 +122,10 @@
// RUN: FileCheck -check-prefix=LINK_NO_CRT1 %s < %t.log
// LINK_NO_CRT1-NOT: crt
+// RUN: %clang -target armv7-apple-ios6.0 -miphoneos-version-min=6.0 -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_NO_IOS_CRT1 %s < %t.log
+// LINK_NO_IOS_CRT1-NOT: crt
+
// RUN: %clang -target i386-apple-darwin12 -pg -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK_PG %s < %t.log
// LINK_PG: -lgcrt1.o
diff --git a/test/Driver/darwin-sdkroot.c b/test/Driver/darwin-sdkroot.c
new file mode 100644
index 000000000000..5abf08156362
--- /dev/null
+++ b/test/Driver/darwin-sdkroot.c
@@ -0,0 +1,22 @@
+// Check that SDKROOT is used to define the default for -isysroot on Darwin.
+//
+// RUN: rm -rf %t.tmpdir
+// RUN: mkdir -p %t.tmpdir
+// RUN: env SDKROOT=%t.tmpdir %clang -target x86_64-apple-darwin10 \
+// RUN: -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-BASIC < %t.log %s
+//
+// CHECK-BASIC: clang
+// CHECK-BASIC: "-cc1"
+// CHECK-BASIC: "-isysroot" "{{.*tmpdir}}"
+
+// Check that we don't use SDKROOT as the default if it is not a valid path.
+
+// RUN: rm -rf %t.nonpath
+// RUN: env SDKROOT=%t.nonpath %clang -target x86_64-apple-darwin10 \
+// RUN: -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-NONPATH < %t.log %s
+//
+// CHECK-NONPATH: clang
+// CHECK-NONPATH: "-cc1"
+// CHECK-NONPATH-NOT: "-isysroot"
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index 8426f0950acf..17bf6ed617dd 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -12,16 +12,46 @@
// CHECK-NO-INFS: "-cc1"
// CHECK-NO-INFS: "-menable-no-infs"
//
+// RUN: %clang -### -fno-fast-math -fno-honor-infinities -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH-NO-INFS %s
+// CHECK-NO-FAST-MATH-NO-INFS: "-cc1"
+// CHECK-NO-FAST-MATH-NO-INFS: "-menable-no-infs"
+//
+// RUN: %clang -### -fno-honor-infinities -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-INFS-NO-FAST-MATH %s
+// CHECK-NO-INFS-NO-FAST-MATH: "-cc1"
+// CHECK-NO-INFS-NO-FAST-MATH-NOT: "-menable-no-infs"
+//
// RUN: %clang -### -fno-honor-nans -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-NANS %s
// CHECK-NO-NANS: "-cc1"
// CHECK-NO-NANS: "-menable-no-nans"
//
+// RUN: %clang -### -fno-fast-math -fno-honor-nans -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH-NO-NANS %s
+// CHECK-NO-FAST-MATH-NO-NANS: "-cc1"
+// CHECK-NO-FAST-MATH-NO-NANS: "-menable-no-nans"
+//
+// RUN: %clang -### -fno-honor-nans -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NANS-NO-FAST-MATH %s
+// CHECK-NO-NANS-NO-FAST-MATH: "-cc1"
+// CHECK-NO-NANS-NO-FAST-MATH-NOT: "-menable-no-nans"
+//
// RUN: %clang -### -fmath-errno -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
// 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
// RUN: %clang -### -target i686-apple-darwin -c %s 2>&1 \
@@ -43,6 +73,18 @@
// CHECK-UNSAFE-MATH: "-cc1"
// CHECK-UNSAFE-MATH: "-menable-unsafe-fp-math"
//
+// RUN: %clang -### -fno-fast-math -fno-math-errno -fassociative-math -freciprocal-math \
+// RUN: -fno-signed-zeros -fno-trapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH-UNSAFE-MATH %s
+// CHECK-NO-FAST-MATH-UNSAFE-MATH: "-cc1"
+// CHECK-NO-FAST-MATH-UNSAFE-MATH: "-menable-unsafe-fp-math"
+//
+// RUN: %clang -### -fno-fast-math -fno-math-errno -fassociative-math -freciprocal-math \
+// RUN: -fno-fast-math -fno-signed-zeros -fno-trapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-UNSAFE-MATH-NO-FAST-MATH %s
+// CHECK-UNSAFE-MATH-NO-FAST-MATH: "-cc1"
+// CHECK-UNSAFE-MATH-NO-FAST-MATH-NOT: "-menable-unsafe-fp-math"
+//
// Check that various umbrella flags also enable these frontend options.
// RUN: %clang -### -ffast-math -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-INFS %s
@@ -63,12 +105,19 @@
// impact remains even if every optimization is disabled.
// RUN: %clang -### -ffast-math -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// RUN: %clang -### -fno-fast-math -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
// RUN: %clang -### -ffast-math -fno-finite-math-only \
// RUN: -fno-unsafe-math-optimizations -fmath-errno -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
// CHECK-FAST-MATH: "-cc1"
// CHECK-FAST-MATH: "-ffast-math"
//
+// RUN: %clang -### -ffast-math -fno-fast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FAST-MATH %s
+// CHECK-NO-FAST-MATH: "-cc1"
+// CHECK-NO-FAST-MATH-NOT: "-ffast-math"
+//
// Check various means of disabling these flags, including disabling them after
// they've been enabled via an umbrella flag.
// RUN: %clang -### -fno-honor-infinities -fhonor-infinities -c %s 2>&1 \
diff --git a/test/Driver/freebsd-mips-as.c b/test/Driver/freebsd-mips-as.c
new file mode 100644
index 000000000000..54ff1875155b
--- /dev/null
+++ b/test/Driver/freebsd-mips-as.c
@@ -0,0 +1,81 @@
+// Check passing options to the assembler for MIPS targets.
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-AS %s
+// MIPS32-EB-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB-AS-NOT: "-KPIC"
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -fPIC -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-PIC %s
+// MIPS32-EB-PIC: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB-PIC: "-KPIC"
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -fpic -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-PIC-SMALL %s
+// MIPS32-EB-PIC-SMALL: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB-PIC-SMALL: "-KPIC"
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -fPIE -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-PIE %s
+// MIPS32-EB-PIE: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB-PIE: "-KPIC"
+//
+// RUN: %clang -target mips-unknown-freebsd -### \
+// RUN: -no-integrated-as -fpie -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-PIE-SMALL %s
+// MIPS32-EB-PIE-SMALL: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB-PIE-SMALL: "-KPIC"
+//
+// RUN: %clang -target mipsel-unknown-freebsd -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EL-AS %s
+// MIPS32-EL-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EL"
+//
+// RUN: %clang -target mips64-unknown-freebsd -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EB-AS %s
+// MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB"
+//
+// RUN: %clang -target mips64el-unknown-freebsd -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EL-AS %s
+// MIPS64-EL-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EL"
+//
+// RUN: %clang -target mips-unknown-freebsd -mabi=eabi -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-EABI %s
+// MIPS-EABI: as{{(.exe)?}}" "-march" "mips32" "-mabi" "eabi" "-EB"
+//
+// RUN: %clang -target mips64-unknown-freebsd -mabi=n32 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-N32 %s
+// MIPS-N32: as{{(.exe)?}}" "-march" "mips64" "-mabi" "n32" "-EB"
+//
+// RUN: %clang -target mips-linux-freebsd -march=mips32r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-32R2 %s
+// MIPS-32R2: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-unknown-freebsd -mips32 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-32 %s
+// MIPS-ALIAS-32: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-unknown-freebsd -mips32r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-32R2 %s
+// MIPS-ALIAS-32R2: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-unknown-freebsd -mips64 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64 %s
+// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB"
+//
+// RUN: %clang -target mips-unknown-freebsd -mips64r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2 %s
+// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EB"
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index 642c60ce77b5..db53d4ddd8a1 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -1,5 +1,5 @@
-// REQUIRES: ppc32-registered-target,ppc64-registered-target
-// RUN: %clang -ccc-clang-archs powerpc -no-canonical-prefixes \
+// REQUIRES: ppc32-registered-target,ppc64-registered-target,mips-registered-target
+// RUN: %clang -no-canonical-prefixes \
// RUN: -target powerpc-pc-freebsd8 %s \
// RUN: --sysroot=%S/Inputs/basic_freebsd_tree -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PPC %s
@@ -7,7 +7,7 @@
// CHECK-PPC: ld{{.*}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-PPC: "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L[[SYSROOT]]/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o"
//
-// RUN: %clang -ccc-clang-archs powerpc64 -no-canonical-prefixes \
+// RUN: %clang -no-canonical-prefixes \
// RUN: -target powerpc64-pc-freebsd8 %s \
// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PPC64 %s
@@ -43,4 +43,56 @@
// CHECK-LDFLAGS8: --enable-new-dtags
// CHECK-LDFLAGS9: --hash-style=both
// CHECK-LDFLAGS9: --enable-new-dtags
+//
+// Check that we do not pass --hash-style=gnu and --hash-style=both to linker
+// and provide correct path to the dynamic linker for MIPS platforms.
+// Also verify that we tell the assembler to target the right ISA and ABI.
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips-unknown-freebsd10.0 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS %s
+// CHECK-MIPS: "{{[^" ]*}}ld{{[^" ]*}}"
+// CHECK-MIPS: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
+// CHECK-MIPS-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mipsel-unknown-freebsd10.0 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPSEL %s
+// CHECK-MIPSEL: "{{[^" ]*}}ld{{[^" ]*}}"
+// CHECK-MIPSEL: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
+// CHECK-MIPSEL-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips64-unknown-freebsd10.0 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64 %s
+// CHECK-MIPS64: "{{[^" ]*}}ld{{[^" ]*}}"
+// CHECK-MIPS64: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
+// CHECK-MIPS64-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips64el-unknown-freebsd10.0 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL %s
+// CHECK-MIPS64EL: "{{[^" ]*}}ld{{[^" ]*}}"
+// CHECK-MIPS64EL: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
+// CHECK-MIPS64EL-NOT: "--hash-style={{gnu|both}}"
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd8 -static %s \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-STATIC %s
+// CHECK-STATIC: crt1.o
+// CHECK-STATIC: crtbeginT.o
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd8 -shared %s \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-SHARED %s
+// CHECK-SHARED: crti.o
+// CHECK-SHARED: crtbeginS.o
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd8 -pie %s \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PIE %s
+// CHECK-PIE: pie
+// CHECK-PIE: Scrt1.o
+// CHECK-PIE: crtbeginS.o
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd8 %s \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NORMAL %s
+// CHECK-NORMAL: crt1.o
+// CHECK-NORMAL: crtbegin.o
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
new file mode 100644
index 000000000000..9f7cd46c6cf7
--- /dev/null
+++ b/test/Driver/fsanitize.c
@@ -0,0 +1,23 @@
+// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow),?){11}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -fno-sanitize=float-cast-overflow,vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size),?){9}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with '-fno-rtti'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,thread -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANT
+// CHECK-SANA-SANT: '-fsanitize=address' not allowed with '-fsanitize=thread'
+
+// RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -c -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
+// CHECK-ASAN-TSAN: '-faddress-sanitizer' not allowed with '-fthread-sanitizer'
+
+// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fthread-sanitizer -fno-thread-sanitizer -faddress-sanitizer -fno-address-sanitizer -c -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEPRECATED
+// CHECK-DEPRECATED: argument '-fcatch-undefined-behavior' is deprecated, use '-fsanitize=undefined' 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 '-fno-address-sanitizer' is deprecated, use '-fno-sanitize=address' instead
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index 77f401b92e5a..8eead214feef 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -1,7 +1,7 @@
// Check that we don't try to forward -Xclang or -mlinker-version to GCC.
//
// RUN: %clang -target powerpc-unknown-unknown \
-// RUN: -ccc-clang-archs i386 -c %s \
+// RUN: -c %s \
// RUN: -Xclang foo-bar \
// RUN: -mlinker-version=10 -### 2> %t
// RUN: FileCheck < %t %s
diff --git a/test/Driver/hello.c b/test/Driver/hello.c
deleted file mode 100644
index c2260e53eb38..000000000000
--- a/test/Driver/hello.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// RUN: %clang -ccc-echo -o %t.exe %s 2> %t.log
-
-// Make sure we used clang.
-// RUN: grep 'clang\(-[0-9.]\+\)\?\(\.[Ee][Xx][Ee]\)\?" -cc1 .*hello.c' %t.log
-
-// RUN: %t.exe > %t.out
-// RUN: grep "I'm a little driver, short and stout." %t.out
-
-// FIXME: We don't have a usable assembler on Windows, so we can't build real
-// apps yet.
-// XFAIL: win32
-
-#include <stdio.h>
-
-int main() {
- printf("I'm a little driver, short and stout.");
- return 0;
-}
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
index 5a3ec872b4fe..2b54ecf7c150 100644
--- a/test/Driver/immediate-options.c
+++ b/test/Driver/immediate-options.c
@@ -1,4 +1,6 @@
-// RUN: %clang --help
-// RUN: %clang --help-hidden
+// 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
diff --git a/test/Driver/ios-simulator-arcruntime.c b/test/Driver/ios-simulator-arcruntime.c
index 33d34924ced1..605df93f4957 100644
--- a/test/Driver/ios-simulator-arcruntime.c
+++ b/test/Driver/ios-simulator-arcruntime.c
@@ -1,8 +1,8 @@
-// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
-// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -mios-simulator-version-min=4.2.1 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -mios-simulator-version-min=5.0.0 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
//
-// CHECK-OPTIONS1: i386-apple-macosx10.6.0
+// CHECK-OPTIONS1: i386-apple-ios4.2.1
// CHECK-OPTIONS1: -fobjc-runtime=ios-4.2.1
-// CHECK-OPTIONS2: i386-apple-macosx10.6.0
+// CHECK-OPTIONS2: i386-apple-ios5.0.0
// CHECK-OPTIONS2: -fobjc-runtime=ios-5.0.0
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
index f68b2206f209..61388c5ca186 100644
--- a/test/Driver/le32-unknown-nacl.cpp
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
-// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -o - | FileCheck %s
-// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+// 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 -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
diff --git a/test/Driver/linker-opts.c b/test/Driver/linker-opts.c
index 85e180c4e210..2a96a17c70d3 100644
--- a/test/Driver/linker-opts.c
+++ b/test/Driver/linker-opts.c
@@ -1,5 +1,5 @@
// RUN: env LIBRARY_PATH=%T/test1 %clang -x c %s -### 2>&1 | FileCheck %s
-// CHECK: "-L" "{{.*}}/test1"
+// CHECK: "-L{{.*}}/test1"
// GCC driver is used as linker on cygming. It should be aware of LIBRARY_PATH.
// XFAIL: cygwin,mingw32,win32
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
index ea82660811d2..065bd34566d7 100644
--- a/test/Driver/linux-header-search.cpp
+++ b/test/Driver/linux-header-search.cpp
@@ -45,7 +45,7 @@
// 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"
-// RUN: %clang -ccc-clang-archs powerpc -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target powerpc-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
@@ -59,7 +59,7 @@
// 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"
-// RUN: %clang -ccc-clang-archs powerpc64 -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target powerpc64-linux-gnu \
// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index a6831b62a904..72370297f40e 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -238,33 +238,47 @@
// 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 -ccc-clang-archs mips \
+// 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 -ccc-clang-archs mipsel \
+// 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 -ccc-clang-archs mips64 \
+// 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 -ccc-clang-archs mips64el \
+// 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: | 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: | FileCheck --check-prefix=CHECK-MIPS64EL-N32 %s
+// CHECK-MIPS64EL-N32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MIPS64EL-N32: "-m" "elf32ltsmipn32"
+// CHECK-MIPS64EL-N32: "-dynamic-linker" "{{.*}}/lib32/ld.so.1"
+// CHECK-MIPS64EL-N32-NOT: "--hash-style={{gnu|both}}"
//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -361,11 +375,45 @@
// 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: --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: "-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: --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: "-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/../../.."
+// CHECK-DEBIAN-MIPS64EL-N32: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib"
//
// Test linker invocation on Android.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// 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: --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: --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: --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"
@@ -376,10 +424,26 @@
// CHECK-ANDROID: "{{.*}}/crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// 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: --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: --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: --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: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-SO-NOT: "gcc_s"
@@ -388,7 +452,22 @@
// CHECK-ANDROID-SO: "{{.*}}/crtend_so.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// 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: --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: --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: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// CHECK-ANDROID-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -398,3 +477,120 @@
// CHECK-ANDROID-STATIC: "-lgcc"
// CHECK-ANDROID-STATIC-NOT: "gcc_s"
// CHECK-ANDROID-STATIC: "{{.*}}/crtend_android.o"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// 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: --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: --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: --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: "-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 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: --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: "-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"
+// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/usr/lib/../lib"
+// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../.."
+// CHECK-DEBIAN-ML-MIPSEL: "-L[[SYSROOT]]/lib"
+// 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: --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: "-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"
+// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/usr/lib/../lib64"
+// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../.."
+// CHECK-DEBIAN-ML-MIPS64EL: "-L[[SYSROOT]]/lib"
+// 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: --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: "-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"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/../lib32"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib/gcc/mipsel-linux-gnu/4.4/../../.."
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-ML-MIPS64EL-N32: "-L[[SYSROOT]]/usr/lib"
+//
+// Test linker invocation for Freescale SDK (OpenEmbedded).
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// 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: "-L[[SYSROOT]]/usr/lib"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// 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: "-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: --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: --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: --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: --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: --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-NOCRTFASTMATH-NOT: crtfastmath.o
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
index 0ace4dd51c74..fbaf62fdadd5 100644
--- a/test/Driver/mips-as.c
+++ b/test/Driver/mips-as.c
@@ -1,3 +1,5 @@
+// REQUIRES: mips-registered-target
+//
// Check passing options to the assembler for MIPS targets.
//
// RUN: %clang -target mips-linux-gnu -### \
@@ -36,3 +38,28 @@
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-N32 %s
// MIPS-N32: as{{(.exe)?}}" "-march" "mips64" "-mabi" "n32" "-EB"
+//
+// RUN: %clang -target mips-linux-gnu -march=mips32r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-32R2 %s
+// MIPS-32R2: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-linux-gnu -mips32 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-32 %s
+// MIPS-ALIAS-32: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-linux-gnu -mips32r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-32R2 %s
+// MIPS-ALIAS-32R2: as{{(.exe)?}}" "-march" "mips32r2" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mips-linux-gnu -mips64 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64 %s
+// MIPS-ALIAS-64: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB"
+//
+// RUN: %clang -target mips-linux-gnu -mips64r2 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-ALIAS-64R2 %s
+// MIPS-ALIAS-64R2: as{{(.exe)?}}" "-march" "mips64r2" "-mabi" "64" "-EB"
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index 5be268318886..28048e7740f2 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -37,3 +37,9 @@
// RUN: -mdspr2 -mno-dspr2 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NOMDSPR2 %s
// CHECK-NOMDSPR2: "-target-feature" "-dspr2"
+//
+// -G
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -G 16 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS-G %s
+// CHECK-MIPS-G: "-mllvm" "-mips-ssection-threshold=16"
diff --git a/test/Driver/mips-float.c b/test/Driver/mips-float.c
index 95eb0025cc09..886c3355a963 100644
--- a/test/Driver/mips-float.c
+++ b/test/Driver/mips-float.c
@@ -3,19 +3,19 @@
// when build for MIPS platforms.
//
// Default
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu \
// RUN: | FileCheck --check-prefix=CHECK-DEF %s
// CHECK-DEF: "-mfloat-abi" "hard"
//
// -mhard-float
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mhard-float \
// RUN: | FileCheck --check-prefix=CHECK-HARD %s
// CHECK-HARD: "-mfloat-abi" "hard"
//
// -msoft-float
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// 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: "-msoft-float"
@@ -23,13 +23,13 @@
// CHECK-SOFT: "-target-feature" "+soft-float"
//
// -mfloat-abi=hard
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mfloat-abi=hard \
// RUN: | FileCheck --check-prefix=CHECK-ABI-HARD %s
// CHECK-ABI-HARD: "-mfloat-abi" "hard"
//
// -mfloat-abi=soft
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// 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: "-msoft-float"
@@ -37,7 +37,7 @@
// CHECK-ABI-SOFT: "-target-feature" "+soft-float"
//
// -mfloat-abi=single
-// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
// RUN: -target mips-linux-gnu -mfloat-abi=single \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SINGLE %s
// CHECK-ABI-SINGLE: "-target-feature" "+single-float"
diff --git a/test/Driver/no-objc-arr.m b/test/Driver/no-objc-arr.m
index e44939337a6a..21246a37a6af 100644
--- a/test/Driver/no-objc-arr.m
+++ b/test/Driver/no-objc-arr.m
@@ -1,4 +1,5 @@
// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -Xclang -verify %s
+// expected-no-diagnostics
// rdar://8949617
void * FOO() {
diff --git a/test/Driver/objc++-cpp-output.mm b/test/Driver/objc++-cpp-output.mm
index bb8814428ac4..9c4d55379ad1 100644
--- a/test/Driver/objc++-cpp-output.mm
+++ b/test/Driver/objc++-cpp-output.mm
@@ -1,5 +1,8 @@
// RUN: %clang -x objc++-cpp-output -c %s -o /dev/null
+// PR13820
+// REQUIRES: LP64
+
// Should compile without errors
@protocol P
- (void)m;
diff --git a/test/Driver/objc-cpp-output.m b/test/Driver/objc-cpp-output.m
index 6d974838c150..8c174f773205 100644
--- a/test/Driver/objc-cpp-output.m
+++ b/test/Driver/objc-cpp-output.m
@@ -1,5 +1,8 @@
// RUN: %clang -x objc-cpp-output -c %s -o /dev/null
+// PR13820
+// REQUIRES: LP64
+
// Should compile without errors
@protocol P
- (void)m;
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index 911c452c6c18..afd8b5ade921 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -1,5 +1,9 @@
-// RUN: %clang -no-canonical-prefixes -ccc-clang-archs "" -target i686-pc-openbsd %s -### 2> %t.log
-// RUN: FileCheck -input-file %t.log %s
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD %s
+// CHECK-LD: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
-// CHECK: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
-// CHECK: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -pg -pthread %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PG %s
+// CHECK-PG: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-PG: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lpthread_p" "-lc_p" "-lgcc" "{{.*}}crtend.o"
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 3952f85ceb29..54e5982c085f 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -5,24 +5,35 @@
// CHECK-NO-PIC-NOT: "-pic-level"
// CHECK-NO-PIC-NOT: "-pie-level"
//
-// CHECK-DYNAMIC-NO-PIC1: "-mrelocation-model" "dynamic-no-pic"
-// CHECK-DYNAMIC-NO-PIC1: "-pic-level" "1"
-//
-// CHECK-DYNAMIC-NO-PIC2: "-mrelocation-model" "dynamic-no-pic"
-// CHECK-DYNAMIC-NO-PIC2: "-pic-level" "2"
-//
-// CHECK-PIC1-NOT: "-mrelocation-model"
+// CHECK-PIC1: "-mrelocation-model" "pic"
// CHECK-PIC1: "-pic-level" "1"
//
-// CHECK-PIC2-NOT: "-mrelocation-model"
+// CHECK-PIC2: "-mrelocation-model" "pic"
// CHECK-PIC2: "-pic-level" "2"
//
-// CHECK-PIE1-NOT: "-mrelocation-model"
+// CHECK-PIE1: "-mrelocation-model" "pic"
+// CHECK-PIE1: "-pic-level" "1"
// CHECK-PIE1: "-pie-level" "1"
//
-// CHECK-PIE2-NOT: "-mrelocation-model"
+// CHECK-PIE2: "-mrelocation-model" "pic"
+// CHECK-PIE2: "-pic-level" "2"
// CHECK-PIE2: "-pie-level" "2"
//
+// CHECK-PIE-LD: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PIE-LD: "-pie"
+// CHECK-PIE-LD: "Scrt1.o" "crti.o" "crtbeginS.o"
+// CHECK-PIE-LD: "crtendS.o" "crtn.o"
+//
+// 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"
+//
+// CHECK-DYNAMIC-NO-PIC-64: "-mrelocation-model" "dynamic-no-pic"
+// CHECK-DYNAMIC-NO-PIC-64: "-pic-level" "2"
+// CHECK-DYNAMIC-NO-PIC-64-NOT: "-pie-level"
+//
+// CHECK-NON-DARWIN-DYNAMIC-NO-PIC: error: unsupported option '-mdynamic-no-pic' for target 'i386-unknown-unknown'
+//
// RUN: %clang -c %s -target i386-unknown-unknown -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target i386-unknown-unknown -fpic -### 2>&1 \
@@ -33,26 +44,62 @@
// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
+// Check that PIC and PIE flags obey last-match-wins. If the last flag is
+// a no-* variant, regardless of which variant or which flags precede it, we
+// get no PIC.
// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-pic -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-PIC -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-pic -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-PIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-pic -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-PIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pie -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-PIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-PIE -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-PIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-PIE -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pie -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-pie -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pic -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-PIE -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-pie -### 2>&1 \
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-PIE -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+//
+// Last-match-wins where both pic and pie are specified.
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
+// Last-match-wins when selecting level 1 vs. level 2.
// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fPIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fpic -### 2>&1 \
@@ -62,20 +109,81 @@
// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fPIC -fPIE -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
//
-// Defaults change for Darwin.
+// Make sure -pie is passed to along to ld and that the right *crt* files
+// are linked in.
+// RUN: %clang %s -target i386-unknown-freebsd -fPIE -pie -### \
+// RUN: --sysroot=%S/Inputs/basic_freebsd_tree 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
+// RUN: %clang %s -target i386-linux-gnu -fPIE -pie -### \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
+// RUN: %clang %s -target i386-linux-gnu -fPIC -pie -### \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE-LD
+//
+// Disregard any of the PIC-specific flags if we have a trump-card flag.
+// RUN: %clang -c %s -target i386-unknown-unknown -mkernel -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -static -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+//
+// Darwin is a beautiful and unique snowflake when it comes to these flags.
+// When targetting a 32-bit darwin system, the -fno-* flag variants work and
+// disable PIC, but any other flag enables PIC (*not* PIE) even if the flag
+// specifies PIE. On 64-bit targets, there is simply nothing you can do, there
+// is no PIE, there is only PIC when it comes to compilation.
// RUN: %clang -c %s -target i386-apple-darwin -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
-// RUN: %clang -c %s -target i386-apple-darwin -fno-pic -### 2>&1 \
-// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-apple-darwin -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-apple-darwin -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-apple-darwin -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-apple-darwin -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
// RUN: %clang -c %s -target i386-apple-darwin -fno-PIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-apple-darwin -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-apple-darwin -fno-PIC -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-apple-darwin -fno-PIC -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target x86_64-apple-darwin -fno-PIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target x86_64-apple-darwin -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target x86_64-apple-darwin -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target x86_64-apple-darwin -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
//
-// Disregard any of the PIC-specific flags if we have a trump-card flag.
-// RUN: %clang -c %s -target i386-unknown-unknown -mkernel -fPIC -### 2>&1 \
+// Darwin gets even more special with '-mdynamic-no-pic'. This flag is only
+// valid on Darwin, and it's behavior is very strange but needs to remain
+// consistent for compatibility.
+// RUN: %clang -c %s -target i386-unknown-unknown -mdynamic-no-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NON-DARWIN-DYNAMIC-NO-PIC
+// RUN: %clang -c %s -target i386-apple-darwin -mdynamic-no-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-32
+// RUN: %clang -c %s -target i386-apple-darwin -mdynamic-no-pic -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-32
+// RUN: %clang -c %s -target i386-apple-darwin -mdynamic-no-pic -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-32
+// RUN: %clang -c %s -target x86_64-apple-darwin -mdynamic-no-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-64
+// RUN: %clang -c %s -target x86_64-apple-darwin -mdynamic-no-pic -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-64
+// RUN: %clang -c %s -target x86_64-apple-darwin -mdynamic-no-pic -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC-64
+//
+// Checks for ARM+Apple+IOS including -fapple-kext, -mkernel, and iphoneos
+// version boundaries.
+// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=6.0.0 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target armv7-apple-ios -mkernel -miphoneos-version-min=6.0.0 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=5.0.0 -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
-// RUN: %clang -c %s -target i386-unknown-unknown -static -fPIC -### 2>&1 \
+// 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
-// RUN: %clang -c %s -target i386-unknown-unknown -mdynamic-no-pic -fPIC -### 2>&1 \
-// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC1
-// RUN: %clang -c %s -target i386-apple-darwin -mdynamic-no-pic -fPIC -### 2>&1 \
-// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC2
diff --git a/test/Driver/retain-comments-from-system-headers.c b/test/Driver/retain-comments-from-system-headers.c
new file mode 100644
index 000000000000..4d3e2ffe06f4
--- /dev/null
+++ b/test/Driver/retain-comments-from-system-headers.c
@@ -0,0 +1,9 @@
+// Check that we pass -fretain-comments-from-system-headers to frontend.
+//
+// RUN: %clang -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RETAIN
+// RUN: %clang -c %s -fretain-comments-from-system-headers -### 2>&1 | FileCheck %s --check-prefix=CHECK-RETAIN
+//
+// CHECK-RETAIN: -fretain-comments-from-system-headers
+//
+// CHECK-NO-RETAIN-NOT: -fretain-comments-from-system-headers
+
diff --git a/test/Driver/rewrite-legacy-objc.m b/test/Driver/rewrite-legacy-objc.m
index d243c7a15b39..2e3f4218ef2d 100644
--- a/test/Driver/rewrite-legacy-objc.m
+++ b/test/Driver/rewrite-legacy-objc.m
@@ -3,13 +3,5 @@
// 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" "-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" "-fobjc-default-synthesize-properties" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
// TEST0: rewrite-legacy-objc.m"
-
-// RUN: not %clang -ccc-no-clang -target unknown -rewrite-legacy-objc %s -o - -### 2>&1 | \
-// RUN: FileCheck -check-prefix=TEST1 %s
-// TEST1: invalid output type 'rewritten-legacy-objc' for use with gcc
-
-// RUN: not %clang -ccc-no-clang -target i386-apple-darwin10 -rewrite-legacy-objc %s -o - -### 2>&1 | \
-// RUN: FileCheck -check-prefix=TEST2 %s
-// TEST2: invalid output type 'rewritten-legacy-objc' for use with gcc
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index 669679772203..fa159a625824 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -3,13 +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" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
-// TEST0: rewrite-objc.m"
-
-// RUN: not %clang -ccc-no-clang -target unknown -rewrite-objc %s -o - -### 2>&1 | \
-// RUN: FileCheck -check-prefix=TEST1 %s
-// TEST1: invalid output type 'rewritten-objc' for use with gcc
-
-// RUN: not %clang -ccc-no-clang -target i386-apple-darwin10 -rewrite-objc %s -o - -### 2>&1 | \
-// RUN: FileCheck -check-prefix=TEST2 %s
-// TEST2: invalid output type 'rewritten-objc' for use with gcc
+// 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"
diff --git a/test/Driver/stack-protector.c b/test/Driver/stack-protector.c
new file mode 100644
index 000000000000..5f3d679c1ade
--- /dev/null
+++ b/test/Driver/stack-protector.c
@@ -0,0 +1,11 @@
+// RUN: %clang -fno-stack-protector -### %s 2>&1 | FileCheck %s -check-prefix=NOSSP
+// NOSSP-NOT: "-stack-protector" "1"
+// NOSSP-NOT: "-stack-protector-buffer-size"
+
+// RUN: %clang -fstack-protector -### %s 2>&1 | FileCheck %s -check-prefix=SSP
+// SSP: "-stack-protector" "1"
+// SSP-NOT: "-stack-protector-buffer-size"
+
+// 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"
diff --git a/test/Driver/std.cpp b/test/Driver/std.cpp
index 7704c8dda1ea..822658c837dc 100644
--- a/test/Driver/std.cpp
+++ b/test/Driver/std.cpp
@@ -5,6 +5,8 @@
// 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
void f(int n) {
typeof(n)();
@@ -22,3 +24,9 @@ void f(int n) {
// GNUXX11-NOT: undeclared identifier 'typeof'
// GNUXX11-NOT: undeclared identifier 'decltype'
+
+// CXX1Y: undeclared identifier 'typeof'
+// CXX1Y-NOT: undeclared identifier 'decltype'
+
+// GNUXX1Y-NOT: undeclared identifier 'typeof'
+// GNUXX1Y-NOT: undeclared identifier 'decltype'
diff --git a/test/Driver/tsan.c b/test/Driver/tsan.c
index 1dadb8ea265b..18b027fbceec 100644
--- a/test/Driver/tsan.c
+++ b/test/Driver/tsan.c
@@ -1,8 +1,9 @@
-// RUN: %clang -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O1 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O2 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
-// RUN: %clang -O3 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
-// Verify that -fthread-sanitizer invokes tsan instrumentation.
+// 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
+// Verify that -fsanitize=thread invokes tsan instrumentation.
int foo(int *a) { return *a; }
// CHECK: __tsan_init
diff --git a/test/Driver/ubsan-ld.c b/test/Driver/ubsan-ld.c
new file mode 100644
index 000000000000..775e6699443f
--- /dev/null
+++ b/test/Driver/ubsan-ld.c
@@ -0,0 +1,10 @@
+// Test UndefinedBehaviorSanitizer ld flags.
+
+// RUN: %clang -fcatch-undefined-behavior %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LINUX %s
+// CHECK-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LINUX-NOT: "-lc"
+// CHECK-LINUX: libclang_rt.ubsan-i386.a"
+// CHECK-LINUX: "-lpthread"
diff --git a/test/Driver/warning-options.cpp b/test/Driver/warning-options.cpp
index ab0da42e4bfc..cce88e65c259 100644
--- a/test/Driver/warning-options.cpp
+++ b/test/Driver/warning-options.cpp
@@ -8,3 +8,8 @@
// CHECK: unknown warning option '-Wmonkey'
// CHECK: unknown warning option '-Wno-monkey'
// CHECK: unknown warning option '-Wno-unused-command-line-arguments'; did you mean '-Wno-unused-command-line-argument'?
+
+// FIXME: Remove this together with -Warc-abi once an Xcode is released that doesn't pass this flag.
+// RUN: %clang -### -Warc-abi -Wno-arc-abi %s 2>&1 | FileCheck -check-prefix=ARCABI %s
+// ARCABI-NOT: unknown warning option '-Warc-abi'
+// ARCABI-NOT: unknown warning option '-Wno-arc-abi'
diff --git a/test/Driver/working-directory-and-abs.c b/test/Driver/working-directory-and-abs.c
new file mode 100644
index 000000000000..6738c776d40c
--- /dev/null
+++ b/test/Driver/working-directory-and-abs.c
@@ -0,0 +1 @@
+// RUN: %clang -working-directory=%S %S/working-directory-and-abs.c -fsyntax-only
diff --git a/test/Driver/x86_64-nacl-defines.cpp b/test/Driver/x86_64-nacl-defines.cpp
new file mode 100644
index 000000000000..caa9a74d2db6
--- /dev/null
+++ b/test/Driver/x86_64-nacl-defines.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang -target x86_64-unknown-nacl -ccc-echo %s -emit-llvm-only -c 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
+
+// Check platform defines
+
+// CHECK: __LITTLE_ENDIAN__defined
+#ifdef __LITTLE_ENDIAN__
+void __LITTLE_ENDIAN__defined() {}
+#endif
+
+// CHECK: __native_client__defined
+#ifdef __native_client__
+void __native_client__defined() {}
+#endif
+
+// CHECK: __x86_64__defined
+#ifdef __x86_64__
+void __x86_64__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/x86_64-nacl-types.cpp b/test/Driver/x86_64-nacl-types.cpp
new file mode 100644
index 000000000000..a994cb75ef66
--- /dev/null
+++ b/test/Driver/x86_64-nacl-types.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-nacl -std=c++11 -verify %s
+// expected-no-diagnostics
+
+#include <stddef.h>
+#include <stdarg.h>
+
+static_assert(alignof(char) == 1, "alignof char is wrong");
+
+static_assert(alignof(short) == 2, "sizeof short is wrong");
+static_assert(alignof(short) == 2, "alignof short is wrong");
+
+static_assert(alignof(int) == 4, "sizeof int is wrong");
+static_assert(alignof(int) == 4, "alignof int is wrong");
+
+static_assert(sizeof(long) == 4, "sizeof long is wrong");
+static_assert(sizeof(long) == 4, "alignof long is wrong");
+
+static_assert(sizeof(long long) == 8, "sizeof long long is wrong wrong");
+static_assert(alignof(long long) == 8, "alignof long long is wrong wrong");
+
+static_assert(sizeof(void*) == 4, "sizeof void * is wrong");
+static_assert(alignof(void*) == 4, "alignof void * is wrong");
+
+static_assert(sizeof(float) == 4, "sizeof float is wrong");
+static_assert(alignof(float) == 4, "alignof float is wrong");
+
+static_assert(sizeof(double) == 8, "sizeof double is wrong");
+static_assert(alignof(double) == 8, "alignof double is wrong");
+
+static_assert(sizeof(long double) == 8, "sizeof long double is wrong");
+static_assert(alignof(long double) == 8, "alignof long double is wrong");
+
+static_assert(sizeof(va_list) == 16, "sizeof va_list is wrong");
+static_assert(alignof(va_list) == 4, "alignof va_list is wrong");
+
+static_assert(sizeof(size_t) == 4, "sizeof size_t is wrong");
+static_assert(alignof(size_t) == 4, "alignof size_t is wrong");
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 0c837b4beb02..a173ce4bc271 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -66,13 +66,11 @@ const char *p = "foo"bar; // expected-error {{requires a space between}}
#define ord - '0'
int k = '4'ord; // expected-error {{requires a space between}}
-void operator""_x(char); // expected-error {{requires a space}}
void operator"x" _y(char); // expected-error {{must be '""'}}
void operator L"" _z(char); // expected-error {{encoding prefix}}
void operator "x" "y" U"z" ""_whoops "z" "y"(char); // expected-error {{must be '""'}}
void f() {
- 'a'_x;
'b'_y;
'c'_z;
'd'_whoops;
diff --git a/test/FixIt/fixit-include.c b/test/FixIt/fixit-include.c
index 51bd9b0dfd50..383c51386ab7 100644
--- a/test/FixIt/fixit-include.c
+++ b/test/FixIt/fixit-include.c
@@ -3,8 +3,10 @@
// 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
#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}
#pragma does_not_exist // expected-warning {{unknown pragma ignored}}
diff --git a/test/FixIt/fixit-missing-self-in-block.m b/test/FixIt/fixit-missing-self-in-block.m
new file mode 100644
index 000000000000..8fd9564ed02c
--- /dev/null
+++ b/test/FixIt/fixit-missing-self-in-block.m
@@ -0,0 +1,20 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x objective-c -fobjc-arc -fblocks -fixit %t
+// RUN: %clang_cc1 -x objective-c -fobjc-arc -fblocks -Werror %t
+// rdar://11194874
+
+@interface Root @end
+
+@interface I : Root
+{
+ int _bar;
+}
+@end
+
+@implementation I
+ - (void)foo{
+ ^{
+ _bar = 3;
+ }();
+ }
+@end
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index df591c792296..77099fccc9bb 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -49,7 +49,7 @@ void f(Test *t) {
@property (assign) int y;
@end
-int f0(Radar7861841 *a) { return a.x; } // expected-error {{property 'x' not found on object of type 'Radar7861841 *'; did you mean to access ivar 'x'}}
+int f0(Radar7861841 *a) { return a.x; } // expected-error {{property 'x' not found on object of type 'Radar7861841 *'; did you mean to access instance variable 'x'}}
int f1(Radar7861841 *a) { return a->y; } // expected-error {{property 'y' found on object of type 'Radar7861841 *'; did you mean to access it with the "." operator?}}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index ce6f1092df19..00adb19e50ce 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -81,6 +81,13 @@ void oopsMoreCommas() {
&a == &b ? oopsMoreCommas() : removeUnusedLabels(a[0]);
}
+int commaAtEndOfStatement() {
+ int a = 1;
+ a = 5, // expected-error {{';'}}
+ int m = 5, // expected-error {{';'}}
+ return 0, // expected-error {{';'}}
+}
+
int noSemiAfterLabel(int n) {
switch (n) {
default:
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 3eac434a36bd..253abd0f4e8b 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -64,7 +64,7 @@ namespace rdar7796492 {
// extra qualification on member
class C {
- int C::foo(); // expected-warning {{extra qualification}}
+ int C::foo(); // expected-error {{extra qualification}}
};
namespace rdar8488464 {
@@ -292,3 +292,10 @@ namespace greatergreater {
//(void)(&t<S<int>>==p);
}
}
+
+class foo {
+ static void test() {
+ (void)&i; // expected-error{{must explicitly qualify name of member function when taking its address}}
+ }
+ int i();
+};
diff --git a/test/FixIt/format-darwin.m b/test/FixIt/format-darwin.m
new file mode 100644
index 000000000000..1bfe27292e1f
--- /dev/null
+++ b/test/FixIt/format-darwin.m
@@ -0,0 +1,198 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
+
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck %s
+
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK-64 %s
+
+int printf(const char * restrict, ...);
+
+#if __LP64__
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef int SInt32;
+typedef unsigned int UInt32;
+
+#else
+
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+typedef long SInt32;
+typedef unsigned long UInt32;
+#endif
+
+NSInteger getNSInteger();
+NSUInteger getNSUInteger();
+SInt32 getSInt32();
+UInt32 getUInt32();
+
+void testCorrectionInAllCases() {
+ printf("%s", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%s", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
+ printf("%s", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
+
+ // CHECK: fix-it:"{{.*}}":{32:11-32:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{32:16-32:16}:"(long)"
+
+ // CHECK: fix-it:"{{.*}}":{33:11-33:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{33:16-33:16}:"(unsigned long)"
+
+ // CHECK: fix-it:"{{.*}}":{34:11-34:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{34:16-34:16}:"(int)"
+
+ // CHECK: fix-it:"{{.*}}":{35:11-35:13}:"%u"
+ // CHECK: fix-it:"{{.*}}":{35:16-35:16}:"(unsigned int)"
+}
+
+@interface Foo {
+@public
+ NSInteger _value;
+}
+- (NSInteger)getInteger;
+
+@property NSInteger value;
+@end
+
+struct Bar {
+ NSInteger value;
+};
+
+
+void testParens(Foo *obj, struct Bar *record) {
+ NSInteger arr[4] = {0};
+ NSInteger i = 0;
+
+ // These cases match the cases in CheckPrintfHandler::checkFormatExpr.
+ printf("%s", arr[0]); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", obj->_value); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", [obj getInteger]); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", obj.value); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", record->value); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", (i ? i : i)); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", *arr); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK-NOT: fix-it:{{.*}}:")"
+
+ printf("%s", i ? i : i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK: fix-it:"{{.*}}":{81:11-81:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{81:16-81:16}:"(long)("
+ // CHECK: fix-it:"{{.*}}":{81:25-81:25}:")"
+}
+
+
+#if __LP64__
+
+void testWarn() {
+ printf("%d", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%u", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%ld", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
+ printf("%lu", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
+
+ // CHECK-64: fix-it:"{{.*}}":{92:11-92:13}:"%ld"
+ // CHECK-64: fix-it:"{{.*}}":{92:16-92:16}:"(long)"
+
+ // CHECK-64: fix-it:"{{.*}}":{93:11-93:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{93:16-93:16}:"(unsigned long)"
+
+ // CHECK-64: fix-it:"{{.*}}":{94:11-94:14}:"%d"
+ // CHECK-64: fix-it:"{{.*}}":{94:17-94:17}:"(int)"
+
+ // CHECK-64: fix-it:"{{.*}}":{95:11-95:14}:"%u"
+ // CHECK-64: fix-it:"{{.*}}":{95:17-95:17}:"(unsigned int)"
+}
+
+void testPreserveHex() {
+ printf("%x", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%x", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+
+ // CHECK-64: fix-it:"{{.*}}":{111:11-111:13}:"%lx"
+ // CHECK-64: fix-it:"{{.*}}":{111:16-111:16}:"(long)"
+
+ // CHECK-64: fix-it:"{{.*}}":{112:11-112:13}:"%lx"
+ // CHECK-64: fix-it:"{{.*}}":{112:16-112:16}:"(unsigned long)"
+}
+
+void testNoWarn() {
+ printf("%ld", getNSInteger()); // no-warning
+ printf("%lu", getNSUInteger()); // no-warning
+ printf("%d", getSInt32()); // no-warning
+ printf("%u", getUInt32()); // no-warning
+}
+
+#else
+
+void testWarn() {
+ printf("%ld", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%lu", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%d", getSInt32()); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
+ printf("%u", getUInt32()); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
+
+ // CHECK-32: fix-it:"{{.*}}":{131:17-131:17}:"(long)"
+
+ // CHECK-32: fix-it:"{{.*}}":{132:17-132:17}:"(unsigned long)"
+
+ // CHECK-32: fix-it:"{{.*}}":{133:16-133:16}:"(int)"
+
+ // CHECK-32: fix-it:"{{.*}}":{134:16-134:16}:"(unsigned int)"
+}
+
+void testPreserveHex() {
+ printf("%lx", getNSInteger()); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%lx", getNSUInteger()); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+
+ // CHECK-32: fix-it:"{{.*}}":{146:17-146:17}:"(long)"
+
+ // CHECK-32: fix-it:"{{.*}}":{147:17-147:17}:"(unsigned long)"
+}
+
+void testNoWarn() {
+ printf("%d", getNSInteger()); // no-warning
+ printf("%u", getNSUInteger()); // no-warning
+ printf("%ld", getSInt32()); // no-warning
+ printf("%lu", getUInt32()); // no-warning
+}
+
+#endif
+
+
+void testCasts() {
+ printf("%s", (NSInteger)0); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+ printf("%s", (NSUInteger)0); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%s", (SInt32)0); // expected-warning{{values of type 'SInt32' should not be used as format arguments; add an explicit cast to 'int' instead}}
+ printf("%s", (UInt32)0); // expected-warning{{values of type 'UInt32' should not be used as format arguments; add an explicit cast to 'unsigned int' instead}}
+
+ // CHECK: fix-it:"{{.*}}":{165:11-165:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{165:16-165:27}:"(long)"
+
+ // CHECK: fix-it:"{{.*}}":{166:11-166:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{166:16-166:28}:"(unsigned long)"
+
+ // CHECK: fix-it:"{{.*}}":{167:11-167:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{167:16-167:24}:"(int)"
+
+ // CHECK: fix-it:"{{.*}}":{168:11-168:13}:"%u"
+ // CHECK: fix-it:"{{.*}}":{168:16-168:24}:"(unsigned int)"
+}
+
+void testCapitals() {
+ printf("%D", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ printf("%U", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+ printf("%O", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+
+ // CHECK: fix-it:"{{.*}}":{184:12-184:13}:"d"
+ // CHECK: fix-it:"{{.*}}":{185:12-185:13}:"u"
+ // CHECK: fix-it:"{{.*}}":{186:12-186:13}:"o"
+
+
+ printf("%lD", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}} expected-warning{{format specifies type 'long' but the argument has type 'int'}}
+
+ // FIXME: offering two somewhat-conflicting fixits is less than ideal.
+ // CHECK: fix-it:"{{.*}}":{193:13-193:14}:"d"
+ // CHECK: fix-it:"{{.*}}":{193:11-193:14}:"%D"
+}
diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp
index c95c8670d6d2..9da29229f041 100644
--- a/test/FixIt/no-fixit.cpp
+++ b/test/FixIt/no-fixit.cpp
@@ -5,3 +5,9 @@
// CHECK-NOT: fix-it:
template<template<typename> +> void func();
+
+struct {
+ void i() {
+ (void)&i;
+ }
+} x;
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index 3d40da8d256a..b3568a5bbf73 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -5,7 +5,8 @@
// RUN: grep test_string %t
namespace std {
- template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}}
+ template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}} \
+ // expected-note {{'otherstd::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}}
@@ -76,13 +77,50 @@ int foo() {
}
namespace nonstd {
- typedef std::basic_string<char> yarn; // expected-note{{'nonstd::yarn' declared here}}
+ typedef std::basic_string<char> yarn; // expected-note 2 {{'nonstd::yarn' declared here}}
+ int narf; // expected-note{{'nonstd::narf' declared here}}
}
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'?}}
+
+int poit() {
+ nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean 'otherstd::basic_string'?}}
+ return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}}
+}
namespace check_bool {
void f() {
Bool b; // expected-error{{use of undeclared identifier 'Bool'; did you mean 'bool'?}}
}
}
+
+namespace outr {
+}
+namespace outer {
+ namespace inner { // expected-note{{'outer::inner' declared here}} \
+ // expected-note{{namespace 'outer::inner' defined here}} \
+ // expected-note{{'inner' declared here}}
+ int i;
+ }
+}
+
+using namespace outr::inner; // expected-error{{no namespace named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
+
+void func() {
+ outr::inner::i = 3; // expected-error{{no member named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
+ outer::innr::i = 4; // expected-error{{no member named 'innr' in namespace 'outer'; did you mean 'inner'?}}
+}
+
+struct base {
+};
+struct derived : base {
+ int i;
+};
+
+void func2() {
+ derived d;
+ // FIXME: we should offer a fix here. We do if the 'i' is misspelled, but we don't do name qualification changes
+ // to replace base::i with derived::i as we would for other qualified name misspellings.
+ // d.base::i = 3;
+}
diff --git a/test/Frontend/ast-codegen.c b/test/Frontend/ast-codegen.c
index b5b2157e21ae..b85c5dcf5085 100644
--- a/test/Frontend/ast-codegen.c
+++ b/test/Frontend/ast-codegen.c
@@ -1,5 +1,5 @@
-// RUN: %clang -emit-ast -o %t.ast %s
-// RUN: %clang -emit-llvm -S -o - %t.ast | FileCheck %s
+// RUN: %clang -target i386-unknown-unknown -emit-ast -o %t.ast %s
+// RUN: %clang -target i386-unknown-unknown -emit-llvm -S -o - %t.ast | FileCheck %s
// CHECK: module asm "foo"
__asm__("foo");
diff --git a/test/Frontend/iframework.c b/test/Frontend/iframework.c
index 0c241fd4891c..6f801f2437a2 100644
--- a/test/Frontend/iframework.c
+++ b/test/Frontend/iframework.c
@@ -1,3 +1,4 @@
-// RUN: %clang -fsyntax-only -iframework%S/Inputs %s -Xclang -verify
+// RUN: %clang -fsyntax-only -iframework %S/Inputs %s -Xclang -verify
+// expected-no-diagnostics
#include <TestFramework/TestFramework.h>
diff --git a/test/Frontend/macros.c b/test/Frontend/macros.c
index 317079709c63..68f220339dbf 100644
--- a/test/Frontend/macros.c
+++ b/test/Frontend/macros.c
@@ -1,4 +1,13 @@
// RUN: %clang_cc1 -DA= -DB=1 -verify -fsyntax-only %s
+// expected-no-diagnostics
int a[(B A) == 1 ? 1 : -1];
+
+// PR13747 - Don't warn about unused results with statement exprs in macros.
+void stuff(int,int,int);
+#define memset(x,y,z) ({ stuff(x,y,z); x; })
+
+void foo(int a, int b, int c) {
+ memset(a,b,c); // No warning!
+}
diff --git a/test/Frontend/unknown-pragmas.c b/test/Frontend/unknown-pragmas.c
index 53a5a45a4337..eea025ceeea9 100644
--- a/test/Frontend/unknown-pragmas.c
+++ b/test/Frontend/unknown-pragmas.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -Eonly -Wall -verify %s
// RUN: %clang_cc1 -E -dM -Wall -verify %s
+// expected-no-diagnostics
#pragma adgohweopihweotnwet
diff --git a/test/Frontend/verify.c b/test/Frontend/verify.c
index f8d0f4282b4a..062e6bd8618f 100644
--- a/test/Frontend/verify.c
+++ b/test/Frontend/verify.c
@@ -22,7 +22,7 @@
#if 0
// expected-error {{should be ignored}}
#endif
-
+// eexpected-error {{should also be ignored: unrecognised directive}}
#error should not be ignored
// expected-error@-1 1+ {{should not be ignored}}
@@ -111,9 +111,10 @@ unexpected b; // expected-error@33 1-1 {{unknown type}}
#if 0
// RUN: %clang_cc1 -verify %t.invalid 2>&1 | FileCheck -check-prefix=CHECK6 %s
-// CHECK6: error: 'error' diagnostics seen but not expected:
+// 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: 1 error generated.
+// 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
diff --git a/test/Frontend/verify2.c b/test/Frontend/verify2.c
index a1c797581ed9..04f80ad48e1a 100644
--- a/test/Frontend/verify2.c
+++ b/test/Frontend/verify2.c
@@ -3,7 +3,7 @@
// Please note that all comments are inside "#if 0" blocks so that
// VerifyDiagnosticConsumer sees no comments while processing this
-// test-case.
+// test-case (and hence no expected-* directives).
#endif
#include "verify2.h"
@@ -12,8 +12,9 @@
#if 0
// expected-error {{should be ignored}}
-// CHECK: error: 'error' diagnostics seen but not expected:
+// CHECK: error: no expected directives found: consider use of 'expected-no-diagnostics'
+// CHECK-NEXT: error: 'error' diagnostics seen but not expected:
// CHECK-NEXT: Line 1: header
// CHECK-NEXT: Line 10: source
-// CHECK-NEXT: 2 errors generated.
+// CHECK-NEXT: 3 errors generated.
#endif
diff --git a/test/Frontend/verify3.c b/test/Frontend/verify3.c
new file mode 100644
index 000000000000..0705b4b7ee57
--- /dev/null
+++ b/test/Frontend/verify3.c
@@ -0,0 +1,41 @@
+// This test-case runs several sub-tests on -verify to ensure that correct
+// 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
+#ifdef TEST1
+// expected-no-diagnostics
+// expected-note {{}}
+
+// CHECK1: error: 'error' diagnostics seen but not expected:
+// CHECK1-NEXT: Line 8: expected directive cannot follow 'expected-no-diagnostics' directive
+// CHECK1-NEXT: 1 error generated.
+#endif
+
+// RUN: %clang_cc1 -DTEST2 -verify %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
+#ifdef TEST2
+#warning X
+// expected-warning@-1 {{X}}
+// expected-no-diagnostics
+
+// CHECK2: error: 'error' diagnostics seen but not expected:
+// CHECK2-NEXT: Line 19: 'expected-no-diagnostics' directive cannot follow other expected directives
+// 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
+#ifdef TEST3
+// no directives
+
+// CHECK3: error: no expected directives found: consider use of 'expected-no-diagnostics'
+// CHECK3-NEXT: 1 error generated.
+#endif
+
+// RUN: %clang_cc1 -E -DTEST4 -verify %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
+#ifdef TEST4
+#warning X
+// expected-warning@-1 {{X}}
+
+// CHECK4-NOT: error: no expected directives found: consider use of 'expected-no-diagnostics'
+#endif
diff --git a/test/Frontend/warning-mapping-1.c b/test/Frontend/warning-mapping-1.c
index 883dafb1f500..623e5e3933a2 100644
--- a/test/Frontend/warning-mapping-1.c
+++ b/test/Frontend/warning-mapping-1.c
@@ -1,5 +1,6 @@
// Check that -w has higher priority than -Werror.
// RUN: %clang_cc1 -verify -Wsign-compare -Werror -w %s
+// expected-no-diagnostics
int f0(int x, unsigned y) {
return x < y;
diff --git a/test/Frontend/warning-mapping-4.c b/test/Frontend/warning-mapping-4.c
index d8d2769fc535..6644042e24ee 100644
--- a/test/Frontend/warning-mapping-4.c
+++ b/test/Frontend/warning-mapping-4.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -verify -Wno-error=sign-compare %s
// RUN: %clang_cc1 -verify -Wsign-compare -w -Wno-error=sign-compare %s
+// expected-no-diagnostics
int f0(int x, unsigned y) {
return x < y;
diff --git a/test/Headers/Inputs/include/stdint.h b/test/Headers/Inputs/include/stdint.h
new file mode 100644
index 000000000000..7a1fddef82da
--- /dev/null
+++ b/test/Headers/Inputs/include/stdint.h
@@ -0,0 +1,18 @@
+#ifndef STDINT_H
+#define STDINT_H
+
+#ifdef __INT32_TYPE__
+typedef unsigned __INT32_TYPE__ uint32_t;
+#endif
+
+#ifdef __INT64_TYPE__
+typedef unsigned __INT64_TYPE__ uint64_t;
+#endif
+
+#ifdef __INTPTR_TYPE__
+typedef unsigned __INTPTR_TYPE__ uintptr_t;
+#else
+#error Every target should have __INTPTR_TYPE__
+#endif
+
+#endif /* STDINT_H */
diff --git a/test/Headers/altivec-header.c b/test/Headers/altivec-header.c
new file mode 100644
index 000000000000..085e799f9599
--- /dev/null
+++ b/test/Headers/altivec-header.c
@@ -0,0 +1,12 @@
+// 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
+
+#include <altivec.h>
+
+// Verify that simply including <altivec.h> does not generate any code
+// (i.e. all inline routines in the header are marked "static")
+
+// CHECK-NOT: .text
+
diff --git a/test/Headers/c89.c b/test/Headers/c89.c
index eea8d44d8dce..acf01b40e06e 100644
--- a/test/Headers/c89.c
+++ b/test/Headers/c89.c
@@ -1,4 +1,5 @@
// RUN: %clang -target i386-apple-darwin10 -fsyntax-only -Xclang -verify -std=c89 %s
+// expected-no-diagnostics
// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
// on win32 since we don't generally know how to find errno.h.
diff --git a/test/Headers/int64-type.c b/test/Headers/int64-type.c
index 16b42d2d7f8f..442f8a0cc230 100644
--- a/test/Headers/int64-type.c
+++ b/test/Headers/int64-type.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -verify %s -ffreestanding
+// expected-no-diagnostics
#include <stdint.h>
typedef unsigned long long uint64_t;
diff --git a/test/Headers/typedef_guards.c b/test/Headers/typedef_guards.c
index 646b2ca0efe8..968b26d8c731 100644
--- a/test/Headers/typedef_guards.c
+++ b/test/Headers/typedef_guards.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// NULL is rdefined in stddef.h
#define NULL ((void*) 0)
diff --git a/test/Headers/unwind.c b/test/Headers/unwind.c
new file mode 100644
index 000000000000..68100a8f8551
--- /dev/null
+++ b/test/Headers/unwind.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple arm-unknown-linux-gnueabi \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only %s
+// RUN: %clang_cc1 -triple mips-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only %s
+// RUN: %clang_cc1 -triple i686-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only %s
+
+// RUN: %clang_cc1 -triple arm-unknown-linux-gnueabi \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only -x c++ %s
+// RUN: %clang_cc1 -triple mips-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only -x c++ %s
+// RUN: %clang_cc1 -triple i686-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only -x c++ %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux \
+// RUN: -isystem %S/Inputs/include -ffreestanding -fsyntax-only -x c++ %s
+
+#include "unwind.h"
diff --git a/test/Headers/wchar_limits.cpp b/test/Headers/wchar_limits.cpp
index 93a99ad78f2b..35ae7affb514 100644
--- a/test/Headers/wchar_limits.cpp
+++ b/test/Headers/wchar_limits.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify %s
// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -fshort-wchar %s
+// expected-no-diagnostics
#include <stdint.h>
diff --git a/test/Headers/wmmintrin.c b/test/Headers/wmmintrin.c
index 6aa8be49881a..8cabbf066388 100644
--- a/test/Headers/wmmintrin.c
+++ b/test/Headers/wmmintrin.c
@@ -1,4 +1,5 @@
// Check that wmmintrin.h is includable with just -maes.
// RUN: %clang_cc1 -triple x86_64-unknown-unknown \
// RUN: -verify %s -ffreestanding -target-feature +aes
+// expected-no-diagnostics
#include <wmmintrin.h>
diff --git a/test/Index/Inputs/CommentXML/valid-availability-attr-01.xml b/test/Index/Inputs/CommentXML/valid-availability-attr-01.xml
new file mode 100644
index 000000000000..20ce01229ec7
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/valid-availability-attr-01.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Availability distribution="OS X">
+ <IntroducedInVersion>8.0</IntroducedInVersion>
+ <DeprecatedInVersion>9.0</DeprecatedInVersion>
+ <RemovedAfterVersion>10.0</RemovedAfterVersion>
+ <DeprecationSummary>use availability_test</DeprecationSummary>
+</Availability>
+</Function>
diff --git a/test/Index/Inputs/CommentXML/valid-availability-attr-02.xml b/test/Index/Inputs/CommentXML/valid-availability-attr-02.xml
new file mode 100644
index 000000000000..589262e9a9f7
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/valid-availability-attr-02.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Availability distribution="OS X">
+ <IntroducedInVersion>8.0.1</IntroducedInVersion>
+ <DeprecatedInVersion>9.0.1</DeprecatedInVersion>
+ <RemovedAfterVersion>10.0.1</RemovedAfterVersion>
+ <DeprecationSummary>use availability_test</DeprecationSummary>
+</Availability>
+</Function>
diff --git a/test/Index/Inputs/CommentXML/valid-deprecated-attr.xml b/test/Index/Inputs/CommentXML/valid-deprecated-attr.xml
new file mode 100644
index 000000000000..194720b832fb
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/valid-deprecated-attr.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Deprecated>since OS X 10.6</Deprecated>
+</Function>
diff --git a/test/Index/Inputs/CommentXML/valid-unavailable-attr.xml b/test/Index/Inputs/CommentXML/valid-unavailable-attr.xml
new file mode 100644
index 000000000000..5811c3427af8
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/valid-unavailable-attr.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Deprecated>Since iOS 4.0</Deprecated>
+<Unavailable/>
+</Function>
diff --git a/test/Index/Inputs/Frameworks/module.map b/test/Index/Inputs/Frameworks/module.map
new file mode 100644
index 000000000000..77879fe32817
--- /dev/null
+++ b/test/Index/Inputs/Frameworks/module.map
@@ -0,0 +1 @@
+framework module * { }
diff --git a/test/Index/Inputs/retain-comments-from-system-headers.h b/test/Index/Inputs/retain-comments-from-system-headers.h
new file mode 100644
index 000000000000..28dd94f2aadc
--- /dev/null
+++ b/test/Index/Inputs/retain-comments-from-system-headers.h
@@ -0,0 +1,8 @@
+#pragma clang system_header
+
+/**
+ * system_function
+ * \param a Aaa.
+ */
+int system_function(int a);
+
diff --git a/test/Index/annotate-comments-availability-attrs.cpp b/test/Index/annotate-comments-availability-attrs.cpp
new file mode 100644
index 000000000000..777881d683e8
--- /dev/null
+++ b/test/Index/annotate-comments-availability-attrs.cpp
@@ -0,0 +1,44 @@
+// rdar://12378879
+
+// 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 %s > %t/out
+// RUN: FileCheck %s < %t/out
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+/// Aaa.
+void attr_availability_1() __attribute__((availability(macosx,obsoleted=10.0,introduced=8.0,deprecated=9.0, message="use availability_test in <foo.h>")))
+ __attribute__((availability(ios,unavailable, message="not for iOS")));
+
+/// Aaa.
+void attr_availability_2() __attribute__((availability(macosx,obsoleted=10.0.1,introduced=8.0.1,deprecated=9.0.1)));
+
+/// Aaa.
+void attr_deprecated_1() __attribute__((deprecated));
+
+/// Aaa.
+void attr_deprecated_2() __attribute__((deprecated("message 1 <foo.h>")));
+
+/// Aaa.
+void attr_unavailable_1() __attribute__((unavailable));
+
+/// Aaa.
+void attr_unavailable_2() __attribute__((unavailable("message 2 <foo.h>")));
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="13" column="6"><Name>attr_availability_1</Name><USR>c:@F@attr_availability_1#</USR><Declaration>void attr_availability_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="iOS"><DeprecationSummary>not for iOS</DeprecationSummary><Unavailable/></Availability><Availability distribution="OS X"><IntroducedInVersion>8.0</IntroducedInVersion><DeprecatedInVersion>9.0</DeprecatedInVersion><RemovedAfterVersion>10.0</RemovedAfterVersion><DeprecationSummary>use availability_test in &lt;foo.h&gt;</DeprecationSummary></Availability></Function>]
+
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="17" column="6"><Name>attr_availability_2</Name><USR>c:@F@attr_availability_2#</USR><Declaration>void attr_availability_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="OS X"><IntroducedInVersion>8.0.1</IntroducedInVersion><DeprecatedInVersion>9.0.1</DeprecatedInVersion><RemovedAfterVersion>10.0.1</RemovedAfterVersion></Availability></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="20" column="6"><Name>attr_deprecated_1</Name><USR>c:@F@attr_deprecated_1#</USR><Declaration>void attr_deprecated_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated/></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="23" column="6"><Name>attr_deprecated_2</Name><USR>c:@F@attr_deprecated_2#</USR><Declaration>void attr_deprecated_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated>message 1 &lt;foo.h&gt;</Deprecated></Function>]
+
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="26" column="6"><Name>attr_unavailable_1</Name><USR>c:@F@attr_unavailable_1#</USR><Declaration>void attr_unavailable_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable/></Function>]
+
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="29" column="6"><Name>attr_unavailable_2</Name><USR>c:@F@attr_unavailable_2#</USR><Declaration>void attr_unavailable_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable>message 2 &lt;foo.h&gt;</Unavailable></Function>]
diff --git a/test/Index/annotate-comments.cpp b/test/Index/annotate-comments.cpp
index 22724d0b68d7..b8b8e6c2c41b 100644
--- a/test/Index/annotate-comments.cpp
+++ b/test/Index/annotate-comments.cpp
@@ -66,16 +66,16 @@ void isdoxy15(void);
/// Doxygen comment. IS_DOXYGEN_END
void isdoxy16(void);
-/// isdoxy17 IS_DOXYGEN_START
-// Not a Doxygen comment, but still picked up.
-/// IS_DOXYGEN_END
+/// NOT_DOXYGEN
+// NOT_DOXYGEN
+/// isdoxy17 IS_DOXYGEN_START IS_DOXYGEN_END
void isdoxy17(void);
unsigned
// NOT_DOXYGEN
-/// isdoxy18 IS_DOXYGEN_START
-// Not a Doxygen comment, but still picked up.
-/// IS_DOXYGEN_END
+/// NOT_DOXYGEN
+// NOT_DOXYGEN
+/// isdoxy18 IS_DOXYGEN_START IS_DOXYGEN_END
// NOT_DOXYGEN
int isdoxy18(void);
@@ -168,7 +168,7 @@ class test42 {
///\brief
///
/// Some malformed command.
-/* \*/
+/** \*/
/**
* \brief Aaa aaaaaaa aaaa.
* IS_DOXYGEN_END
@@ -221,6 +221,32 @@ void isdoxy49(void);
/// \returns ddd IS_DOXYGEN_END
void isdoxy50(int);
+// One of the following lines has trailing whitespace. It is intended, don't
+// fix it.
+/**
+ * Aaa. IS_DOXYGEN_START
+ *
+ * Bbb. IS_DOXYGEN_END
+ */
+void isdoxy51(int);
+
+// One of the following lines has trailing whitespace. It is intended, don't
+// fix it.
+/**
+ * Aaa. IS_DOXYGEN_START
+ * Bbb.
+ *
+ * Ccc. IS_DOXYGEN_END
+ */
+void isdoxy52(int);
+
+/**
+ * \fn isdoxy53
+ *
+ * Aaa. IS_DOXYGEN_START IS_DOXYGEN_END
+ */
+void isdoxy53(int);
+
/// Aaa.
void comment_to_html_conversion_1();
@@ -344,27 +370,30 @@ void comment_to_html_conversion_24();
/// Blah blah.
void comment_to_html_conversion_25();
-/// \b Aaa
+/// \unknown
void comment_to_html_conversion_26();
-/// \c Aaa \p Bbb
+/// \b Aaa
void comment_to_html_conversion_27();
-/// \a Aaa \e Bbb \em Ccc
+/// \c Aaa \p Bbb
void comment_to_html_conversion_28();
-/// \a 1<2 \e 3<4 \em 5<6 \param 7<8 aaa \tparam 9<10 bbb
+/// \a Aaa \e Bbb \em Ccc
void comment_to_html_conversion_29();
-/// \\ \@ \& \$ \# \< \> \% \" \. \::
+/// \a 1<2 \e 3<4 \em 5<6 \param 7<8 aaa \tparam 9<10 bbb
void comment_to_html_conversion_30();
-/// &amp; &lt; &gt; &quot;
+/// \\ \@ \& \$ \# \< \> \% \" \. \::
void comment_to_html_conversion_31();
-/// <em>0&lt;i</em>
+/// &amp; &lt; &gt; &quot;
void comment_to_html_conversion_32();
+/// <em>0&lt;i</em>
+void comment_to_html_conversion_33();
+
/// Aaa.
class comment_to_xml_conversion_01 {
/// \param aaa Blah blah.
@@ -518,13 +547,15 @@ enum class comment_to_xml_conversion_17 {
// CHECK: annotate-comments.cpp:214:6: FunctionDecl=isdoxy48:{{.*}} BriefComment=[IS_DOXYGEN_START Aaa bbb]
// CHECK: annotate-comments.cpp:218:6: FunctionDecl=isdoxy49:{{.*}} BriefComment=[IS_DOXYGEN_START Aaa]
// 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:225:6: FunctionDecl=comment_to_html_conversion_1:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="225" column="6"><Name>comment_to_html_conversion_1</Name><USR>c:@F@comment_to_html_conversion_1#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:251:6: FunctionDecl=comment_to_html_conversion_1:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="251" column="6"><Name>comment_to_html_conversion_1</Name><USR>c:@F@comment_to_html_conversion_1#</USR><Declaration>void comment_to_html_conversion_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.])))]
-// CHECK: annotate-comments.cpp:228:6: FunctionDecl=comment_to_html_conversion_2:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="228" column="6"><Name>comment_to_html_conversion_2</Name><USR>c:@F@comment_to_html_conversion_2#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:254:6: FunctionDecl=comment_to_html_conversion_2:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="254" column="6"><Name>comment_to_html_conversion_2</Name><USR>c:@F@comment_to_html_conversion_2#</USR><Declaration>void comment_to_html_conversion_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -532,7 +563,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:231:6: FunctionDecl=comment_to_html_conversion_3:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="231" column="6"><Name>comment_to_html_conversion_3</Name><USR>c:@F@comment_to_html_conversion_3#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:257:6: FunctionDecl=comment_to_html_conversion_3:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="257" column="6"><Name>comment_to_html_conversion_3</Name><USR>c:@F@comment_to_html_conversion_3#</USR><Declaration>void comment_to_html_conversion_3()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -540,7 +571,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[short]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:236:6: FunctionDecl=comment_to_html_conversion_4:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="236" column="6"><Name>comment_to_html_conversion_4</Name><USR>c:@F@comment_to_html_conversion_4#</USR><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para></Discussion></Function>]
+// CHECK: annotate-comments.cpp:262:6: FunctionDecl=comment_to_html_conversion_4:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="262" column="6"><Name>comment_to_html_conversion_4</Name><USR>c:@F@comment_to_html_conversion_4#</USR><Declaration>void comment_to_html_conversion_4()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -550,7 +581,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:243:6: FunctionDecl=comment_to_html_conversion_5:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p><p> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="243" column="6"><Name>comment_to_html_conversion_5</Name><USR>c:@F@comment_to_html_conversion_5#</USR><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para><Para> Ccc.</Para></Discussion></Function>]
+// CHECK: annotate-comments.cpp:269:6: FunctionDecl=comment_to_html_conversion_5:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p><p> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="269" column="6"><Name>comment_to_html_conversion_5</Name><USR>c:@F@comment_to_html_conversion_5#</USR><Declaration>void comment_to_html_conversion_5()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para><Para> Ccc.</Para></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -562,7 +593,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.])))
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Ccc.])))]
-// CHECK: annotate-comments.cpp:247:6: FunctionDecl=comment_to_html_conversion_6:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa. </p><p class="para-brief"> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="247" column="6"><Name>comment_to_html_conversion_6</Name><USR>c:@F@comment_to_html_conversion_6#</USR><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: annotate-comments.cpp:273:6: FunctionDecl=comment_to_html_conversion_6:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa. </p><p class="para-brief"> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="273" column="6"><Name>comment_to_html_conversion_6</Name><USR>c:@F@comment_to_html_conversion_6#</USR><Declaration>void comment_to_html_conversion_6()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para> Bbb.</Para></Discussion></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -574,7 +605,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:252: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="{{[^"]+}}annotate-comments.cpp" line="252" column="6"><Name>comment_to_html_conversion_7</Name><USR>c:@F@comment_to_html_conversion_7#</USR><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: annotate-comments.cpp:278: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="{{[^"]+}}annotate-comments.cpp" line="278" 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
@@ -584,7 +615,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[return]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:257: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="{{[^"]+}}annotate-comments.cpp" line="257" column="6"><Name>comment_to_html_conversion_8</Name><USR>c:@F@comment_to_html_conversion_8#</USR><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: annotate-comments.cpp:283: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="{{[^"]+}}annotate-comments.cpp" line="283" 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
@@ -594,7 +625,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:262: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="{{[^"]+}}annotate-comments.cpp" line="262" column="6"><Name>comment_to_html_conversion_9</Name><USR>c:@F@comment_to_html_conversion_9#</USR><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK: annotate-comments.cpp:288: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="{{[^"]+}}annotate-comments.cpp" line="288" 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
@@ -604,7 +635,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[result]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:266: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="{{[^"]+}}annotate-comments.cpp" line="266" column="6"><Name>comment_to_html_conversion_10</Name><USR>c:@F@comment_to_html_conversion_10#</USR><ResultDiscussion><Para> Aaa. </Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: annotate-comments.cpp:292: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="{{[^"]+}}annotate-comments.cpp" line="292" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -616,7 +647,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:273: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="{{[^"]+}}annotate-comments.cpp" line="273" column="6"><Name>comment_to_html_conversion_11</Name><USR>c:@F@comment_to_html_conversion_11#</USR><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Ccc.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK: annotate-comments.cpp:299: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="{{[^"]+}}annotate-comments.cpp" line="299" 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
@@ -628,14 +659,14 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))]
-// CHECK: annotate-comments.cpp:276:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="276" column="6"><Name>comment_to_html_conversion_12</Name><USR>c:@F@comment_to_html_conversion_12#I#</USR></Function>]
+// CHECK: annotate-comments.cpp:302:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="302" column="6"><Name>comment_to_html_conversion_12</Name><USR>c:@F@comment_to_html_conversion_12#I#</USR><Declaration>void comment_to_html_conversion_12(int x1)</Declaration></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=[] ParamIndex=Invalid
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace)))]
-// CHECK: annotate-comments.cpp:279:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="279" column="6"><Name>comment_to_html_conversion_13</Name><USR>c:@F@comment_to_html_conversion_13#I#</USR><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:305:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="305" column="6"><Name>comment_to_html_conversion_13</Name><USR>c:@F@comment_to_html_conversion_13#I#</USR><Declaration>void comment_to_html_conversion_13(int x1)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -643,7 +674,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:282:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="282" column="6"><Name>comment_to_html_conversion_14</Name><USR>c:@F@comment_to_html_conversion_14#I#</USR><Parameters><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:308:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="308" column="6"><Name>comment_to_html_conversion_14</Name><USR>c:@F@comment_to_html_conversion_14#I#</USR><Declaration>void comment_to_html_conversion_14(int x1)</Declaration><Parameters><Parameter><Name>zzz</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 IsWhitespace
@@ -651,7 +682,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:286:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="286" column="6"><Name>comment_to_html_conversion_15</Name><USR>c:@F@comment_to_html_conversion_15#I#I#</USR><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:312:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="312" column="6"><Name>comment_to_html_conversion_15</Name><USR>c:@F@comment_to_html_conversion_15#I#I#</USR><Declaration>void comment_to_html_conversion_15(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><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
@@ -663,7 +694,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:291:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="291" column="6"><Name>comment_to_html_conversion_16</Name><USR>c:@F@comment_to_html_conversion_16#I#I#</USR><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa. </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:317:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="317" column="6"><Name>comment_to_html_conversion_16</Name><USR>c:@F@comment_to_html_conversion_16#I#I#</USR><Declaration>void comment_to_html_conversion_16(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter><Parameter><Name>zzz</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 IsWhitespace
@@ -679,7 +710,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:296: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="{{[^"]+}}annotate-comments.cpp" line="296" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:322: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="{{[^"]+}}annotate-comments.cpp" line="322" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -690,7 +721,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))]
-// CHECK: annotate-comments.cpp:301: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="{{[^"]+}}annotate-comments.cpp" line="301" column="6"><Name>comment_to_html_conversion_18</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_18#t0.0#</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:327: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="{{[^"]+}}annotate-comments.cpp" line="327" 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
@@ -701,7 +732,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))]
-// CHECK: annotate-comments.cpp:306: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="{{[^"]+}}annotate-comments.cpp" line="306" 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><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: annotate-comments.cpp:332: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="{{[^"]+}}annotate-comments.cpp" line="332" 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; void 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -713,7 +744,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
-// CHECK: annotate-comments.cpp:313: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="{{[^"]+}}annotate-comments.cpp" line="313" 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><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: annotate-comments.cpp:339: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="{{[^"]+}}annotate-comments.cpp" line="339" 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; void 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -733,7 +764,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
-// CHECK: annotate-comments.cpp:320: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="{{[^"]+}}annotate-comments.cpp" line="320" 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><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: annotate-comments.cpp:346: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="{{[^"]+}}annotate-comments.cpp" line="346" 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; void 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -753,7 +784,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TT] ParamPosition={0, 0}
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Bbb]))))]
-// CHECK: annotate-comments.cpp:329: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="{{[^"]+}}annotate-comments.cpp" line="329" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@F@comment_to_html_conversion_22#I#I#</USR><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: annotate-comments.cpp:355: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="{{[^"]+}}annotate-comments.cpp" line="355" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -776,7 +807,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))]
-// CHECK: annotate-comments.cpp:332:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="332" column="6"><Name>comment_to_html_conversion_23</Name><USR>c:@F@comment_to_html_conversion_23#</USR><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:358:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="358" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -785,7 +816,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_HTMLStartTag Name=[a] Attrs: href=http://example.com/)
// CHECK-NEXT: (CXComment_Text Text=[Aaa])
// CHECK-NEXT: (CXComment_HTMLEndTag Name=[a])))]
-// CHECK: annotate-comments.cpp:338: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="{{[^"]+}}annotate-comments.cpp" line="338" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><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: annotate-comments.cpp:364: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="{{[^"]+}}annotate-comments.cpp" line="364" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
@@ -793,7 +824,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_VerbatimBlockCommand CommandName=[verbatim]
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href="http://example.com/">Aaa</a>])
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href='http://example.com/'>Aaa</a>])))]
-// CHECK: annotate-comments.cpp:345:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="345" column="6"><Name>comment_to_html_conversion_25</Name><USR>c:@F@comment_to_html_conversion_25#</USR><Abstract><Para> Blah blah.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:371:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="371" 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: CommentAST=[
// CHECK: (CXComment_FullComment
// CHECK: (CXComment_Paragraph IsWhitespace
@@ -810,13 +841,19 @@ enum class comment_to_xml_conversion_17 {
// CHECK: (CXComment_VerbatimLine Text=[ foo])
// CHECK: (CXComment_Paragraph
// CHECK: (CXComment_Text Text=[ Blah blah.])))]
-// CHECK: annotate-comments.cpp:348:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="348" column="6"><Name>comment_to_html_conversion_26</Name><USR>c:@F@comment_to_html_conversion_26#</USR><Abstract><Para> <bold>Aaa</bold></Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:374:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> </p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="374" 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: CommentAST=[
+// CHECK: (CXComment_FullComment
+// CHECK: (CXComment_Paragraph
+// CHECK: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK: (CXComment_InlineCommand CommandName=[unknown] RenderNormal)))]
+// CHECK: annotate-comments.cpp:377:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="377" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[b] RenderBold Arg[0]=Aaa)))]
-// CHECK: annotate-comments.cpp:351:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="351" column="6"><Name>comment_to_html_conversion_27</Name><USR>c:@F@comment_to_html_conversion_27#</USR><Abstract><Para> <monospaced>Aaa</monospaced> <monospaced>Bbb</monospaced></Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:380:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="380" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -824,7 +861,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[c] RenderMonospaced Arg[0]=Aaa)
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[p] RenderMonospaced Arg[0]=Bbb)))]
-// CHECK: annotate-comments.cpp:354:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="354" column="6"><Name>comment_to_html_conversion_28</Name><USR>c:@F@comment_to_html_conversion_28#</USR><Abstract><Para> <emphasized>Aaa</emphasized> <emphasized>Bbb</emphasized> <emphasized>Ccc</emphasized></Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:383: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="{{[^"]+}}annotate-comments.cpp" line="383" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -834,7 +871,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[e] RenderEmphasized Arg[0]=Bbb)
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=Ccc)))]
-// CHECK: annotate-comments.cpp:357:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} 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="{{[^"]+}}annotate-comments.cpp" line="357" column="6"><Name>comment_to_html_conversion_29</Name><USR>c:@F@comment_to_html_conversion_29#</USR><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: annotate-comments.cpp:386: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="{{[^"]+}}annotate-comments.cpp" line="386" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -851,7 +888,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[9<10] ParamPosition=Invalid
// CHECK-NEXT: (CXComment_Paragraph
// CHECK-NEXT: (CXComment_Text Text=[ bbb]))))]
-// CHECK: annotate-comments.cpp:360:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="360" column="6"><Name>comment_to_html_conversion_30</Name><USR>c:@F@comment_to_html_conversion_30#</USR><Abstract><Para> \ @ &amp; $ # &lt; &gt; % &quot; . ::</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:389:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="389" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -877,7 +914,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_Text Text=[.])
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
// CHECK-NEXT: (CXComment_Text Text=[::])))]
-// CHECK: annotate-comments.cpp:363:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot;</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="363" column="6"><Name>comment_to_html_conversion_31</Name><USR>c:@F@comment_to_html_conversion_31#</USR><Abstract><Para> &amp; &lt; &gt; &quot;</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:392:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot;</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="392" 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
@@ -889,7 +926,7 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_Text Text=[>])
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
// CHECK-NEXT: (CXComment_Text Text=["])))]
-// CHECK: annotate-comments.cpp:366:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="366" column="6"><Name>comment_to_html_conversion_32</Name><USR>c:@F@comment_to_html_conversion_32#</USR><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:395:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="395" 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-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -900,27 +937,27 @@ enum class comment_to_xml_conversion_17 {
// CHECK-NEXT: (CXComment_Text Text=[i])
// CHECK-NEXT: (CXComment_HTMLEndTag Name=[em])))]
-// CHECK: annotate-comments.cpp:369:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}annotate-comments.cpp" line="369" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01</USR><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:371:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="371" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:374:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="374" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:377:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="377" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:380:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="380" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:383:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="383" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:386:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="386" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:389:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="389" column="8"><Name>operator()</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator()#I#</USR><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:392:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="392" column="3"><Name>operator _Bool</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator _Bool#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:395:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="395" column="15"><Name>comment_to_xml_conversion_06</Name><USR>c:annotate-comments.cpp@8055@C@comment_to_xml_conversion_01@T@comment_to_xml_conversion_06</USR><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:398:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="398" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:405:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="405" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:410:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="410" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:414:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="414" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@F@comment_to_xml_conversion_10&lt;#I#I&gt;#I#I#</USR><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:418:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="418" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT&gt;2#T#T@comment_to_xml_conversion_11</USR><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:422:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}annotate-comments.cpp" line="422" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:426:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="426" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@C@comment_to_xml_conversion_11&gt;#I#I</USR><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:429:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="429" column="5"><Name>comment_to_xml_conversion_12</Name><USR>c:@comment_to_xml_conversion_12</USR><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:432:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="432" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
-// CHECK: annotate-comments.cpp:434:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="434" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
-// CHECK: annotate-comments.cpp:439:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="439" column="6"><Name>comment_to_xml_conversion_15</Name><USR>c:@E@comment_to_xml_conversion_15</USR><Abstract><Para> Aaa.</Para></Abstract></Enum>]
-// CHECK: annotate-comments.cpp:441:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="441" column="3"><Name>comment_to_xml_conversion_16</Name><USR>c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16</USR><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:445:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="445" column="12"><Name>comment_to_xml_conversion_17</Name><USR>c:@E@comment_to_xml_conversion_17</USR><Abstract><Para> Aaa.</Para></Abstract></Enum>]
-// CHECK: annotate-comments.cpp:447:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="447" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: annotate-comments.cpp:398:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}annotate-comments.cpp" line="398" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01</USR><Declaration>class comment_to_xml_conversion_01 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: annotate-comments.cpp:400:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="400" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Declaration></Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: annotate-comments.cpp:403:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="403" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Declaration>void ~comment_to_xml_conversion_01()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:406:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="406" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Declaration>int comment_to_xml_conversion_02(int 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: annotate-comments.cpp:409:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="409" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Declaration>static int comment_to_xml_conversion_03(int 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: annotate-comments.cpp:412:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="412" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Declaration>int comment_to_xml_conversion_04</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: annotate-comments.cpp:415:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="415" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Declaration>static int comment_to_xml_conversion_05</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: annotate-comments.cpp:418:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="418" column="8"><Name>operator()</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator()#I#</USR><Declaration>void operator()(int 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: annotate-comments.cpp:421:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="421" column="3"><Name>operator _Bool</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator _Bool#</USR><Declaration>bool operator _Bool()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:424:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="424" column="15"><Name>comment_to_xml_conversion_06</Name><USR>c:annotate-comments.cpp@8505@C@comment_to_xml_conversion_01@T@comment_to_xml_conversion_06</USR><Declaration>typedef int comment_to_xml_conversion_06</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: annotate-comments.cpp:427:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="427" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Declaration>using comment_to_xml_conversion_07 = int</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: annotate-comments.cpp:434:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="434" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template &lt;typename T&gt; using comment_to_xml_conversion_09 = comment_to_xml_conversion_08&lt;T, int&gt;</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+// CHECK: annotate-comments.cpp:439:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="439" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#</USR><Declaration>template &lt;typename T = int, typename U = int&gt; void comment_to_xml_conversion_10(int aaa, int bbb)template &lt;typename T, typename U&gt; void comment_to_xml_conversion_10(T aaa, U bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:443:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="443" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@F@comment_to_xml_conversion_10&lt;#I#I&gt;#I#I#</USR><Declaration>void comment_to_xml_conversion_10(int aaa, int bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK: annotate-comments.cpp:447:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="447" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T = int, typename U = int&gt; class comment_to_xml_conversion_11 {\n}\ntemplate &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: annotate-comments.cpp:451:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}annotate-comments.cpp" line="451" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Declaration>class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: annotate-comments.cpp:455:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="455" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@C@comment_to_xml_conversion_11&gt;#I#I</USR><Declaration>class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+// CHECK: annotate-comments.cpp:458:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="458" column="5"><Name>comment_to_xml_conversion_12</Name><USR>c:@comment_to_xml_conversion_12</USR><Declaration>int comment_to_xml_conversion_12</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: annotate-comments.cpp:461:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="461" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Declaration>namespace comment_to_xml_conversion_13 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
+// CHECK: annotate-comments.cpp:463:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="463" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Declaration>namespace comment_to_xml_conversion_14 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
+// CHECK: annotate-comments.cpp:468:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="468" column="6"><Name>comment_to_xml_conversion_15</Name><USR>c:@E@comment_to_xml_conversion_15</USR><Declaration>enum comment_to_xml_conversion_15{{( : int)?}} {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
+// CHECK: annotate-comments.cpp:470:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="470" column="3"><Name>comment_to_xml_conversion_16</Name><USR>c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16</USR><Declaration>comment_to_xml_conversion_16</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+// CHECK: annotate-comments.cpp:474:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="474" column="12"><Name>comment_to_xml_conversion_17</Name><USR>c:@E@comment_to_xml_conversion_17</USR><Declaration>enum class comment_to_xml_conversion_17 : int {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
+// CHECK: annotate-comments.cpp:476:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="476" 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>]
diff --git a/test/Index/annotate-deep-statements.cpp b/test/Index/annotate-deep-statements.cpp
new file mode 100644
index 000000000000..32a48b7d6ab7
--- /dev/null
+++ b/test/Index/annotate-deep-statements.cpp
@@ -0,0 +1,95 @@
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:1000:1 %s | FileCheck %s
+
+// rdar://11979525
+// Check that we don't get stack overflow trying to annotate an extremely deep AST.
+
+struct S {
+ S &operator()();
+};
+
+// CHECK: Identifier: "foo" [11:6 - 11:9] FunctionDecl=foo:11:6 (Definition)
+void foo() {
+ S s;
+ s()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
+ ;
+}
diff --git a/test/Index/annotate-macro-args.m b/test/Index/annotate-macro-args.m
index b92c0b29eb67..7d56523ce493 100644
--- a/test/Index/annotate-macro-args.m
+++ b/test/Index/annotate-macro-args.m
@@ -1,6 +1,6 @@
// Test without PCH
-// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:9:1:10:1 %s -include annotate-macro-args.h | FileCheck -check-prefix=CHECK1 %s
-// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:15:1:16:1 %s -include annotate-macro-args.h | FileCheck -check-prefix=CHECK2 %s
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:9:1:10:1 %s -include %S/annotate-macro-args.h | FileCheck -check-prefix=CHECK1 %s
+// RUN: c-index-test -test-annotate-tokens=%S/annotate-macro-args.h:15:1:16:1 %s -include %S/annotate-macro-args.h | FileCheck -check-prefix=CHECK2 %s
// Test with PCH
// RUN: c-index-test -write-pch %t.pch -x objective-c-header %S/annotate-macro-args.h -Xclang -detailed-preprocessing-record
diff --git a/test/Index/annotate-module.m b/test/Index/annotate-module.m
new file mode 100644
index 000000000000..3423f2b40d81
--- /dev/null
+++ b/test/Index/annotate-module.m
@@ -0,0 +1,42 @@
+
+#include <DependsOnModule/DependsOnModule.h>
+@__experimental_modules_import DependsOnModule;
+int glob;
+
+// RUN: rm -rf %t.cache
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:5:1 %s -fmodule-cache-path %t.cache -fmodules -F %S/../Modules/Inputs \
+// RUN: | FileCheck %s
+
+// CHECK: Punctuation: "#" [2:1 - 2:2] inclusion directive=[[INC_DIR:DependsOnModule[/\\]DependsOnModule\.h \(.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]DependsOnModule.h\)]]
+// CHECK-NEXT: Identifier: "include" [2:2 - 2:9] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Punctuation: "<" [2:10 - 2:11] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Identifier: "DependsOnModule" [2:11 - 2:26] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Punctuation: "/" [2:26 - 2:27] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Identifier: "DependsOnModule" [2:27 - 2:42] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Punctuation: "." [2:42 - 2:43] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Identifier: "h" [2:43 - 2:44] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Punctuation: ">" [2:44 - 2:45] inclusion directive=[[INC_DIR]]
+// CHECK-NEXT: Punctuation: "@" [3:1 - 3:2] ModuleImport=DependsOnModule:3:1
+// CHECK-NEXT: Keyword: "__experimental_modules_import" [3:2 - 3:31] ModuleImport=DependsOnModule:3:1
+// CHECK-NEXT: Identifier: "DependsOnModule" [3:32 - 3:47] ModuleImport=DependsOnModule:3:1
+// CHECK-NEXT: Punctuation: ";" [3:47 - 3:48]
+// CHECK-NEXT: Keyword: "int" [4:1 - 4:4] VarDecl=glob:4:5
+// CHECK-NEXT: Identifier: "glob" [4:5 - 4:9] VarDecl=glob:4:5
+// CHECK-NEXT: Punctuation: ";" [4:9 - 4:10]
+
+// RUN: c-index-test -test-annotate-tokens=%S/../Modules/Inputs/Module.framework/Headers/Sub.h:1:1:3:1 %s -fmodule-cache-path %t.cache -fmodules -F %S/../Modules/Inputs \
+// RUN: | FileCheck %s -check-prefix=CHECK-MOD
+
+// CHECK-MOD: Punctuation: "#" [1:1 - 1:2] inclusion directive=[[INC_DIR:Module[/\\]Sub2\.h \(.*/Modules/Inputs/Module\.framework[/\\]Headers[/\\]Sub2.h\)]]
+// CHECK-MOD-NEXT: Identifier: "include" [1:2 - 1:9] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Punctuation: "<" [1:10 - 1:11] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Identifier: "Module" [1:11 - 1:17] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Punctuation: "/" [1:17 - 1:18] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Identifier: "Sub2" [1:18 - 1:22] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Punctuation: "." [1:22 - 1:23] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Identifier: "h" [1:23 - 1:24] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Punctuation: ">" [1:24 - 1:25] inclusion directive=[[INC_DIR]]
+// CHECK-MOD-NEXT: Keyword: "int" [2:1 - 2:4] VarDecl=Module_Sub:2:6
+// CHECK-MOD-NEXT: Punctuation: "*" [2:5 - 2:6] VarDecl=Module_Sub:2:6
+// CHECK-MOD-NEXT: Identifier: "Module_Sub" [2:6 - 2:16] VarDecl=Module_Sub:2:6
+// CHECK-MOD-NEXT: Punctuation: ";" [2:16 - 2:17]
diff --git a/test/Index/arc-annotate.m b/test/Index/arc-annotate.m
index b836bc8b26de..95340938f0a0 100644
--- a/test/Index/arc-annotate.m
+++ b/test/Index/arc-annotate.m
@@ -4,7 +4,12 @@
@property (unsafe_unretained, nonatomic) id third_property;
@end
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck %s
+void foo() {
+ A *avar;
+ avar = 0;
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:11:1 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=A:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=A:1:12
// CHECK: Identifier: "A" [1:12 - 1:13] ObjCInterfaceDecl=A:1:12
@@ -36,3 +41,17 @@
// CHECK: Punctuation: ")" [4:40 - 4:41] ObjCPropertyDecl=third_property:4:45
// CHECK: Identifier: "id" [4:42 - 4:44] TypeRef=id:0:0
// CHECK: Identifier: "third_property" [4:45 - 4:59] ObjCPropertyDecl=third_property:4:45
+
+// CHECK: Identifier: "A" [8:3 - 8:4] ObjCClassRef=A:1:12
+// CHECK: Punctuation: "*" [8:5 - 8:6] VarDecl=avar:8:6 (Definition)
+// CHECK: Identifier: "avar" [8:6 - 8:10] VarDecl=avar:8:6 (Definition)
+// CHECK: Punctuation: ";" [8:10 - 8:11] DeclStmt=
+// CHECK: Identifier: "avar" [9:3 - 9:7] DeclRefExpr=avar:8:6
+// CHECK: Punctuation: "=" [9:8 - 9:9] BinaryOperator=
+// CHECK: Literal: "0" [9:10 - 9:11] IntegerLiteral=
+// CHECK: Punctuation: ";" [9:11 - 9:12] CompoundStmt=
+
+// RUN: c-index-test -file-refs-at=%s:8:8 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck %s -check-prefix=CHECK-REFS
+// CHECK-REFS: VarDecl=avar:8:6 (Definition)
+// CHECK-REFS: VarDecl=avar:8:6 (Definition) =[8:6 - 8:10]
+// CHECK-REFS: DeclRefExpr=avar:8:6 =[9:3 - 9:7]
diff --git a/test/Index/c-index-getCursor-pp.c b/test/Index/c-index-getCursor-pp.c
index 0a10450af5cd..01b0a6972ee5 100644
--- a/test/Index/c-index-getCursor-pp.c
+++ b/test/Index/c-index-getCursor-pp.c
@@ -15,6 +15,8 @@ B(int x);
const char *fname = __FILE__;
+#include <a.h>
+
// RUN: c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
// CHECK-1: macro definition=OBSCURE
// RUN: c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s
@@ -31,6 +33,8 @@ const char *fname = __FILE__;
// CHECK-7: macro expansion=B:12:9
// RUN: c-index-test -cursor-at=%s:16:25 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-8 %s
// CHECK-8: macro expansion=__FILE__
+// RUN: c-index-test -cursor-at=%s:18:12 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-9 %s
+// CHECK-9: inclusion directive=a.h
// Same tests, but with "editing" optimizations
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
diff --git a/test/Index/code-completion-skip-bodies.cpp b/test/Index/code-completion-skip-bodies.cpp
new file mode 100644
index 000000000000..67b219639629
--- /dev/null
+++ b/test/Index/code-completion-skip-bodies.cpp
@@ -0,0 +1,20 @@
+
+// This is to make sure we skip function bodies.
+void func_to_skip() {
+ undeclared1 = 0;
+}
+
+struct S { int x; };
+
+void func(S *s) {
+ undeclared2 = 0;
+ s->x = 0;
+}
+
+// RUN: c-index-test -code-completion-at=%s:11:6 %s 2>&1 | FileCheck %s
+// CHECK-NOT: error: use of undeclared identifier 'undeclared1'
+// CHECK: error: use of undeclared identifier 'undeclared2'
+// CHECK: FieldDecl:{ResultType int}{TypedText x}
+
+// FIXME: Investigating
+// XFAIL: cygwin,mingw32,win32
diff --git a/test/Index/comment-xml-schema.c b/test/Index/comment-xml-schema.c
index 1166e78f577e..91ea7b228351 100644
--- a/test/Index/comment-xml-schema.c
+++ b/test/Index/comment-xml-schema.c
@@ -12,6 +12,11 @@
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-function-08.xml
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-function-09.xml
//
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-availability-attr-01.xml
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-availability-attr-02.xml
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-deprecated-attr.xml
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-unavailable-attr.xml
+//
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-class-01.xml
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-class-02.xml
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-class-03.xml
diff --git a/test/Index/complete-cxx-inline-methods.cpp b/test/Index/complete-cxx-inline-methods.cpp
index d441972dd6fe..ee359f75e445 100644
--- a/test/Index/complete-cxx-inline-methods.cpp
+++ b/test/Index/complete-cxx-inline-methods.cpp
@@ -23,8 +23,8 @@ private:
};
}
-// RUN: c-index-test -code-completion-at=%s:4:9 %s | FileCheck %s
-// RUN: c-index-test -code-completion-at=%s:13:7 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:4:9 -std=c++98 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:13:7 -std=c++98 %s | FileCheck %s
// CHECK: CXXMethod:{ResultType MyCls::Vec &}{TypedText operator=}{LeftParen (}{Placeholder const MyCls::Vec &}{RightParen )} (34)
// CHECK-NEXT: StructDecl:{TypedText Vec}{Text ::} (75)
// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText x} (35)
diff --git a/test/Index/complete-documentation-templates.cpp b/test/Index/complete-documentation-templates.cpp
new file mode 100644
index 000000000000..4cb826e1d5aa
--- /dev/null
+++ b/test/Index/complete-documentation-templates.cpp
@@ -0,0 +1,151 @@
+// Note: the run lines follow their respective tests, since line/column numbers
+// matter in this test.
+
+/// This is T1.
+template<typename T>
+void T1(T t) { }
+
+/// This is T2.
+template<typename T>
+void T2(T t) { }
+
+/// This is T2<int>.
+template<>
+void T2(int t) { }
+
+void test_CC1() {
+
+}
+
+// Check that implicit instantiations of class templates and members pick up
+// comments from class templates and specializations.
+
+/// This is T3.
+template<typename T>
+class T3 {
+public:
+ /// This is T4.
+ static void T4();
+
+ /// This is T5.
+ static int T5;
+
+ /// This is T6.
+ void T6();
+
+ /// This is T7.
+ int T7;
+
+ /// This is T8.
+ class T8 {};
+
+ /// This is T9.
+ enum T9 {
+ /// This is T10.
+ T10
+ };
+
+ /// This is T11.
+ template<typename U>
+ void T11(U t) {}
+
+ typedef T3<double> T12;
+};
+
+void test_CC2_CC3_CC4() {
+ T3<int>::T4();
+ T3<int> t3;
+ t3.T6();
+ T3<int>::T8 t8;
+}
+
+/// This is T100.
+template<typename T, typename U>
+class T100 {
+};
+
+/// This is T100<int, T>.
+template<typename T>
+class T100<int, T> {
+public:
+ /// This is T101.
+ static void T101();
+
+ /// This is T102.
+ static int T102;
+
+ /// This is T103.
+ void T103();
+
+ /// This is T104.
+ int T104;
+
+ /// This is T105.
+ class T105 {};
+
+ /// This is T106.
+ enum T106 {
+ /// This is T107.
+ T107
+ };
+
+ /// This is T108.
+ template<typename U>
+ void T108(U t) {}
+
+ typedef T100<double, T> T109;
+
+ typedef T100<double, double> T110;
+};
+
+void test_CC5_CC6_CC7() {
+ T100<int, long>::T101();
+ T100<int, long> t100;
+ t100.T103();
+ 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
+// 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
+// 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
+// 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
+// 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
+// comment from class template.
+// CHECK-CC4: TypedefDecl:{TypedText T12}
+// CHECK-CC4-SHOULD-BE: TypedefDecl:{TypedText T12}{{.*}}(brief comment: This is T3.)
+// 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
+// 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
+// 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
+// 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.)
+// FIXME: after we implement propagating comments through typedefs, these two
+// typedefs for implicit instantiations should pick up the documentation
+// comment from class template.
+// CHECK-CC7: TypedefDecl:{TypedText T109}
+// CHECK-CC7: TypedefDecl:{TypedText T110}
+// CHECK-CC7-SHOULD-BE: TypedefDecl:{TypedText T109}{{.*}}(brief comment: This is T100.)
+// CHECK-CC7-SHOULD-BE: TypedefDecl:{TypedText T110}{{.*}}(brief comment: This is T100.)
+
diff --git a/test/Index/complete-documentation.cpp b/test/Index/complete-documentation.cpp
index a64e62f239de..49b61f03ce6c 100644
--- a/test/Index/complete-documentation.cpp
+++ b/test/Index/complete-documentation.cpp
@@ -47,5 +47,5 @@ void test1() {
// 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
-// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T7}{LeftParen (}{RightParen )} (34) (parent: StructDecl 'T6')(brief comment: Fff.)
-// CHECK-CC3: CXXMethod:{ResultType void}{TypedText T8}{LeftParen (}{RightParen )} (34) (parent: StructDecl 'T6')(brief comment: Ggg.)
+// 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-exprs.cpp b/test/Index/complete-exprs.cpp
index de3aac52c02d..3f3bd5c55a6b 100644
--- a/test/Index/complete-exprs.cpp
+++ b/test/Index/complete-exprs.cpp
@@ -78,7 +78,7 @@ namespace N {
// CHECK-CC4: NotImplemented:{ResultType const X *}{TypedText this} (40)
// RUN: c-index-test -code-completion-at=%s:43:14 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: FieldDecl:{ResultType int}{TypedText member} (8) (parent: ClassDecl 'N::C')
+// CHECK-CC5: FieldDecl:{ResultType int}{TypedText member} (8)
// CHECK-CC5: ParmDecl:{ResultType int}{TypedText param} (8)
-// CHECK-CC5: StructDecl:{TypedText X} (50) (parent: TranslationUnit '(null)')
-// CHECK-CC5: VarDecl:{ResultType int}{TypedText x} (12) (parent: Namespace 'N')
+// CHECK-CC5: StructDecl:{TypedText X} (50)
+// CHECK-CC5: VarDecl:{ResultType int}{TypedText x} (12)
diff --git a/test/Index/complete-lambdas.mm b/test/Index/complete-lambdas.mm
index 3f77dd206922..68f2b6b3fd17 100644
--- a/test/Index/complete-lambdas.mm
+++ b/test/Index/complete-lambdas.mm
@@ -23,16 +23,16 @@
@end
// RUN: c-index-test -code-completion-at=%s:14:6 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod:}{Placeholder (int)}{HorizontalSpace }{TypedText withOther:}{Placeholder (int)} (35) (parent: ObjCInterfaceDecl 'A')
+// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod:}{Placeholder (int)}{HorizontalSpace }{TypedText withOther:}{Placeholder (int)} (35)
// RUN: c-index-test -code-completion-at=%s:15:6 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: ObjCClassMethodDecl:{ResultType id}{TypedText classMethod} (35) (parent: ObjCInterfaceDecl 'A')
+// CHECK-CC2: ObjCClassMethodDecl:{ResultType id}{TypedText classMethod} (35)
// RUN: c-index-test -code-completion-at=%s:16:4 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: ObjCInterfaceDecl:{TypedText A} (50) (parent: TranslationUnit '(null)')
+// CHECK-CC3: ObjCInterfaceDecl:{TypedText A} (50)
// CHECK-CC3: ParmDecl:{ResultType A *}{TypedText a} (34)
-// CHECK-CC3: ObjCInterfaceDecl:{TypedText B} (50) (parent: TranslationUnit '(null)')
-// CHECK-CC3: TypedefDecl:{TypedText Class} (50) (parent: TranslationUnit '(null)')
+// CHECK-CC3: ObjCInterfaceDecl:{TypedText B} (50)
+// CHECK-CC3: TypedefDecl:{TypedText Class} (50)
// RUN: c-index-test -code-completion-at=%s:16:21 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC4 %s
@@ -46,6 +46,6 @@
// CHECK-CC5-NEXT: NotImplemented:{ResultType B *}{TypedText self} (34)
// RUN: c-index-test -code-completion-at=%s:20:11 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC6 %s
-// CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod:}{Placeholder (int)}{HorizontalSpace }{TypedText withOther:}{Placeholder (int)} (37) (parent: ObjCInterfaceDecl 'A')
-// CHECK-CC6-NEXT: ObjCInstanceMethodDecl:{ResultType id}{TypedText someMethod:}{Placeholder (A *)} (32) (parent: ObjCImplementationDecl 'B')
+// CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod:}{Placeholder (int)}{HorizontalSpace }{TypedText withOther:}{Placeholder (int)} (37)
+// CHECK-CC6-NEXT: ObjCInstanceMethodDecl:{ResultType id}{TypedText someMethod:}{Placeholder (A *)} (32)
diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c
index df798a8477f6..6d27b449ae2b 100644
--- a/test/Index/complete-macros.c
+++ b/test/Index/complete-macros.c
@@ -1,8 +1,8 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
-
#define FOO(Arg1,Arg2) foobar
#define nil 0
+#undef FOO
void f() {
}
@@ -25,7 +25,8 @@ void test_variadic() {
}
-// RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC0 %s
+// CHECK-CC0-NOT: FOO
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: macro definition:{TypedText FOO}{LeftParen (}{Placeholder Arg1}{Comma , }{Placeholder Arg2}{RightParen )}
// RUN: c-index-test -code-completion-at=%s:13:13 %s | FileCheck -check-prefix=CHECK-CC2 %s
diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m
index ce4824637092..9e52d93e5701 100644
--- a/test/Index/complete-method-decls.m
+++ b/test/Index/complete-method-decls.m
@@ -73,11 +73,11 @@
@end
// RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc} (40) (parent: ObjCProtocolDecl 'P1')
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt} (40) (parent: ObjCProtocolDecl 'P1')
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf} (40) (parent: ObjCProtocolDecl 'P1')
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40) (parent: ObjCProtocolDecl 'P1')
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y} (40) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y} (40)
// RUN: c-index-test -code-completion-at=%s:17:7 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText abc}
// CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{TypedText getSelf}
@@ -98,8 +98,8 @@
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:33:8 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42) (parent: ObjCProtocolDecl 'P1')
-// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40) (parent: ObjCInterfaceDecl 'B')
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42)
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40)
// CHECK-CC5-NOT: {TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:37:7 %s | FileCheck -check-prefix=CHECK-CC6 %s
@@ -181,4 +181,4 @@
// RUN: c-index-test -code-completion-at=%s:72:2 %s | FileCheck -check-prefix=CHECK-ONEWAY %s
-// CHECK-ONEWAY: ObjCInstanceMethodDecl:{LeftParen (}{Text oneway }{Text void}{RightParen )}{TypedText method}{TypedText :}{LeftParen (}{Text in }{Text id}{RightParen )}{Text x} (40) (parent: ObjCInterfaceDecl 'Passing')
+// CHECK-ONEWAY: ObjCInstanceMethodDecl:{LeftParen (}{Text oneway }{Text void}{RightParen )}{TypedText method}{TypedText :}{LeftParen (}{Text in }{Text id}{RightParen )}{Text x} (40)
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index 1835c3edc55e..aa10ea2445e2 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -190,11 +190,11 @@ void test_DO(DO *d, A* a) {
}
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: {TypedText categoryClassMethod} (35) (parent: ObjCCategoryDecl 'Foo(FooTestCategory)')
-// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)} (35) (parent: ObjCInterfaceDecl 'Foo')
-// CHECK-CC1: {TypedText classMethod2} (35) (parent: ObjCInterfaceDecl 'Foo')
-// CHECK-CC1: {TypedText new} (35) (parent: ObjCInterfaceDecl 'Foo')
-// CHECK-CC1: {TypedText protocolClassMethod} (37) (parent: ObjCProtocolDecl 'FooTestProtocol')
+// CHECK-CC1: {TypedText categoryClassMethod} (35)
+// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)} (35)
+// CHECK-CC1: {TypedText classMethod2} (35)
+// CHECK-CC1: {TypedText new} (35)
+// CHECK-CC1: {TypedText protocolClassMethod} (37)
// CHECK-CC1: Completion contexts:
// CHECK-CC1-NEXT: Objective-C class method
// CHECK-CC1-NEXT: Container Kind: ObjCInterfaceDecl
@@ -309,7 +309,7 @@ void test_DO(DO *d, A* a) {
// RUN: c-index-test -code-completion-at=%s:170:16 %s | FileCheck -check-prefix=CHECK-CLASS-RESULT %s
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method3} (35)
-// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35) (parent: ObjCCategoryDecl 'A(Cat)')
+// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35)
// RUN: c-index-test -code-completion-at=%s:181:4 %s | FileCheck -check-prefix=CHECK-BLOCK-RECEIVER %s
// CHECK-BLOCK-RECEIVER: ObjCInterfaceDecl:{TypedText A} (50)
diff --git a/test/Index/complete-preamble.cpp b/test/Index/complete-preamble.cpp
index 8f4810522527..61fb90a9db96 100644
--- a/test/Index/complete-preamble.cpp
+++ b/test/Index/complete-preamble.cpp
@@ -4,5 +4,5 @@ void f() {
}
// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CC1 %s
-// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50) (parent: Namespace 'std')
+// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50)
diff --git a/test/Index/complete-preprocessor.m b/test/Index/complete-preprocessor.m
index bea9d32d1a55..baeb4e94562f 100644
--- a/test/Index/complete-preprocessor.m
+++ b/test/Index/complete-preprocessor.m
@@ -53,8 +53,8 @@ FOO(in,t) value;
// CHECK-CC2-NEXT: NotImplemented:{TypedText undef}{HorizontalSpace }{Placeholder macro} (40)
// CHECK-CC2-NEXT: NotImplemented:{TypedText warning}{HorizontalSpace }{Placeholder message} (40)
// RUN: c-index-test -code-completion-at=%s:9:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: NotImplemented:{TypedText BAR} (40)
-// CHECK-CC3: NotImplemented:{TypedText FOO} (40)
+// CHECK-CC3: macro definition:{TypedText BAR} (40)
+// CHECK-CC3: macro definition:{TypedText FOO} (40)
// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: c-index-test -code-completion-at=%s:11:13 %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: c-index-test -code-completion-at=%s:11:5 %s | FileCheck -check-prefix=CHECK-CC4 %s
diff --git a/test/Index/complete-property-flags.m b/test/Index/complete-property-flags.m
index f2e08c36607c..86ee8e26f759 100644
--- a/test/Index/complete-property-flags.m
+++ b/test/Index/complete-property-flags.m
@@ -6,7 +6,8 @@
}
@property(copy) Foo *myprop;
@property(retain, nonatomic) id xx;
-// RUN: c-index-test -code-completion-at=%s:7:11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+
+// RUN: c-index-test -code-completion-at=%s:7:11 %s -fno-objc-arc | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText assign}
// CHECK-CC1-NEXT: {TypedText atomic}
// CHECK-CC1-NEXT: {TypedText copy}
@@ -18,9 +19,26 @@
// CHECK-CC1-NEXT: {TypedText setter}{Text = }{Placeholder method}
// CHECK-CC1-NEXT: {TypedText strong}
// CHECK-CC1-NEXT: {TypedText unsafe_unretained}
+// CHECK-CC1-NOT: {TypedText weak}
+
+// RUN: c-index-test -code-completion-at=%s:7:11 %s -fobjc-arc -fobjc-runtime=macosx-10.7 | FileCheck -check-prefix=CHECK-CC1-ARC %s
+// CHECK-CC1-ARC: {TypedText assign}
+// CHECK-CC1-ARC-NEXT: {TypedText atomic}
+// CHECK-CC1-ARC-NEXT: {TypedText copy}
+// CHECK-CC1-ARC-NEXT: {TypedText getter}{Text = }{Placeholder method}
+// CHECK-CC1-ARC-NEXT: {TypedText nonatomic}
+// CHECK-CC1-ARC-NEXT: {TypedText readonly}
+// CHECK-CC1-ARC-NEXT: {TypedText readwrite}
+// CHECK-CC1-ARC-NEXT: {TypedText retain}
+// CHECK-CC1-ARC-NEXT: {TypedText setter}{Text = }{Placeholder method}
+// CHECK-CC1-ARC-NEXT: {TypedText strong}
+// CHECK-CC1-ARC-NEXT: {TypedText unsafe_unretained}
+// CHECK-CC1-ARC-NEXT: {TypedText weak}
+
// RUN: c-index-test -code-completion-at=%s:8:18 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText getter}{Text = }{Placeholder method}
// CHECK-CC2-NEXT: {TypedText nonatomic}
+// CHECK-CC2-NEXT: {TypedText readonly}
// CHECK-CC2-NEXT: {TypedText readwrite}
// CHECK-CC2-NEXT: {TypedText setter}{Text = }{Placeholder method}
@end
diff --git a/test/Index/complete-qualified.cpp b/test/Index/complete-qualified.cpp
index f5c032c23d0b..38a678af2422 100644
--- a/test/Index/complete-qualified.cpp
+++ b/test/Index/complete-qualified.cpp
@@ -14,7 +14,7 @@ void foo()
Foo::
// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CC1 %s
-// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35) (parent: ClassDecl 'Foo')
-// CHECK-CC1: ClassDecl:{TypedText Foo} (35) (parent: ClassDecl 'Foo')
-// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35) (parent: ClassDecl 'Foo')
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35) (parent: ClassDecl 'Foo')
+// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35)
+// CHECK-CC1: ClassDecl:{TypedText Foo} (35)
+// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )}
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35)
diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm
index f9d6a8716d16..ac9e6d351a0a 100644
--- a/test/Index/cursor-dynamic-call.mm
+++ b/test/Index/cursor-dynamic-call.mm
@@ -50,10 +50,12 @@ void foo(SS *ss, IS* is, Class cls) {
// CHECK: 8:11 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call
// CHECK-NOT: 9:9 {{.*}} Dynamic-call
-// CHECK: 25:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call
+// CHECK: 25:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer
// CHECK-NOT: 26:3 {{.*}} Dynamic-call
// CHECK-NOT: 29:3 {{.*}} Dynamic-call
+// CHECK: 29:3 {{.*}} Receiver-type=ObjCInterface
// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call
-// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call
+// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer
// CHECK-NOT: 36:3 {{.*}} Dynamic-call
-// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call
+// CHECK: 36:3 {{.*}} Receiver-type=ObjCInterface
+// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call Receiver-type=ObjCClass
diff --git a/test/Index/get-cursor-macro-args.h b/test/Index/get-cursor-macro-args.h
index 40ec8dc0b81f..70d0dc7bf832 100644
--- a/test/Index/get-cursor-macro-args.h
+++ b/test/Index/get-cursor-macro-args.h
@@ -2,8 +2,8 @@
+(void)meth;
@end
-#define MACRO2(x) x
-#define MACRO(x) MACRO2(x)
+#define MACRO2(x) (x)
+#define MACRO(x) MACRO2((x))
void test() {
MACRO([MyClass meth]);
diff --git a/test/Index/get-cursor-macro-args.m b/test/Index/get-cursor-macro-args.m
index 4945fd389ad3..d5ab72878f52 100644
--- a/test/Index/get-cursor-macro-args.m
+++ b/test/Index/get-cursor-macro-args.m
@@ -1,14 +1,18 @@
// Test without PCH
// RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:9 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:22 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:12 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:20 \
-// RUN: %s -include get-cursor-macro-args.h | FileCheck %s
+// RUN: %s -include %S/get-cursor-macro-args.h | FileCheck %s
// Test with PCH
// RUN: c-index-test -write-pch %t.pch -x objective-c-header %S/get-cursor-macro-args.h
// RUN: c-index-test -cursor-at=%S/get-cursor-macro-args.h:9:12 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:21 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:9 \
+// RUN: -cursor-at=%S/get-cursor-macro-args.h:9:22 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:12 \
// RUN: -cursor-at=%S/get-cursor-macro-args.h:15:20 \
// RUN: %s -include-pch %t.pch | FileCheck %s
@@ -16,4 +20,6 @@
// CHECK: ObjCClassRef=MyClass:1:12
// CHECK-NEXT: ObjCMessageExpr=meth:2:8
// CHECK-NEXT: ObjCMessageExpr=meth:2:8
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
// CHECK-NEXT: ObjCClassRef=MyClass:1:12
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
index d3da9ec19726..7eaa3a0a3c1e 100644
--- a/test/Index/get-cursor.m
+++ b/test/Index/get-cursor.m
@@ -91,6 +91,14 @@ void foo3(Test3 *test3) {
}
@end
+@interface Test6
+@property (assign) id prop1;
+@end
+
+@implementation Test6
+@synthesize prop1 = _prop1;
+@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
@@ -126,11 +134,14 @@ void foo3(Test3 *test3) {
// CHECK-SPELLRANGE: 70:22 ObjCClassRef=Forw3:70:22 Extent=[70:22 - 70:27] Spelling=Forw3 ([70:22 - 70:27])
// RUN: c-index-test -cursor-at=%s:83:15 -cursor-at=%s:83:21 \
-// RUN: -cursor-at=%s:84:12 -cursor-at=%s:84:20 %s | FileCheck -check-prefix=CHECK-MULTISYNTH %s
+// RUN: -cursor-at=%s:84:12 -cursor-at=%s:84:20 \
+// RUN: -cursor-at=%s:99:14 -cursor-at=%s:99:23 %s | FileCheck -check-prefix=CHECK-MULTISYNTH %s
// CHECK-MULTISYNTH: 83:13 ObjCSynthesizeDecl=prop1:76:23 (Definition) Extent=[83:1 - 83:18] Spelling=prop1 ([83:13 - 83:18])
// CHECK-MULTISYNTH: 83:20 ObjCSynthesizeDecl=prop2:77:23 (Definition) Extent=[83:1 - 83:25] Spelling=prop2 ([83:20 - 83:25])
// CHECK-MULTISYNTH: 84:10 ObjCDynamicDecl=prop3:78:23 (Definition) Extent=[84:1 - 84:15] Spelling=prop3 ([84:10 - 84:15])
// CHECK-MULTISYNTH: 84:17 ObjCDynamicDecl=prop4:79:23 (Definition) Extent=[84:1 - 84:22] Spelling=prop4 ([84:17 - 84:22])
+// CHECK-MULTISYNTH: 99:13 ObjCSynthesizeDecl=prop1:95:23 (Definition) Extent=[99:1 - 99:27] Spelling=prop1 ([99:13 - 99:18])
+// CHECK-MULTISYNTH: 99:21 MemberRef=_prop1:99:21 Extent=[99:21 - 99:27] Spelling=_prop1 ([99:21 - 99:27])
// 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
diff --git a/test/Index/index-decls.m b/test/Index/index-decls.m
index 46d37c4345a4..c6b14bb8fda5 100644
--- a/test/Index/index-decls.m
+++ b/test/Index/index-decls.m
@@ -26,6 +26,13 @@ __attribute__((something)) @interface I2 @end
}
@end
+int test1() {
+ extern int extvar;
+ extvar = 2;
+ extern int extfn();
+ return extfn();
+}
+
// 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
@@ -41,3 +48,9 @@ __attribute__((something)) @interface I2 @end
// CHECK: [indexDeclaration]: kind: objc-ivar | name: _auto_prop | {{.*}} | loc: 20:33
// CHECK: [indexEntityReference]: kind: objc-ivar | name: _auto_prop | {{.*}} | loc: 25:3
+
+// CHECK: [indexDeclaration]: kind: function | name: test1 | {{.*}} | loc: 29:5
+// CHECK: [indexDeclaration]: kind: variable | name: extvar | {{.*}} | loc: 30:14
+// 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
diff --git a/test/Index/index-file.cpp b/test/Index/index-file.cpp
new file mode 100644
index 000000000000..bf2d62c55680
--- /dev/null
+++ b/test/Index/index-file.cpp
@@ -0,0 +1,6 @@
+using MyTypeAlias = 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
diff --git a/test/Index/index-module.m b/test/Index/index-module.m
new file mode 100644
index 000000000000..0af4e37f3c3d
--- /dev/null
+++ b/test/Index/index-module.m
@@ -0,0 +1,54 @@
+
+#include <DependsOnModule/DependsOnModule.h>
+@__experimental_modules_import DependsOnModule;
+int glob;
+
+// RUN: rm -rf %t.cache
+// RUN: c-index-test -index-file %s -fmodule-cache-path %t.cache -fmodules -F %S/../Modules/Inputs \
+// RUN: -Xclang -fdisable-module-hash | FileCheck %s
+
+// CHECK-NOT: [indexDeclaration]
+// CHECK: [importedASTFile]: [[PCM:.*[/\\]DependsOnModule\.pcm]] | loc: 2:2 | name: "DependsOnModule" | isImplicit: 1
+// CHECK-NEXT: [ppIncludedFile]: {{.*}}/Modules/Inputs/DependsOnModule.framework{{[/\\]}}Headers{{[/\\]}}DependsOnModule.h | name: "DependsOnModule/DependsOnModule.h" | hash loc: 2:1 | isImport: 0 | isAngled: 1 | isModule: 1
+// CHECK-NOT: [indexDeclaration]
+// CHECK: [importedASTFile]: [[PCM]] | loc: 3:1 | name: "DependsOnModule" | isImplicit: 0
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: glob | {{.*}} | loc: 4:5
+// CHECK-NOT: [indexDeclaration]
+
+// RUN: c-index-test -index-tu %t.cache/DependsOnModule.pcm | FileCheck %s -check-prefix=CHECK-DMOD
+
+// CHECK-DMOD: [startedTranslationUnit]
+// 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_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: 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
+// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_private | {{.*}} | loc: [[DMOD_PRIVATE_H]]:1:5
+// CHECK-DMOD-NOT: [indexDeclaration]
+
+// RUN: c-index-test -index-tu %t.cache/Module.pcm | FileCheck %s -check-prefix=CHECK-TMOD
+
+// CHECK-TMOD: [startedTranslationUnit]
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMOD_MODULE_H:.*/Modules/Inputs/Module\.framework[/\\]Headers[/\\]Module\.h]] | {{.*}} | hash loc: <invalid>
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR:.*/Modules/Inputs/Module.framework[/\\]Headers.]]Sub.h | name: "Module/Sub.h" | hash loc: [[TMOD_MODULE_H]]:23:1 | isImport: 0 | isAngled: 1
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR]]Sub2.h | name: "Module/Sub2.h" | hash loc: [[TMODHDR]]Sub.h:1:1 | isImport: 0 | isAngled: 1
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMODHDR]]Buried/Treasure.h | name: "Module/Buried/Treasure.h" | hash loc: [[TMOD_MODULE_H]]:24:1 | isImport: 0 | isAngled: 1
+// CHECK-TMOD-NEXT: [ppIncludedFile]: [[TMOD_SUB_H:.*[/\\]Modules[/\\]Inputs[/\\]Module\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: <invalid>
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: function | name: getModuleVersion | {{.*}} | loc: [[TMOD_MODULE_H]]:9:13
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: objc-class | name: Module | {{.*}} | loc: [[TMOD_MODULE_H]]:15:12
+// CHECK-TMOD-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: objc-class-method | name: version | {{.*}} | loc: [[TMOD_MODULE_H]]:16:1
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: objc-class-method | name: alloc | {{.*}} | loc: [[TMOD_MODULE_H]]:17:1
+// CHECK-TMOD-NEXT: [importedASTFile]: [[PCM:.*\.cache/Module\.pcm]] | loc: [[TMOD_MODULE_H]]:23:2 | name: "Module.Sub" | isImplicit: 1
+// CHECK-TMOD-NEXT: [importedASTFile]: [[PCM]] | loc: [[TMOD_MODULE_H]]:24:2 | name: "Module.Buried.Treasure" | isImplicit: 1
+// CHECK-TMOD-NEXT: [importedASTFile]: [[PCM]] | loc: [[TMODHDR]]Sub.h:1:2 | name: "Module.Sub2" | isImplicit: 1
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Module_Sub | {{.*}} | loc: [[TMODHDR]]Sub.h:2:6
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Module_Sub2 | USR: c:@Module_Sub2 | {{.*}} | loc: [[TMODHDR]]Sub2.h:1:6
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: Buried_Treasure | {{.*}} | loc: [[TMODHDR]]Buried/Treasure.h:1:11
+// CHECK-TMOD-NEXT: [indexDeclaration]: kind: variable | name: module_subframework | {{.*}} | loc: [[TMOD_SUB_H]]:4:7
+// CHECK-TMOD-NOT: [indexDeclaration]
diff --git a/test/Index/index-pch-with-module.m b/test/Index/index-pch-with-module.m
new file mode 100644
index 000000000000..ebab648c43d4
--- /dev/null
+++ b/test/Index/index-pch-with-module.m
@@ -0,0 +1,31 @@
+
+#ifndef PCH_HEADER
+#define PCH_HEADER
+
+#include <DependsOnModule/DependsOnModule.h>
+extern int pch_glob;
+
+#else
+
+int glob;
+
+#endif
+
+// RUN: rm -rf %t.cache
+// RUN: c-index-test -write-pch %t.h.pch %s -fmodule-cache-path %t.cache -fmodules -F %S/../Modules/Inputs -Xclang -fdisable-module-hash
+// RUN: c-index-test -index-file %s -include %t.h -fmodule-cache-path %t.cache -fmodules -F %S/../Modules/Inputs \
+// RUN: -Xclang -fdisable-module-hash | FileCheck %s
+
+// CHECK-NOT: [indexDeclaration]
+// CHECK: [importedASTFile]: {{.*}}.h.pch
+// CHECK-NEXT: [enteredMainFile]: {{.*[/\\]}}index-pch-with-module.m
+// CHECK-NEXT: [startedTranslationUnit]
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: glob | {{.*}} | loc: 10:5
+// CHECK-NOT: [indexDeclaration]
+
+// RUN: c-index-test -index-tu %t.h.pch | FileCheck %s -check-prefix=CHECK-PCH
+
+// CHECK-PCH: [enteredMainFile]: {{.*[/\\]}}index-pch-with-module.m
+// CHECK-PCH: [startedTranslationUnit]
+// CHECK-PCH: [importedASTFile]: {{.*}}.cache{{[/\\]}}DependsOnModule.pcm | loc: 5:2 | name: "DependsOnModule" | isImplicit: 1
+// CHECK-PCH: [indexDeclaration]: kind: variable | name: pch_glob | {{.*}} | loc: 6:12
diff --git a/test/Index/index-pch.cpp b/test/Index/index-pch.cpp
new file mode 100644
index 000000000000..c8da7b2fbf2a
--- /dev/null
+++ b/test/Index/index-pch.cpp
@@ -0,0 +1,6 @@
+// RUN: c-index-test -write-pch %t.pch -fshort-wchar %s
+// RUN: c-index-test -index-tu %t.pch | FileCheck %s
+
+const wchar_t *wideStr = L"123";
+
+// CHECK: [indexDeclaration]: kind: variable | name: wideStr
diff --git a/test/Index/index-with-working-dir.c b/test/Index/index-with-working-dir.c
new file mode 100644
index 000000000000..de1f1ebe1a98
--- /dev/null
+++ b/test/Index/index-with-working-dir.c
@@ -0,0 +1,5 @@
+
+void foo();
+
+// RUN: c-index-test -index-file -working-directory=%S %s | FileCheck %s
+// CHECK: [indexDeclaration]: kind: function | name: foo
diff --git a/test/Index/overrides.cpp b/test/Index/overrides.cpp
index 698b2566bbe0..a711d82bea80 100644
--- a/test/Index/overrides.cpp
+++ b/test/Index/overrides.cpp
@@ -15,6 +15,9 @@ struct D : C {
virtual void f(int);
};
+void C::g() {}
+
// 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]
diff --git a/test/Index/overrides.m b/test/Index/overrides.m
index d0447b74739d..d2f1506fef5f 100644
--- a/test/Index/overrides.m
+++ b/test/Index/overrides.m
@@ -99,11 +99,11 @@
// RUN: c-index-test -test-load-source local %s | FileCheck %s
// CHECK: overrides.m:12:9: ObjCInstanceMethodDecl=protoMethod:12:9 [Overrides @3:9]
// CHECK: overrides.m:22:9: ObjCInstanceMethodDecl=method:22:9 [Overrides @16:9]
-// CHECK: overrides.m:23:9: ObjCInstanceMethodDecl=protoMethod:23:9 [Overrides @12:9, @8:9, @32:9, @17:9]
+// CHECK: overrides.m:23:9: ObjCInstanceMethodDecl=protoMethod:23:9 [Overrides @8:9, @12:9, @17:9, @32:9]
// CHECK: overrides.m:27:9: ObjCInstanceMethodDecl=method:27:9 (Definition) [Overrides @16:9]
// CHECK: overrides.m:28:9: ObjCClassMethodDecl=methodWithParam::28:9 (Definition) [Overrides @18:9]
// CHECK: overrides.m:32:9: ObjCInstanceMethodDecl=protoMethod:32:9 [Overrides @8:9]
-// CHECK: overrides.m:36:9: ObjCInstanceMethodDecl=protoMethod:36:9 [Overrides @12:9, @8:9, @32:9, @17:9]
+// CHECK: overrides.m:36:9: ObjCInstanceMethodDecl=protoMethod:36:9 [Overrides @8:9, @12:9, @17:9, @32:9]
// CHECK: overrides.m:50:8: ObjCInstanceMethodDecl=meth:50:8 (Definition) [Overrides @43:8]
// CHECK: overrides.m:55:8: ObjCInstanceMethodDecl=kol:55:8 Extent=[55:1 - 55:12]
// CHECK: overrides.m:65:26: ObjCInstanceMethodDecl=prop1:65:26 [Overrides @59:25] Extent=[65:26 - 65:31]
diff --git a/test/Index/overriding-ftemplate-comments.cpp b/test/Index/overriding-ftemplate-comments.cpp
new file mode 100644
index 000000000000..2c5f539a8415
--- /dev/null
+++ b/test/Index/overriding-ftemplate-comments.cpp
@@ -0,0 +1,79 @@
+// 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 %s > %t/out
+// RUN: FileCheck %s < %t/out
+// Test to search overridden methods for documentation when overriding method has none. rdar://12378793
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+/// \tparam
+/// \param AAA Blah blah
+template<typename T>
+void comment_to_html_conversion_17(T AAA);
+
+template<typename T>
+void comment_to_html_conversion_17(T PPP);
+
+/// \tparam BBB Bbb
+/// \tparam AAA Aaa
+template<typename AAA, typename BBB>
+void comment_to_html_conversion_19(AAA aaa, BBB bbb);
+
+template<typename PPP, typename QQQ>
+void comment_to_html_conversion_19(PPP aaa, QQQ bbb);
+
+/// \tparam BBB Bbb
+/// \tparam UUU Zzz
+/// \tparam CCC Ccc
+/// \tparam AAA Aaa
+template<typename AAA, typename BBB, int CCC>
+void comment_to_html_conversion_20(AAA aaa, BBB bbb);
+
+template<typename PPP, typename QQQ, int RRR>
+void comment_to_html_conversion_20(PPP aaa, QQQ bbb);
+
+/// \tparam AAA Aaa
+/// \tparam BBB Bbb
+/// \tparam CCC Ccc
+/// \tparam DDD Ddd
+template<template<template<typename CCC> class DDD, class BBB> class AAA>
+void comment_to_html_conversion_21();
+
+template<template<template<typename RRR> class SSS, class QQQ> class PPP>
+void comment_to_html_conversion_21();
+
+/// \tparam C1 Ccc 1
+/// \tparam AAA Zzz
+/// \tparam C2 Ccc 2
+/// \tparam C3 Ccc 3
+/// \tparam C4 Ccc 4
+/// \tparam BBB Bbb
+template<class C1, template<class C2, template<class C3, class C4> class BBB> class AAA>
+void comment_to_html_conversion_22();
+
+
+template<class CCC1, template<class CCC2, template<class CCC3, class CCC4> class QQQ> class PPP>
+void comment_to_html_conversion_22();
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="14" 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: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="17" 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 PPP)</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="22" 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 AAA, typename BBB&gt; void comment_to_html_conversion_19(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="25" 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 PPP, typename QQQ&gt; void comment_to_html_conversion_19(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="32" 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 AAA, typename BBB, int CCC&gt; void comment_to_html_conversion_20(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="35" 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 PPP, typename QQQ, int RRR&gt; void comment_to_html_conversion_20(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="42" 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 CCC&gt; class DDD, class BBB&gt; class AAA&gt; void comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>DDD</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="45" 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 RRR&gt; class SSS, class QQQ&gt; class PPP&gt; void comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>SSS</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="54" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class C1, template &lt;class C2, template &lt;class C3, class C4&gt; class BBB&gt; class AAA&gt; void comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>C1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>AAA</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>C2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>C3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>C4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="58" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt; class QQQ&gt; class PPP&gt; void comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
new file mode 100644
index 000000000000..e7181380cb81
--- /dev/null
+++ b/test/Index/overriding-method-comments.mm
@@ -0,0 +1,124 @@
+// 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 %s > %t/out
+// RUN: FileCheck %s < %t/out
+// Test to search overridden methods for documentation when overriding method has none. rdar://12378793
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+@protocol P
+- (void)METH:(id)PPP;
+@end
+
+@interface Root<P>
+/**
+ * \param[in] AAA ZZZ
+ */
+- (void)METH:(id)AAA;
+@end
+
+@interface Sub : Root
+@end
+
+@interface Sub (CAT)
+- (void)METH:(id)BBB;
+@end
+
+@implementation Sub(CAT)
+- (void)METH:(id)III {}
+@end
+
+@interface Redec : Root
+@end
+
+@interface Redec()
+/**
+ * \param[in] AAA input value
+ * \param[out] CCC output value is int
+ * \param[in] BBB 2nd input value is double
+ */
+- (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC;
+@end
+
+@implementation Redec
+- (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {}
+@end
+
+struct Base {
+ /// \brief Does something.
+ /// \param AAA argument to foo_pure.
+ virtual void foo_pure(int AAA) = 0;
+
+ /// \brief Does something.
+ /// \param BBB argument to defined virtual.
+ virtual void foo_inline(int BBB) {}
+
+ /// \brief Does something.
+ /// \param CCC argument to undefined virtual.
+ virtual void foo_outofline(int CCC);
+};
+
+void Base::foo_outofline(int RRR) {}
+
+struct Derived : public Base {
+ virtual void foo_pure(int PPP);
+
+ virtual void foo_inline(int QQQ) {}
+};
+
+/// \brief Does something.
+/// \param DDD a value.
+void foo(int DDD);
+
+void foo(int SSS) {}
+
+/// \brief Does something.
+/// \param EEE argument to function decl.
+void foo1(int EEE);
+
+void foo1(int TTT);
+
+/// \brief Documentation
+/// \tparam BBB The type, silly.
+/// \tparam AAA The type, silly as well.
+template<typename AAA, typename BBB>
+void foo(AAA, BBB);
+
+template<typename PPP, typename QQQ>
+void foo(PPP, QQQ);
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="19" 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="26" 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="30" 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="42" 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="46" 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="52" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int AAA) = 0</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="56" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int BBB)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="60" column="16"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>virtual void foo_outofline(int CCC)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>CCC</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="63" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="66" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int PPP)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="68" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int QQQ)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>QQQ</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="73" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int DDD)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>DDD</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="75" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int SSS)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>SSS</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="79" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int EEE)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>EEE</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="81" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int TTT)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>TTT</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="87" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void foo(AAA, BBB)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="90" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void foo(PPP, QQQ)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/preamble-reparse-with-BOM.m b/test/Index/preamble-reparse-with-BOM.m
new file mode 100644
index 000000000000..a2a89c8d8e15
--- /dev/null
+++ b/test/Index/preamble-reparse-with-BOM.m
@@ -0,0 +1,6 @@
+
+@interface I2
+@end
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 \
+// RUN: c-index-test -test-load-source-reparse 1 local %s
diff --git a/test/Index/rdar12316296-codecompletion.m b/test/Index/rdar12316296-codecompletion.m
new file mode 100644
index 000000000000..f588a9983718
--- /dev/null
+++ b/test/Index/rdar12316296-codecompletion.m
@@ -0,0 +1,23 @@
+// RUN: c-index-test -write-pch %t.h.pch %s
+// RUN: c-index-test -code-completion-at=%s:19:1 %s -include %t.h | FileCheck %s
+
+// <rdar://12316296> clang Code Completion returns nothing but preprocessor macros
+
+#ifndef HEADER
+#define HEADER
+
+@interface I
+@end
+
+// CHECK: FunctionDecl:{ResultType void}{TypedText foo}
+void foo();
+
+#else
+
+@implementation I
+-(void)meth {
+
+}
+@end
+
+#endif
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 9b93872ee01b..501dc2954f02 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -1523,7 +1523,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ";" [185:31 - 185:32] CompoundStmt=
// CHECK-tokens: Punctuation: "}" [186:1 - 186:2] CompoundStmt=
-// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s
+// RUN: c-index-test -test-load-source all %s -std=c++98 2>&1 | FileCheck %s
// CHECK: 1:27: TypedefDecl=__darwin_size_t:1:27 (Definition) Extent=[1:1 - 1:42]
// CHECK: 2:25: TypedefDecl=size_t:2:25 (Definition) Extent=[2:1 - 2:31]
// CHECK: 2:9: TypeRef=__darwin_size_t:1:27 Extent=[2:9 - 2:24]
diff --git a/test/Index/retain-comments-from-system-headers.c b/test/Index/retain-comments-from-system-headers.c
new file mode 100644
index 000000000000..a9b2e2f1ef3c
--- /dev/null
+++ b/test/Index/retain-comments-from-system-headers.c
@@ -0,0 +1,19 @@
+// Run lines are sensitive to line numbers and come below the code.
+
+#include "retain-comments-from-system-headers.h"
+
+/**
+ * user_function
+ * \param a Aaa.
+ */
+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
+
+// 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]
+
+// CHECK-RETAIN: retain-comments-from-system-headers.h:7:5: FunctionDecl=system_function:7:5 RawComment=[/**\n * system_function\n * \param a Aaa.\n */] RawCommentRange=[3:1 - 6:4] BriefComment=[system_function]
+// CHECK-RETAIN: 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/usrs.m b/test/Index/usrs.m
index 95a538825f8c..be0e323c9360 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -120,7 +120,6 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@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@d1 Extent=[44:13 - 44:15]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
// CHECK: usrs.m c:@z Extent=[47:1 - 47:6]
// CHECK: usrs.m c:usrs.m@529@F@local_func Extent=[49:1 - 49:43]
@@ -208,7 +207,6 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:42:3: ReturnStmt= Extent=[42:3 - 42:11]
// CHECK-source: usrs.m:42:10: UnexposedExpr= Extent=[42:10 - 42:11]
// CHECK-source: usrs.m:42:10: IntegerLiteral= Extent=[42:10 - 42:11]
-// CHECK-source: usrs.m:44:13: ObjCIvarDecl=d1:44:13 (Definition) Extent=[44:13 - 44:15]
// CHECK-source: usrs.m:44:13: ObjCSynthesizeDecl=d1:31:15 (Definition) Extent=[44:1 - 44:15]
// CHECK-source: usrs.m:47:5: VarDecl=z:47:5 Extent=[47:1 - 47:6]
// CHECK-source: usrs.m:49:12: FunctionDecl=local_func:49:12 (Definition) Extent=[49:1 - 49:43]
diff --git a/test/Lexer/clang-keywords.cpp b/test/Lexer/clang-keywords.cpp
index a349b44ade20..3a24dce981a3 100644
--- a/test/Lexer/clang-keywords.cpp
+++ b/test/Lexer/clang-keywords.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
__char16_t c16;
void f(__char32_t) { }
diff --git a/test/Lexer/digraph.c b/test/Lexer/digraph.c
index cf6e4789afa8..e940caf44f4b 100644
--- a/test/Lexer/digraph.c
+++ b/test/Lexer/digraph.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// expected-no-diagnostics
%:include <stdint.h>
diff --git a/test/Lexer/dollar-idents.c b/test/Lexer/dollar-idents.c
index cbf25b0251bc..e57ee865886b 100644
--- a/test/Lexer/dollar-idents.c
+++ b/test/Lexer/dollar-idents.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -dump-tokens %s 2> %t
-// RUN: grep "identifier '\$A'" %t
-// RUN: %clang_cc1 -dump-tokens -x assembler-with-cpp %s 2> %t
-// RUN: grep "identifier 'A'" %t
+// 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
// PR3808
+// CHECK: identifier '$A'
+// CHECK-ASM: identifier 'A'
$A
diff --git a/test/Lexer/eof-char.c b/test/Lexer/eof-char.c
new file mode 100644
index 000000000000..42ee6ea6ed0b
--- /dev/null
+++ b/test/Lexer/eof-char.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// vim: set binary noeol:
+
+// This file intentionally ends without a \n on the last line. Make sure your
+// editor doesn't add one.
+
+// expected-warning@+1{{missing terminating ' character}} expected-error@+1{{expected expression}} expected-error@+1{{expected ';'}}
+char c = '\ \ No newline at end of file
diff --git a/test/Lexer/eof-file.c b/test/Lexer/eof-file.c
new file mode 100644
index 000000000000..43c300c04c9e
--- /dev/null
+++ b/test/Lexer/eof-file.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// vim: set binary noeol:
+
+// This file intentionally ends without a \n on the last line. Make sure your
+// editor doesn't add one.
+
+// expected-error@+1{{expected expression}} expected-error@+1{{expected ';'}}
+char c = \ \ No newline at end of file
diff --git a/test/Lexer/eof-string.c b/test/Lexer/eof-string.c
new file mode 100644
index 000000000000..e1a60a475055
--- /dev/null
+++ b/test/Lexer/eof-string.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// vim: set binary noeol:
+
+// This file intentionally ends without a \n on the last line. Make sure your
+// editor doesn't add one.
+
+// expected-warning@+1{{missing terminating '"' character}} expected-error@+1{{expected expression}} expected-error@+1{{expected ';'}}
+char c = "\ \ No newline at end of file
diff --git a/test/Lexer/gnu_keywords.c b/test/Lexer/gnu_keywords.c
index c4bd9b3e59d6..10a7d31d2038 100644
--- a/test/Lexer/gnu_keywords.c
+++ b/test/Lexer/gnu_keywords.c
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s
+// expected-no-diagnostics
void f() {
#ifdef GNU_KEYWORDS
diff --git a/test/Lexer/has_feature_address_sanitizer.cpp b/test/Lexer/has_feature_address_sanitizer.cpp
index 69acc39f0a85..5c981161f9fc 100644
--- a/test/Lexer/has_feature_address_sanitizer.cpp
+++ b/test/Lexer/has_feature_address_sanitizer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E -faddress-sanitizer %s -o - | FileCheck --check-prefix=CHECK-ASAN %s
+// RUN: %clang_cc1 -E -fsanitize=address %s -o - | FileCheck --check-prefix=CHECK-ASAN %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-ASAN %s
#if __has_feature(address_sanitizer)
diff --git a/test/Lexer/long-long.cpp b/test/Lexer/long-long.cpp
new file mode 100644
index 000000000000..1a0f37b7ff40
--- /dev/null
+++ b/test/Lexer/long-long.cpp
@@ -0,0 +1,24 @@
+/* RUN: %clang_cc1 -x c -std=c89 -fsyntax-only -verify -pedantic-errors -Wno-empty-translation-unit %s
+ * RUN: %clang_cc1 -x c -std=c99 -fsyntax-only -verify -pedantic-errors -Wno-empty-translation-unit %s
+ * RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify -pedantic-errors -Wno-empty-translation-unit %s
+ * RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify -Wc++98-compat-pedantic -Wno-empty-translation-unit %s
+ */
+
+#if !defined(__cplusplus)
+# if __STDC_VERSION__ < 199901L
+/* expected-error@21 {{'long long' is an extension when C99 mode is not enabled}} */
+# else
+/* expected-no-diagnostics */
+# endif
+#else
+# if __cplusplus < 201103L
+/* expected-error@21 {{'long long' is a C++11 extension}} */
+# else
+/* expected-warning@21 {{'long long' is incompatible with C++98}} */
+# endif
+#endif
+
+#if 1 > 2LL
+# error should not happen
+#endif
+
diff --git a/test/Lexer/msdos-cpm-eof.c b/test/Lexer/msdos-cpm-eof.c
index 9ef6e32ea0b4..3469b59d4089 100644
--- a/test/Lexer/msdos-cpm-eof.c
+++ b/test/Lexer/msdos-cpm-eof.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+// expected-no-diagnostics
int x;
diff --git a/test/Lexer/newline-eof-c++11.cpp b/test/Lexer/newline-eof-c++11.cpp
index 3c45f28336f5..eeabe8bb9fc3 100644
--- a/test/Lexer/newline-eof-c++11.cpp
+++ b/test/Lexer/newline-eof-c++11.cpp
@@ -1,4 +1,5 @@
// 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/numeric-literal-trash.c b/test/Lexer/numeric-literal-trash.c
index 5407ba9824f7..60981feee16b 100644
--- a/test/Lexer/numeric-literal-trash.c
+++ b/test/Lexer/numeric-literal-trash.c
@@ -1,5 +1,5 @@
/* RUN: %clang_cc1 -fsyntax-only -verify %s
- */
+ * expected-no-diagnostics */
# define XRECORD(x, c_name) e##c (x, __LINE__)
diff --git a/test/Lexer/pragma-mark.c b/test/Lexer/pragma-mark.c
index 96e8485a70ac..e58b2267ddbc 100644
--- a/test/Lexer/pragma-mark.c
+++ b/test/Lexer/pragma-mark.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// Lexer diagnostics shouldn't be included in #pragma mark.
#pragma mark Mike's world
diff --git a/test/Lexer/rdr-6096838.c b/test/Lexer/rdr-6096838.c
index d1426cca14aa..b77b95e79613 100644
--- a/test/Lexer/rdr-6096838.c
+++ b/test/Lexer/rdr-6096838.c
@@ -2,5 +2,6 @@
* RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=gnu89 -fsyntax-only -verify %s
rdar://6096838
*/
+// expected-no-diagnostics
long double d = 0x0.0000003ffffffff00000p-16357L;
diff --git a/test/Lexer/string-literal-errors.cpp b/test/Lexer/string-literal-errors.cpp
new file mode 100644
index 000000000000..be574c2a557b
--- /dev/null
+++ b/test/Lexer/string-literal-errors.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
+
+void foo() {
+ (void)"\q \u123z \x \U \U123 \U12345 \u123 \xyzzy \777 \U"
+ // CHECK: {{^ \(void\)"\\q \\u123z \\x \\U \\U123 \\U12345 \\u123 \\xyzzy \\777 \\U"$}}
+ //
+ // (void)"\q \u123z \x \U \U123 \U12345 \u123 \xyzzy \777 \U"
+ // CHECK: {{^ \^~$}}
+ // CHECK: {{^ \^~~~~$}}
+ // CHECK: {{^ \^~$}}
+ // CHECK: {{^ \^~$}}
+ // CHECK: {{^ \^~~~~$}}
+ // CHECK: {{^ \^~~~~~~$}}
+ // CHECK: {{^ \^~~~~$}}
+ // CHECK: {{^ \^~$}}
+ // CHECK: {{^ \^~~~$}}
+ // CHECK: {{^ \^~$}}
+
+ "123 \x \z";
+ // CHECK: {{^ "123 \\x \\z";$}}
+ //
+ // "123 \x \z";
+ // CHECK: {{^ \^~$}}
+ // CHECK: {{^ \^~$}}
+}
diff --git a/test/Misc/ast-dump-stmt.c b/test/Misc/ast-dump-stmt.c
new file mode 100644
index 000000000000..d7fdce8d593c
--- /dev/null
+++ b/test/Misc/ast-dump-stmt.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+int TestLocation = 0;
+// CHECK: Dumping TestLocation
+// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <{{.*}}:3:20> 'int' 0
+
+int TestIndent = 1 + (1);
+// CHECK: Dumping TestIndent
+// CHECK-NEXT: {{\(BinaryOperator[^()]*$}}
+// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)$}}
+// CHECK-NEXT: {{^ \(ParenExpr.*0[^()]*$}}
+// CHECK-NEXT: {{^ \(IntegerLiteral.*0[^()]*\)\)\)$}}
+
+void TestDeclStmt() {
+ int x = 0;
+ int y, z;
+}
+// CHECK: Dumping TestDeclStmt
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: int x =
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: int y
+// CHECK-NEXT: int z
+
+int TestOpaqueValueExpr = 0 ?: 1;
+// CHECK: Dumping TestOpaqueValueExpr
+// CHECK-NEXT: BinaryConditionalOperator
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: OpaqueValueExpr
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: OpaqueValueExpr
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: IntegerLiteral
diff --git a/test/Misc/ast-dump-stmt.m b/test/Misc/ast-dump-stmt.m
new file mode 100644
index 000000000000..8dfee74ab544
--- /dev/null
+++ b/test/Misc/ast-dump-stmt.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+void TestBlockExpr(int x) {
+ ^{ x; };
+}
+// CHECK: Dumping TestBlockExpr
+// CHECK: BlockExpr{{.*}} decl=
+// CHECK-NEXT: capture ParmVar
+// CHECK-NEXT: CompoundStmt
+
+void TestExprWithCleanup(int x) {
+ ^{ x; };
+}
+// CHECK: Dumping TestExprWithCleanup
+// CHECK: ExprWithCleanups
+// CHECK-NEXT: cleanup Block
+// CHECK-NEXT: BlockExpr
+
+@interface A
+@end
+
+void TestObjCAtCatchStmt() {
+ @try {
+ } @catch(A *a) {
+ } @catch(...) {
+ } @finally {
+ }
+}
+// CHECK: Dumping TestObjCAtCatchStmt
+// CHECK: ObjCAtTryStmt
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch parm = "A *a"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ObjCAtFinallyStmt
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index de1ee76ed1be..5faddb65f6e6 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s -strict-whitespace
#define M1(x) x
#define M2 1;
void foo() {
M1(
M2);
- // CHECK: :7:{{[0-9]+}}: warning: expression result unused
- // CHECK: :4:{{[0-9]+}}: note: expanded from macro 'M2'
- // CHECK: :3:{{[0-9]+}}: note: expanded from macro 'M1'
+ // CHECK: {{.*}}:7:{{[0-9]+}}: warning: expression result unused
+ // CHECK: {{.*}}:4:{{[0-9]+}}: note: expanded from macro 'M2'
+ // CHECK: {{.*}}:3:{{[0-9]+}}: note: expanded from macro 'M1'
}
#define A 1
@@ -15,10 +15,10 @@ void foo() {
#define C B
void bar() {
C;
- // CHECK: :17:3: warning: expression result unused
- // CHECK: :15:11: note: expanded from macro 'C'
- // CHECK: :14:11: note: expanded from macro 'B'
- // CHECK: :13:11: note: expanded from macro 'A'
+ // CHECK: {{.*}}:17:3: warning: expression result unused
+ // CHECK: {{.*}}:15:11: note: expanded from macro 'C'
+ // CHECK: {{.*}}:14:11: note: expanded from macro 'B'
+ // CHECK: {{.*}}:13:11: note: expanded from macro 'A'
}
// rdar://7597492
@@ -40,12 +40,12 @@ void baz(char *Msg) {
#define macro_many_args3(x, y, z) macro_many_args2(x, y, z)
void test() {
- macro_args3(1);
+ macro_args3(11);
// CHECK: {{.*}}:43:15: warning: expression result unused
// Also check that the 'caret' printing agrees with the location here where
// its easy to FileCheck.
- // CHECK-NEXT: macro_args3(1);
- // CHECK-NEXT: ~~~~~~~~~~~~^~
+ // CHECK-NEXT: macro_args3(11);
+ // CHECK-NEXT: {{^ \^~}}
// CHECK: {{.*}}:36:36: note: expanded from macro 'macro_args3'
// CHECK: {{.*}}:35:36: note: expanded from macro 'macro_args2'
// CHECK: {{.*}}:34:24: note: expanded from macro 'macro_args1'
@@ -71,13 +71,13 @@ void test() {
macro_many_args3(
1,
- macro_args2(2),
+ macro_args2(22),
3);
// CHECK: {{.*}}:74:17: warning: expression result unused
// This caret location needs to be printed *inside* a different macro's
// arguments.
- // CHECK-NEXT: macro_args2(2),
- // CHECK-NEXT: ~~~~~~~~~~~~^~~
+ // CHECK-NEXT: macro_args2(22),
+ // CHECK-NEXT: {{^ \^~}}
// CHECK: {{.*}}:35:36: note: expanded from macro 'macro_args2'
// CHECK: {{.*}}:34:24: note: expanded from macro 'macro_args1'
// CHECK: {{.*}}:40:55: note: expanded from macro 'macro_many_args3'
@@ -90,10 +90,10 @@ void test() {
#define variadic_args3(x, y, ...) variadic_args2(x, y, __VA_ARGS__)
void test2() {
- variadic_args3(1, 2, 3, 4);
+ variadic_args3(1, 22, 3, 4);
// CHECK: {{.*}}:93:21: warning: expression result unused
- // CHECK-NEXT: variadic_args3(1, 2, 3, 4);
- // CHECK-NEXT: ~~~~~~~~~~~~~~~~~~^~~~~~~~
+ // CHECK-NEXT: variadic_args3(1, 22, 3, 4);
+ // CHECK-NEXT: {{^ \^~}}
// CHECK: {{.*}}:90:53: note: expanded from macro 'variadic_args3'
// CHECK: {{.*}}:89:50: note: expanded from macro 'variadic_args2'
// CHECK: {{.*}}:88:35: note: expanded from macro 'variadic_args1'
@@ -118,3 +118,48 @@ void test3() {
// CHECK: {{.*}}:104:70: note: expanded from macro 'variadic_pasting_args2a'
// CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
}
+
+#define BAD_CONDITIONAL_OPERATOR (2<3)?2:3
+int test4 = BAD_CONDITIONAL_OPERATOR+BAD_CONDITIONAL_OPERATOR;
+// CHECK: {{.*}}:122:39: note: expanded from macro 'BAD_CONDITIONAL_OPERATOR'
+// CHECK-NEXT: #define BAD_CONDITIONAL_OPERATOR (2<3)?2:3
+// CHECK-NEXT: {{^ \^}}
+// CHECK: {{.*}}:122:39: note: expanded from macro 'BAD_CONDITIONAL_OPERATOR'
+// CHECK-NEXT: #define BAD_CONDITIONAL_OPERATOR (2<3)?2:3
+// CHECK-NEXT: {{^ \^}}
+// CHECK: {{.*}}:122:39: note: expanded from macro 'BAD_CONDITIONAL_OPERATOR'
+// CHECK-NEXT: #define BAD_CONDITIONAL_OPERATOR (2<3)?2:3
+// CHECK-NEXT: {{^ ~~~~~\^~~~}}
+
+#define QMARK ?
+#define TWOL (2<
+#define X 1+TWOL 3) QMARK 4:5
+int x = X;
+// CHECK: {{.*}}:137:9: note: place parentheses around the '+' expression to silence this warning
+// CHECK-NEXT: int x = X;
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{.*}}:136:21: note: expanded from macro 'X'
+// CHECK-NEXT: #define X 1+TWOL 3) QMARK 4:5
+// CHECK-NEXT: {{^ ~~~~~~~~~ \^}}
+// CHECK-NEXT: {{.*}}:134:15: note: expanded from macro 'QMARK'
+// CHECK-NEXT: #define QMARK ?
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{.*}}:137:9: note: place parentheses around the '?:' expression to evaluate it first
+// CHECK-NEXT: int x = X;
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{.*}}:136:21: note: expanded from macro 'X'
+// CHECK-NEXT: #define X 1+TWOL 3) QMARK 4:5
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~}}
+
+#define ONEPLUS 1+
+#define Y ONEPLUS (2<3) QMARK 4:5
+int y = Y;
+// CHECK: {{.*}}:156:9: warning: operator '?:' has lower precedence than '+'; '+' will be evaluated first
+// CHECK-NEXT: int y = Y;
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{.*}}:155:25: note: expanded from macro 'Y'
+// CHECK-NEXT: #define Y ONEPLUS (2<3) QMARK 4:5
+// CHECK-NEXT: {{^ ~~~~~~~~~~~~~ \^}}
+// CHECK-NEXT: {{.*}}:134:15: note: expanded from macro 'QMARK'
+// CHECK-NEXT: #define QMARK ?
+// CHECK-NEXT: {{^ \^}}
diff --git a/test/Misc/diag-template-diffing-color.cpp b/test/Misc/diag-template-diffing-color.cpp
index 6903e848d3df..cfa1a681e1a6 100644
--- a/test/Misc/diag-template-diffing-color.cpp
+++ b/test/Misc/diag-template-diffing-color.cpp
@@ -17,3 +17,56 @@ foo<double> &B = A;
// TREE: non-const lvalue reference cannot bind to a value of unrelated type
// TREE: foo<
// TREE: [{{.}}[0;1;36mdouble{{.}}[0m{{.}}[1m != {{.}}[0;1;36mint{{.}}[0m{{.}}[1m]>{{.}}[0m
+
+template<typename> class vector {};
+
+void set15(vector<const vector<int> >) {}
+void test15() {
+ set15(vector<const vector<const int> >());
+}
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<const vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}int>>' to 'vector<const vector<int>>' for 1st argument
+// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE: vector<
+// TREE: const vector<
+// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{.}}[0m] int>>
+
+void set16(vector<vector<int> >) {}
+void test16() {
+ set16(vector<const vector<int> >());
+}
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<vector<[...]>>' for 1st argument
+// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE: vector<
+// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{ ?.}}[0m]{{ ?}}vector<
+// TREE: [...]>>
+
+void set17(vector<const vector<int> >) {}
+void test17() {
+ set17(vector<vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<vector<[...]>>' to 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE: vector<
+// TREE: [{{.}}[0;1;36m(no qualifiers){{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36mconst{{.}}[0m] vector<
+// TREE: [...]>>
+
+void set18(vector<volatile vector<int> >) {}
+void test18() {
+ set18(vector<const vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<{{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: no matching function for call to 'set18'
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE: vector<
+// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36mvolatile{{.}}[0m] vector<
+// TREE: [...]>>
+
+void set19(vector<const volatile vector<int> >) {}
+void test19() {
+ set19(vector<const vector<int> >());
+}
+// CHECK: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<const {{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// TREE: vector<
+// TREE: [const != const {{.}}[0;1;36mvolatile{{.}}[0m] vector<
+// TREE: [...]>>
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 9addcc50aec6..2c044f877e8b 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -426,6 +426,372 @@ void test13() {
// CHECK-NOELIDE-TREE: &b13,
// CHECK-NOELIDE-TREE: [&d13 != (no argument)]>
+template<typename T> struct s14 {};
+template<typename T> using a14 = s14<T>;
+typedef a14<int> b14;
+template<typename T> using c14 = b14;
+int f14(c14<int>);
+int k14 = f14(a14<char>());
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f14'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'a14<char>' to 'a14<int>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f14'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'a14<char>' to 'a14<int>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'f14'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: a14<
+// CHECK-ELIDE-TREE: [char != int]>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f14'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: a14<
+// CHECK-NOELIDE-TREE: [char != int]>
+
+void set15(vector<vector<int>>) {}
+void test15() {
+ set15(vector<vector<int>>());
+}
+// CHECK-ELIDE-NOTREE-NOT: set15
+// CHECK-NOELIDE-NOTREE-NOT: set15
+// CHECK-ELIDE-TREE-NOT: set15
+// CHECK-NOELIDE-TREE-NOT: set15
+// no error here
+
+void set16(vector<const vector<int>>) {}
+void test16() {
+ set16(vector<const vector<const int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set16'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<const int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set16'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<const int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set16'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: const vector<
+// CHECK-ELIDE-TREE: [const != (no qualifiers)] int>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set16'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: const vector<
+// CHECK-NOELIDE-TREE: [const != (no qualifiers)] int>>
+
+void set17(vector<vector<int>>) {}
+void test17() {
+ set17(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set17'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set17'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<int>>' to 'vector<vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set17'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [const != (no qualifiers)] vector<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set17'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [const != (no qualifiers)] vector<
+// CHECK-NOELIDE-TREE: int>>
+
+void set18(vector<const vector<int>>) {}
+void test18() {
+ set18(vector<vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set18'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<vector<[...]>>' to 'vector<const vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set18'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<vector<int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set18'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [(no qualifiers) != const] vector<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set18'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [(no qualifiers) != const] vector<
+// CHECK-NOELIDE-TREE: int>>
+
+void set19(vector<volatile vector<int>>) {}
+void test19() {
+ set19(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set19'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<volatile vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set19'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<int>>' to 'vector<volatile vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set19'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [const != volatile] vector<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set19'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [const != volatile] vector<
+// CHECK-NOELIDE-TREE: int>>
+
+void set20(vector<const volatile vector<int>>) {}
+void test20() {
+ set20(vector<const vector<int>>());
+}
+// CHECK-ELIDE-NOTREE: no matching function for call to 'set20'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<const volatile vector<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'set20'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<const vector<int>>' to 'vector<const volatile vector<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'set20'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [const != const volatile] vector<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'set20'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [const != const volatile] vector<
+// CHECK-NOELIDE-TREE: int>>
+
+
+// Checks that volatile does not show up in diagnostics.
+template<typename T> struct S21 {};
+template<typename T> using U21 = volatile S21<T>;
+int f21(vector<const U21<int>>);
+int k21 = f21(vector<U21<int>>());
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f21'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<U21<[...]>>' to 'vector<const U21<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f21'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<U21<int>>' to 'vector<const U21<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'f21'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [(no qualifiers) != const] U21<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f21'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [(no qualifiers) != const] U21<
+// CHECK-NOELIDE-TREE: int>>
+
+// Checks that volatile does not show up in diagnostics.
+template<typename T> struct S22 {};
+template<typename T> using U22 = volatile S22<T>;
+int f22(vector<volatile const U22<int>>);
+int k22 = f22(vector<volatile U22<int>>());
+// CHECK-ELIDE-NOTREE: no matching function for call to 'f22'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<U22<[...]>>' to 'vector<const U22<[...]>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'f22'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'vector<U22<int>>' to 'vector<const U22<int>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'f22'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: vector<
+// CHECK-ELIDE-TREE: [(no qualifiers) != const] U22<
+// CHECK-ELIDE-TREE: [...]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'f22'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: vector<
+// CHECK-NOELIDE-TREE: [(no qualifiers) != const] U22<
+// CHECK-NOELIDE-TREE: int>>
+
+// Testing qualifiers and typedefs.
+template <class T> struct D23{};
+template <class T> using C23 = D23<T>;
+typedef const C23<int> B23;
+template<class ...T> using A23 = B23;
+
+void foo23(D23<A23<>> b) {}
+void test23() {
+ foo23(D23<D23<char>>());
+ foo23(C23<char>());
+}
+
+// CHECK-ELIDE-NOTREE: no matching function for call to 'foo23'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'D23<D23<char>>' to 'D23<const D23<int>>' for 1st argument
+// CHECK-ELIDE-NOTREE: no matching function for call to 'foo23'
+// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'D23<char>' to 'D23<A23<>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'foo23'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'D23<D23<char>>' to 'D23<const D23<int>>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no matching function for call to 'foo23'
+// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'D23<char>' to 'D23<A23<>>' for 1st argument
+// CHECK-ELIDE-TREE: no matching function for call to 'foo23'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: D23<
+// CHECK-ELIDE-TREE: [(no qualifiers) != const] D23<
+// CHECK-ELIDE-TREE: [char != int]>>
+// CHECK-ELIDE-TREE: no matching function for call to 'foo23'
+// CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: D23<
+// CHECK-ELIDE-TREE: [char != A23<>]>
+// CHECK-NOELIDE-TREE: no matching function for call to 'foo23'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: D23<
+// CHECK-NOELIDE-TREE: [(no qualifiers) != const] D23<
+// CHECK-NOELIDE-TREE: [char != int]>>
+// CHECK-NOELIDE-TREE: no matching function for call to 'foo23'
+// CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: D23<
+// CHECK-NOELIDE-TREE: [char != A23<>]>
+
+namespace PR14015 {
+template <unsigned N> class Foo1 {};
+template <unsigned N = 2> class Foo2 {};
+template <unsigned ...N> class Foo3 {};
+
+void Play1() {
+ Foo1<1> F1;
+ Foo1<2> F2, F3;
+ F2 = F1;
+ F1 = F2;
+ F2 = F3;
+ F3 = F2;
+}
+
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo1<1>' to 'Foo1<2>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo1<1>' to 'Foo1<2>' for 1st argument
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo1<2>' to 'Foo1<1>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo1<2>' to 'Foo1<1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo1<1>' to 'Foo1<2>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo1<1>' to 'Foo1<2>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo1<2>' to 'Foo1<1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo1<2>' to 'Foo1<1>' for 1st argument
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo1<
+// CHECK-ELIDE-TREE: [1 != 2]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo1<
+// CHECK-ELIDE-TREE: [1 != 2]>
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo1<
+// CHECK-ELIDE-TREE: [2 != 1]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo1<
+// CHECK-ELIDE-TREE: [2 != 1]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo1<
+// CHECK-NOELIDE-TREE: [1 != 2]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo1<
+// CHECK-NOELIDE-TREE: [1 != 2]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo1<
+// CHECK-NOELIDE-TREE: [2 != 1]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo1<
+// CHECK-NOELIDE-TREE: [2 != 1]>
+
+void Play2() {
+ Foo2<1> F1;
+ Foo2<> F2, F3;
+ F2 = F1;
+ F1 = F2;
+ F2 = F3;
+ F3 = F2;
+}
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo2<1>' to 'Foo2<2>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo2<1>' to 'Foo2<2>' for 1st argument
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'Foo2<1>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'Foo2<1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo2<1>' to 'Foo2<2>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo2<1>' to 'Foo2<2>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'Foo2<1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'Foo2<1>' for 1st argument
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo2<
+// CHECK-ELIDE-TREE: [1 != 2]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo2<
+// CHECK-ELIDE-TREE: [1 != 2]>
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo2<
+// CHECK-ELIDE-TREE: [(default) 2 != 1]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo2<
+// CHECK-ELIDE-TREE: [(default) 2 != 1]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo2<
+// CHECK-NOELIDE-TREE: [1 != 2]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo2<
+// CHECK-NOELIDE-TREE: [1 != 2]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo2<
+// CHECK-NOELIDE-TREE: [(default) 2 != 1]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo2<
+// CHECK-NOELIDE-TREE: [(default) 2 != 1]>
+
+void Play3() {
+ Foo3<1> F1;
+ Foo3<2, 1> F2, F3;
+ F2 = F1;
+ F1 = F2;
+ F2 = F3;
+ F3 = F2;
+}
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'Foo3<2, 1>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'Foo3<2, 1>' for 1st argument
+// CHECK-ELIDE-NOTREE: no viable overloaded '='
+// CHECK-ELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'Foo3<1, (no argument)>' for 1st argument
+// CHECK-ELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'Foo3<1, (no argument)>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'Foo3<2, 1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'Foo3<2, 1>' for 1st argument
+// CHECK-NOELIDE-NOTREE: no viable overloaded '='
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'Foo3<1, (no argument)>' for 1st argument
+// CHECK-NOELIDE-NOTREE: candidate function (the implicit move assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'Foo3<1, (no argument)>' for 1st argument
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo3<
+// CHECK-ELIDE-TREE: [1 != 2],
+// CHECK-ELIDE-TREE: [(no argument) != 1]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo3<
+// CHECK-ELIDE-TREE: [1 != 2],
+// CHECK-ELIDE-TREE: [(no argument) != 1]>
+// CHECK-ELIDE-TREE: no viable overloaded '='
+// CHECK-ELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo3<
+// CHECK-ELIDE-TREE: [2 != 1],
+// CHECK-ELIDE-TREE: [1 != (no argument)]>
+// CHECK-ELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-ELIDE-TREE: Foo3<
+// CHECK-ELIDE-TREE: [2 != 1],
+// CHECK-ELIDE-TREE: [1 != (no argument)]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo3<
+// CHECK-NOELIDE-TREE: [1 != 2],
+// CHECK-NOELIDE-TREE: [(no argument) != 1]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo3<
+// CHECK-NOELIDE-TREE: [1 != 2],
+// CHECK-NOELIDE-TREE: [(no argument) != 1]>
+// CHECK-NOELIDE-TREE: no viable overloaded '='
+// CHECK-NOELIDE-TREE: candidate function (the implicit copy assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo3<
+// CHECK-NOELIDE-TREE: [2 != 1],
+// CHECK-NOELIDE-TREE: [1 != (no argument)]>
+// CHECK-NOELIDE-TREE: candidate function (the implicit move assignment operator) not viable: no known conversion from argument type to parameter type for 1st argument
+// CHECK-NOELIDE-TREE: Foo3<
+// CHECK-NOELIDE-TREE: [2 != 1],
+// CHECK-NOELIDE-TREE: [1 != (no argument)]>
+}
+
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.
diff --git a/test/Misc/predefines.c b/test/Misc/predefines.c
index 87f676e89fc4..63944b03d8f9 100644
--- a/test/Misc/predefines.c
+++ b/test/Misc/predefines.c
@@ -1,4 +1,5 @@
/* RUN: %clang_cc1 -fsyntax-only -verify -std=c89 -ffreestanding -pedantic-errors %s
+ * expected-no-diagnostics
* rdar://6814950
*/
#include <stdint.h>
diff --git a/test/Misc/unnecessary-elipses.cpp b/test/Misc/unnecessary-elipses.cpp
new file mode 100644
index 000000000000..2ee725869b5c
--- /dev/null
+++ b/test/Misc/unnecessary-elipses.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -fmessage-length 80 %s 2>&1 | FileCheck -strict-whitespace %s
+
+int main() {
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+// CHECK: {{^ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";}}
+
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+// CHECK: {{^ ..."xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";}}
+
+"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ;
+// CHECK: {{^"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"...}}
+
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ;
+// CHECK: {{^ ..."xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"...}}
+} \ No newline at end of file
diff --git a/test/Misc/unprintable.c b/test/Misc/unprintable.c
index 860503e63c39..cd97131c8d1a 100644
--- a/test/Misc/unprintable.c
+++ b/test/Misc/unprintable.c
@@ -1,16 +1,39 @@
-// RUN: %clang_cc1 %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 %s -fmessage-length 40 2>&1 | FileCheck -strict-whitespace %s
int main() {
int i;
- if((i==/*👿*/1));
+ if((i==/*￾*/1));
-// CHECK: {{^ if\(\(i==/\*<U\+1F47F>\*/1\)\);}}
+// CHECK: {{^ if\(\(i==/\*<U\+FFFE>\*/1\)\);}}
-// CHECK: {{^ ~\^~~~~~~~~~~~~~~~}}
-// CHECK: {{^ ~ \^ ~}}
+// CHECK: {{^ ~\^~~~~~~~~~~~~~~}}
+// CHECK: {{^ ~ \^ ~}}
- /* 👿 */ "👿berhund";
+ (void)"Ê￾ô";
-// CHECK: {{^ /\* <U\+1F47F> \*/ "<U\+1F47F>berhund";}}
-// CHECK: {{^ \^~~~~~~~~~~~~~~~~~}}
-} \ No newline at end of file
+// CHECK: {{^ \(void\)"<CA><U\+FFFE><F4>";}}
+// CHECK: {{^ \^~~~}}
+
+  int n = 0;
+
+// CHECK: {{ int n = 0;}}
+// CHECK: {{^\^}}
+
+ "￾ \z";
+
+// CHECK: {{^ \.\.\.\\z";}}
+// CHECK: {{^ \^~}}
+
+
+ /* ￾ */ "￾berhund";
+
+// CHECK: {{^ /\* <U\+FFFE> \*/ "<U\+FFFE>berhund";}}
+// CHECK: {{^ \^~~~~~~~~~~~~~~~~}}
+
+
+// PR14292
+ "x°xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+// CHECK: {{^ "x<B0>}}
+// CHECK: {{^ \^}}
+
+}
diff --git a/test/Misc/warning-flags-enabled.c b/test/Misc/warning-flags-enabled.c
index 7ef5c94dbc8c..ba29e7ac51a1 100644
--- a/test/Misc/warning-flags-enabled.c
+++ b/test/Misc/warning-flags-enabled.c
@@ -25,3 +25,19 @@
// CHECK-NO-LEVELS-NOT: E
// CHECK-NO-LEVELS-NOT: F
// CHECK-NO-LEVELS: warn_objc_root_class_missing [-Wobjc-root-class]
+
+// Test if EnumConversion is a subgroup of -Wconversion.
+// RUN: diagtool show-enabled --no-levels -Wno-conversion -Wenum-conversion %s | FileCheck --check-prefix CHECK-ENUM-CONVERSION %s
+// RUN: diagtool show-enabled --no-levels %s | FileCheck --check-prefix CHECK-ENUM-CONVERSION %s
+// RUN: diagtool show-enabled --no-levels -Wno-conversion %s | FileCheck --check-prefix CHECK-NO-ENUM-CONVERSION %s
+//
+// CHECK-ENUM-CONVERSION: -Wenum-conversion
+// CHECK-NO-ENUM-CONVERSION-NOT: -Wenum-conversion
+
+// Test if -Wshift-op-parentheses is a subgroup of -Wparentheses
+// RUN: diagtool show-enabled --no-levels -Wno-parentheses -Wshift-op-parentheses %s | FileCheck --check-prefix CHECK-SHIFT-OP-PARENTHESES %s
+// RUN: diagtool show-enabled --no-levels %s | FileCheck --check-prefix CHECK-SHIFT-OP-PARENTHESES %s
+// RUN: diagtool show-enabled --no-levels -Wno-parentheses %s | FileCheck --check-prefix CHECK-NO-SHIFT-OP-PARENTHESES %s
+//
+// CHECK-SHIFT-OP-PARENTHESES: -Wshift-op-parentheses
+// CHECK-NO-SHIFT-OP-PARENTHESES-NOT: -Wshift-op-parentheses
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 06c70eb57c59..c3f14bce316d 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (159):
+CHECK: Warnings without flags (148):
CHECK-NEXT: ext_delete_void_ptr_operand
CHECK-NEXT: ext_enum_friend
CHECK-NEXT: ext_expected_semi_decl_list
@@ -30,8 +30,6 @@ CHECK-NEXT: ext_new_paren_array_nonconst
CHECK-NEXT: ext_plain_complex
CHECK-NEXT: ext_pp_macro_redef
CHECK-NEXT: ext_template_arg_extra_parens
-CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers
-CHECK-NEXT: ext_typecheck_comparison_of_distinct_pointers_nonstandard
CHECK-NEXT: ext_typecheck_comparison_of_pointer_integer
CHECK-NEXT: ext_typecheck_cond_incompatible_operands
CHECK-NEXT: ext_typecheck_cond_incompatible_operands_nonstandard
@@ -59,10 +57,7 @@ CHECK-NEXT: warn_call_to_pure_virtual_member_function_from_ctor_dtor
CHECK-NEXT: warn_call_wrong_number_of_arguments
CHECK-NEXT: warn_case_empty_range
CHECK-NEXT: warn_char_constant_too_large
-CHECK-NEXT: warn_cmdline_missing_macro_defs
CHECK-NEXT: warn_collection_expr_type
-CHECK-NEXT: warn_conflicting_param_types
-CHECK-NEXT: warn_conflicting_ret_types
CHECK-NEXT: warn_conflicting_variadic
CHECK-NEXT: warn_conv_to_base_not_used
CHECK-NEXT: warn_conv_to_self_not_used
@@ -71,9 +66,6 @@ CHECK-NEXT: warn_delete_array_type
CHECK-NEXT: warn_double_const_requires_fp64
CHECK-NEXT: warn_drv_assuming_mfloat_abi_is
CHECK-NEXT: warn_drv_clang_unsupported
-CHECK-NEXT: warn_drv_not_using_clang_arch
-CHECK-NEXT: warn_drv_not_using_clang_cpp
-CHECK-NEXT: warn_drv_not_using_clang_cxx
CHECK-NEXT: warn_drv_objc_gc_unsupported
CHECK-NEXT: warn_drv_pch_not_first_include
CHECK-NEXT: warn_dup_category_def
@@ -101,7 +93,6 @@ CHECK-NEXT: warn_integer_too_large_for_signed
CHECK-NEXT: warn_invalid_asm_cast_lvalue
CHECK-NEXT: warn_many_braces_around_scalar_init
CHECK-NEXT: warn_maynot_respond
-CHECK-NEXT: warn_member_extra_qualification
CHECK-NEXT: warn_method_param_redefinition
CHECK-NEXT: warn_mismatched_exception_spec
CHECK-NEXT: warn_missing_case_for_condition
@@ -134,7 +125,6 @@ CHECK-NEXT: warn_pragma_expected_rparen
CHECK-NEXT: warn_pragma_extra_tokens_at_eol
CHECK-NEXT: warn_pragma_ms_struct
CHECK-NEXT: warn_pragma_options_align_reset_failed
-CHECK-NEXT: warn_pragma_options_align_unsupported_option
CHECK-NEXT: warn_pragma_options_expected_align
CHECK-NEXT: warn_pragma_pack_invalid_action
CHECK-NEXT: warn_pragma_pack_invalid_alignment
@@ -149,7 +139,6 @@ 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_printf_asterisk_missing_arg
CHECK-NEXT: warn_property_attr_mismatch
CHECK-NEXT: warn_property_attribute
CHECK-NEXT: warn_property_getter_owning_mismatch
@@ -181,4 +170,4 @@ CHECK-NEXT: warn_weak_import
The list of warnings in -Wpedantic should NEVER grow.
-CHECK: Number in -Wpedantic (not covered by other -W flags): 39
+CHECK: Number in -Wpedantic (not covered by other -W flags): 29
diff --git a/test/Misc/wrong-encoding.c b/test/Misc/wrong-encoding.c
index bd1cf3dc02ae..c48402d2a132 100644
--- a/test/Misc/wrong-encoding.c
+++ b/test/Misc/wrong-encoding.c
@@ -1,16 +1,39 @@
-// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value %s 2>&1 | FileCheck -strict-whitespace %s
+// REQUIRES: asserts
void foo() {
"§Ã"; // ø
// CHECK: {{^ "<A7><C3>"; // <F8>}}
-// CHECK: {{^ \^}}
+// CHECK: {{^ \^~~~~~~}}
/* þ« */ const char *d = "¥";
// CHECK: {{^ /\* <FE><AB> \*/ const char \*d = "<A5>";}}
-// CHECK: {{^ \^}}
+// CHECK: {{^ \^~~~}}
-// CHECK: {{^ "<A7><C3>"; // <F8>}}
-// CHECK: {{^ \^~~~~~~~~~}}
+ "xxé¿¿¿d";
+// CHECK: {{^ "xx<U\+9FFF><BF>d";}}
+// CHECK: {{^ \^~~~}}
+
+ "xxé¿bcd";
+// CHECK: {{^ "xx<E9><BF>bcd";}}
+// CHECK: {{^ \^~~~~~~~}}
+
+ "xxéabcd";
+// CHECK: {{^ "xx<E9>abcd";}}
+// CHECK: {{^ \^~~~}}
+
+ "xxé¿é¿d";
+// CHECK: {{^ "xx<E9><BF><E9><BF>d";}}
+// CHECK: {{^ \^~~~~~~~~~~~~~~}}
+
+ "xxé¿xxxxxxxxxxxxxxxxxxxxxé¿xx";
+// CHECK: {{^ "xx<E9><BF>xxxxxxxxxxxxxxxxxxxxx<E9><BF>xx";}}
+// CHECK: {{^ \^~~~~~~~ ~~~~~~~~}}
+
+ "?kÍ›S¥ÇØg7†, 2,Díu„†*É,pûäÚ&”‰(K§:Ñ'1á‹ÎjOÅ°<:";
+
+ "xé¿xé¿xé¿xé¿xé¿xé¿xé¿xé¿xé¿xé¿xé¿xé¿x";
}
+// CHECK-NOT:Assertion
diff --git a/test/Misc/wrong-encoding2.c b/test/Misc/wrong-encoding2.c
new file mode 100644
index 000000000000..43a0f4e900ed
--- /dev/null
+++ b/test/Misc/wrong-encoding2.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -fmessage-length 100 %s 2>&1 | FileCheck -strict-whitespace %s
+// REQUIRES: asserts
+
+int main() {
+ "É#x#p )6Ò)ѽŠ$ûž>U êhÑüÃö|Ÿ থϻgŸY|`?ò;;Æ¿VjÇ\\ù€‡ûݪW9úТ:ÌŠO EøÛy?SKªy¦¹‡Øài&n";
+}
+
+// CHECK-NOT:Assertion
diff --git a/test/Modules/Inputs/Modified/A.h b/test/Modules/Inputs/Modified/A.h
new file mode 100644
index 000000000000..ff833c7520f0
--- /dev/null
+++ b/test/Modules/Inputs/Modified/A.h
@@ -0,0 +1 @@
+int getA();
diff --git a/test/Modules/Inputs/Modified/B.h b/test/Modules/Inputs/Modified/B.h
new file mode 100644
index 000000000000..d1c8bb5e8e15
--- /dev/null
+++ b/test/Modules/Inputs/Modified/B.h
@@ -0,0 +1,2 @@
+#include "A.h"
+int getB();
diff --git a/test/Modules/Inputs/Modified/module.map b/test/Modules/Inputs/Modified/module.map
new file mode 100644
index 000000000000..d9aed01430c4
--- /dev/null
+++ b/test/Modules/Inputs/Modified/module.map
@@ -0,0 +1,2 @@
+module A { header "A.h" }
+module B { header "B.h" }
diff --git a/test/Modules/Inputs/Module.framework/Headers/Module.h b/test/Modules/Inputs/Module.framework/Headers/Module.h
index f8949848bd4c..3d2476b20431 100644
--- a/test/Modules/Inputs/Module.framework/Headers/Module.h
+++ b/test/Modules/Inputs/Module.framework/Headers/Module.h
@@ -23,4 +23,6 @@ const char *getModuleVersion(void);
#include <Module/Sub.h>
#include <Module/Buried/Treasure.h>
+__asm("foo");
+
#endif // MODULE_H
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module.map b/test/Modules/Inputs/NoUmbrella.framework/module.map
index 4a4d9702c5ff..03a8a17e68c0 100644
--- a/test/Modules/Inputs/NoUmbrella.framework/module.map
+++ b/test/Modules/Inputs/NoUmbrella.framework/module.map
@@ -2,8 +2,5 @@ framework module NoUmbrella [system] {
umbrella "Headers"
module * { }
- module unavailable {
- requires unavailable
- header "Boom.h"
- }
+ exclude header "Boom.h"
}
diff --git a/test/Modules/Inputs/NotAModule.framework/Headers/NotAModule.h b/test/Modules/Inputs/NotAModule.framework/Headers/NotAModule.h
new file mode 100644
index 000000000000..263979212bbd
--- /dev/null
+++ b/test/Modules/Inputs/NotAModule.framework/Headers/NotAModule.h
@@ -0,0 +1,2 @@
+extern int not_a_module;
+
diff --git a/test/Modules/Inputs/lookup_right.hpp b/test/Modules/Inputs/lookup_right.hpp
index 884534747f69..b2611a1380cc 100644
--- a/test/Modules/Inputs/lookup_right.hpp
+++ b/test/Modules/Inputs/lookup_right.hpp
@@ -1 +1,2 @@
float *f0(float*);
+// expected-no-diagnostics
diff --git a/test/Modules/Inputs/macros.h b/test/Modules/Inputs/macros.h
index 4f535563ad27..27f43c0626ec 100644
--- a/test/Modules/Inputs/macros.h
+++ b/test/Modules/Inputs/macros.h
@@ -8,3 +8,12 @@
#__private_macro MODULE
int (INTEGER);
+
+#if !__building_module(macros)
+# error Can't include this header without building the 'macros' module.
+#endif
+
+#ifdef __MODULE__
+extern int __MODULE__;
+#endif
+
diff --git a/test/Modules/Inputs/macros_left.h b/test/Modules/Inputs/macros_left.h
new file mode 100644
index 000000000000..cd0569389189
--- /dev/null
+++ b/test/Modules/Inputs/macros_left.h
@@ -0,0 +1,14 @@
+@__experimental_modules_import macros_top;
+#define LEFT unsigned long
+
+#undef TOP_LEFT_UNDEF
+
+
+
+
+#define LEFT_RIGHT_IDENTICAL int
+
+#define LEFT_RIGHT_DIFFERENT2 float
+#define LEFT_RIGHT_DIFFERENT3 float
+
+#define LEFT_RIGHT_DIFFERENT float
diff --git a/test/Modules/Inputs/macros_other.h b/test/Modules/Inputs/macros_other.h
new file mode 100644
index 000000000000..ea686bfc558a
--- /dev/null
+++ b/test/Modules/Inputs/macros_other.h
@@ -0,0 +1 @@
+#define OTHER_INTEGER int
diff --git a/test/Modules/Inputs/macros_right.h b/test/Modules/Inputs/macros_right.h
new file mode 100644
index 000000000000..e16a64b50ad3
--- /dev/null
+++ b/test/Modules/Inputs/macros_right.h
@@ -0,0 +1,17 @@
+@__experimental_modules_import macros_top;
+#define RIGHT unsigned short
+
+
+
+
+
+
+
+
+#define LEFT_RIGHT_IDENTICAL int
+#define LEFT_RIGHT_DIFFERENT int
+#define LEFT_RIGHT_DIFFERENT2 int
+#define LEFT_RIGHT_DIFFERENT3 int
+
+#undef TOP_RIGHT_REDEF
+#define TOP_RIGHT_REDEF float
diff --git a/test/Modules/Inputs/macros_right_undef.h b/test/Modules/Inputs/macros_right_undef.h
new file mode 100644
index 000000000000..49473e36f0cb
--- /dev/null
+++ b/test/Modules/Inputs/macros_right_undef.h
@@ -0,0 +1 @@
+#undef TOP_RIGHT_UNDEF
diff --git a/test/Modules/Inputs/macros_top.h b/test/Modules/Inputs/macros_top.h
new file mode 100644
index 000000000000..9c3f3c071fd0
--- /dev/null
+++ b/test/Modules/Inputs/macros_top.h
@@ -0,0 +1,16 @@
+#define TOP unsigned int
+
+#define TOP_LEFT_UNDEF 1
+
+
+
+
+
+
+
+
+
+#define TOP_RIGHT_REDEF int
+
+#define TOP_RIGHT_UNDEF int
+
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 79056cb51800..032241d6aa1e 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -18,6 +18,20 @@ module lookup_left_cxx { header "lookup_left.hpp" }
module lookup_right_cxx { header "lookup_right.hpp" }
module module_private_left { header "module_private_left.h" }
module module_private_right { header "module_private_right.h" }
+module macros_top {
+ header "macros_top.h"
+}
+module macros_left {
+ header "macros_left.h"
+ export *
+}
+module macros_right {
+ header "macros_right.h"
+ export *
+ explicit module undef {
+ header "macros_right_undef.h"
+ }
+}
module macros { header "macros.h" }
module category_top { header "category_top.h" }
module category_left {
@@ -78,6 +92,18 @@ module namespaces_right {
header "namespaces-right.h"
export *
}
+module templates_top {
+ header "templates-top.h"
+ export *
+}
+module templates_left {
+ header "templates-left.h"
+ export *
+}
+module templates_right {
+ header "templates-right.h"
+ export *
+}
module MethodPoolA {
header "MethodPoolA.h"
}
@@ -87,3 +113,7 @@ module MethodPoolB {
module import_decl {
header "import-decl.h"
}
+
+framework module * {
+ exclude NotAModule
+}
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h
new file mode 100644
index 000000000000..e8a3e6340d51
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/1.h
@@ -0,0 +1 @@
+int one;
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h
new file mode 100644
index 000000000000..91522aa1a962
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/a-extras.h
@@ -0,0 +1 @@
+int extra_a;
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/decltype.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/decltype.h
new file mode 100644
index 000000000000..506a217d1b98
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/decltype.h
@@ -0,0 +1,2 @@
+int decltype_val;
+
diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h
index 40a9404abf29..cfea7dc87da5 100644
--- a/test/Modules/Inputs/redecl-merge-bottom.h
+++ b/test/Modules/Inputs/redecl-merge-bottom.h
@@ -18,11 +18,3 @@ struct S3;
void refers_to_C4(C4*);
-#ifdef __cplusplus
-template<typename T> class Vector;
-
-template<typename T> class Vector;
-
-template<typename T> class Vector;
-#endif
-
diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h
index b3a7ba83c1af..5e6d2e512b00 100644
--- a/test/Modules/Inputs/redecl-merge-left.h
+++ b/test/Modules/Inputs/redecl-merge-left.h
@@ -60,7 +60,7 @@ typedef int T1;
typedef float T2;
int func0(int);
-int func1(int);
+int func1(int x) { return x; }
int func2(int);
@@ -78,12 +78,6 @@ extern float var2;
extern double var3;
-#ifdef __cplusplus
-template<typename T> class Vector;
-
-template<typename T> class Vector;
-#endif
-
// Make sure this doesn't introduce an ambiguity-creating 'id' at the
// top level.
typedef void funcptr_with_id(int id);
diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h
index de7aa08cfb2b..20223083c31a 100644
--- a/test/Modules/Inputs/redecl-merge-right.h
+++ b/test/Modules/Inputs/redecl-merge-right.h
@@ -65,7 +65,7 @@ typedef double T2;
int func0(int);
int func1(int);
int func1(int);
-int func1(int);
+int func1(int x) { return x; }
int func1(int);
static int func2(int);
@@ -78,13 +78,6 @@ extern int var2;
static double var3;
-#ifdef __cplusplus
-template<typename T> class Vector {
-public:
- void push_back(const T&);
-};
-#endif
-
int ONE;
@__experimental_modules_import redecl_merge_top.Explicit;
const int one = ONE;
diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h
index 519254ca2213..690e6df1c9e2 100644
--- a/test/Modules/Inputs/redecl-merge-top.h
+++ b/test/Modules/Inputs/redecl-merge-top.h
@@ -15,6 +15,4 @@ struct S1;
struct S2;
struct S2;
-#ifdef __cplusplus
-template<typename T> class Vector;
-#endif
+int func1(int);
diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h
new file mode 100644
index 000000000000..57a8c85bf602
--- /dev/null
+++ b/test/Modules/Inputs/templates-left.h
@@ -0,0 +1,29 @@
+@__experimental_modules_import templates_top;
+
+template<typename T> class Vector;
+
+template<typename T> class Vector;
+
+template<typename T> class List;
+template<> class List<bool> {
+public:
+ void push_back(int);
+};
+namespace N {
+ template<typename T> class Set;
+}
+namespace N {
+ template<typename T> class Set {
+ public:
+ void insert(T);
+ };
+}
+
+template <typename T>
+void pendingInstantiationEmit(T) {}
+void triggerPendingInstantiation() {
+ pendingInstantiationEmit(12);
+ pendingInstantiationEmit(42.);
+}
+
+void redeclDefinitionEmit(){}
diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h
new file mode 100644
index 000000000000..4ef4a32e8e27
--- /dev/null
+++ b/test/Modules/Inputs/templates-right.h
@@ -0,0 +1,27 @@
+@__experimental_modules_import templates_top;
+
+template<typename T> class Vector {
+public:
+ void push_back(const T&);
+};
+
+template<typename T> class List;
+template<> class List<bool> {
+public:
+ void push_back(int);
+};
+
+namespace N {
+ template<typename T> class Set {
+ public:
+ void insert(T);
+ };
+}
+
+template <typename T>
+void pendingInstantiationEmit(T) {}
+void triggerPendingInstantiationToo() {
+ pendingInstantiationEmit(12);
+}
+
+void redeclDefinitionEmit(){}
diff --git a/test/Modules/Inputs/templates-top.h b/test/Modules/Inputs/templates-top.h
new file mode 100644
index 000000000000..5985ee8820d6
--- /dev/null
+++ b/test/Modules/Inputs/templates-top.h
@@ -0,0 +1,17 @@
+template<typename T> class Vector;
+
+template<typename T> class List {
+public:
+ void push_back(T);
+};
+
+namespace A {
+ class Y {
+ template <typename T> friend class WhereAmI;
+ };
+}
+
+template <typename T> class A::WhereAmI {
+public:
+ static void func() {}
+};
diff --git a/test/Modules/compiler_builtins.m b/test/Modules/compiler_builtins.m
index de6f57b5f285..dfa46c8a34f5 100644
--- a/test/Modules/compiler_builtins.m
+++ b/test/Modules/compiler_builtins.m
@@ -1,5 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang -fsyntax-only -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
+// RUN: %clang -fsyntax-only -std=c99 -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
+// expected-no-diagnostics
#ifdef __SSE__
@__experimental_modules_import _Builtin_intrinsics.intel.sse;
diff --git a/test/Modules/direct-module-import.m b/test/Modules/direct-module-import.m
new file mode 100644
index 000000000000..317d7aea164b
--- /dev/null
+++ b/test/Modules/direct-module-import.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -fmodules -F %S/Inputs -include Module/Module.h %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: call i8* @getModuleVersion
+const char* getVer(void) {
+ return getModuleVersion();
+}
diff --git a/test/Modules/header-import.m b/test/Modules/header-import.m
index 5444854a62bf..49549d0c671a 100644
--- a/test/Modules/header-import.m
+++ b/test/Modules/header-import.m
@@ -1,5 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// expected-no-diagnostics
#import "point.h"
@__experimental_modules_import Module;
diff --git a/test/Modules/import-decl.cpp b/test/Modules/import-decl.cpp
index 76966934acc8..0f05f92708bc 100644
--- a/test/Modules/import-decl.cpp
+++ b/test/Modules/import-decl.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang -fmodule-cache-path %t -fmodules -x objective-c -I %S/Inputs -emit-ast -o %t.ast %s
-// RUN: %clang -cc1 -ast-print -x ast - < %t.ast | FileCheck %s
+// RUN: %clang_cc1 -ast-print -x ast - < %t.ast | FileCheck %s
@__experimental_modules_import import_decl;
// CHECK: struct T
diff --git a/test/Modules/inferred-frameworks.m b/test/Modules/inferred-frameworks.m
new file mode 100644
index 000000000000..916c900b6457
--- /dev/null
+++ b/test/Modules/inferred-frameworks.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+
+#include <NotAModule/NotAModule.h>
+
+@__experimental_modules_import NotAModule; // expected-error{{module 'NotAModule' not found}}
+
+
diff --git a/test/Modules/inferred-submodules.m b/test/Modules/inferred-submodules.m
index bee1cec98e44..8c61bc081c2d 100644
--- a/test/Modules/inferred-submodules.m
+++ b/test/Modules/inferred-submodules.m
@@ -1,5 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// expected-no-diagnostics
@__experimental_modules_import Module.Sub;
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
index 83e1c66a1017..8db3915f24a9 100644
--- a/test/Modules/macros.c
+++ b/test/Modules/macros.c
@@ -1,8 +1,20 @@
// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=macros_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=macros_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=macros_right %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=macros %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -verify -fmodule-cache-path %t %s
// RUN: %clang_cc1 -E -fmodules -x objective-c -fmodule-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.
+
+// FIXME: expected-note{{previous definition is here}}
+// expected-note{{other definition of 'LEFT_RIGHT_DIFFERENT'}}
+// expected-note{{expanding this definition of 'TOP_RIGHT_REDEF'}}
+// FIXME: expected-note{{previous definition is here}} \
+// expected-note{{expanding this definition of 'LEFT_RIGHT_DIFFERENT'}}
+
+// expected-note{{other definition of 'TOP_RIGHT_REDEF'}}
@__experimental_modules_import macros;
@@ -27,4 +39,99 @@ DOUBLE *dp = &d;
void f() {
// CHECK-PREPROCESSED: int i = INTEGER;
int i = INTEGER; // the value was exported, the macro was not.
+ i += macros; // expanded from __MODULE__ within the 'macros' module.
+}
+
+#ifdef __MODULE__
+# error Not building a module!
+#endif
+
+#if __building_module(macros)
+# error Not building a module
+#endif
+
+// None of the modules we depend on have been imported, and therefore
+// their macros should not be visible.
+#ifdef LEFT
+# error LEFT should not be visible
+#endif
+
+#ifdef RIGHT
+# error RIGHT should not be visible
+#endif
+
+#ifdef TOP
+# error TOP should not be visible
+#endif
+
+// Import left module (which also imports top)
+@__experimental_modules_import macros_left;
+
+#ifndef LEFT
+# error LEFT should be visible
+#endif
+
+#ifdef RIGHT
+# error RIGHT should not be visible
+#endif
+
+#ifndef TOP
+# error TOP should be visible
+#endif
+
+#ifdef TOP_LEFT_UNDEF
+# error TOP_LEFT_UNDEF should not be visible
+#endif
+
+void test1() {
+ int i;
+ TOP_RIGHT_REDEF *ip = &i;
}
+
+#define LEFT_RIGHT_DIFFERENT2 double // FIXME: expected-warning{{'LEFT_RIGHT_DIFFERENT2' macro redefined}}
+
+// Import right module (which also imports top)
+@__experimental_modules_import macros_right;
+
+#undef LEFT_RIGHT_DIFFERENT3
+
+#ifndef LEFT
+# error LEFT should be visible
+#endif
+
+#ifndef RIGHT
+# error RIGHT should be visible
+#endif
+
+#ifndef TOP
+# error TOP should be visible
+#endif
+
+void test2() {
+ int i;
+ float f;
+ double d;
+ TOP_RIGHT_REDEF *ip = &i; // expected-warning{{ambiguous expansion of macro 'TOP_RIGHT_REDEF'}}
+
+ LEFT_RIGHT_IDENTICAL *ip2 = &i;
+ LEFT_RIGHT_DIFFERENT *fp = &f; // expected-warning{{ambiguous expansion of macro 'LEFT_RIGHT_DIFFERENT'}}
+ LEFT_RIGHT_DIFFERENT2 *dp = &d;
+ int LEFT_RIGHT_DIFFERENT3;
+}
+
+#define LEFT_RIGHT_DIFFERENT double // FIXME: expected-warning{{'LEFT_RIGHT_DIFFERENT' macro redefined}}
+
+void test3() {
+ double d;
+ LEFT_RIGHT_DIFFERENT *dp = &d; // okay
+}
+
+#ifndef TOP_RIGHT_UNDEF
+# error TOP_RIGHT_UNDEF should still be defined
+#endif
+
+@__experimental_modules_import macros_right.undef;
+
+#ifdef TOP_RIGHT_UNDEF
+# error TOP_RIGHT_UNDEF should not be defined
+#endif
diff --git a/test/Modules/modify-module.m b/test/Modules/modify-module.m
new file mode 100644
index 000000000000..b630ac105874
--- /dev/null
+++ b/test/Modules/modify-module.m
@@ -0,0 +1,23 @@
+// Test that if we modify one of the input files used to form a
+// header, that module and dependent modules get rebuilt.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/include
+// RUN: cp %S/Inputs/Modified/A.h %t/include
+// RUN: cp %S/Inputs/Modified/B.h %t/include
+// RUN: cp %S/Inputs/Modified/module.map %t/include
+// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
+// expected-no-diagnostics
+// RUN: touch %t/include/B.h
+// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
+// RUN: echo 'int getA(); int getA2();' > %t/include/A.h
+// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
+
+@__experimental_modules_import B;
+
+int getValue() { return getA() + getB(); }
+
+
+
+
+
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
index 246dcaf80e24..31a3410a03f8 100644
--- a/test/Modules/module-private.cpp
+++ b/test/Modules/module-private.cpp
@@ -12,9 +12,12 @@ void test() {
}
int test_broken() {
- HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}
+ HiddenStruct hidden; // \
+ // expected-error{{must use 'struct' tag to refer to type 'HiddenStruct' in this scope}} \
+ // expected-error{{definition of 'struct HiddenStruct' must be imported}}
+ // expected-note@3 {{previous definition is here}}
- Integer i; // expected-error{{use of undeclared identifier 'Integer'}}
+ Integer i; // expected-error{{unknown type name 'Integer'}}
int *ip = 0;
f1(ip); // expected-error{{use of undeclared identifier 'f1'}}
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 7cd448235d81..07ca5ed9330a 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -33,3 +33,13 @@ int testNestedUmbrellaBFail() {
int testNestedUmbrellaB() {
return nested_umbrella_b;
}
+
+@__experimental_modules_import nested_umbrella.a_extras;
+
+@__experimental_modules_import nested_umbrella._1;
+
+@__experimental_modules_import nested_umbrella.decltype_;
+
+int testSanitizedName() {
+ return extra_a + one + decltype_val;
+}
diff --git a/test/Modules/on-demand-macros.m b/test/Modules/on-demand-macros.m
index 2b8c5456eb65..8b50529f1a28 100644
--- a/test/Modules/on-demand-macros.m
+++ b/test/Modules/on-demand-macros.m
@@ -1,6 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -DFOO_RETURNS_INT_PTR -verify %s
// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -verify %s
+// expected-no-diagnostics
@__experimental_modules_import CmdLine;
diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m
index d7930aca2ecc..d7224149a282 100644
--- a/test/Modules/redecl-merge.m
+++ b/test/Modules/redecl-merge.m
@@ -1,6 +1,5 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify -Wno-objc-root-class
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify -Wno-objc-root-class
@class C2;
@class C3;
@class C3;
@@ -57,26 +56,26 @@ void testTagMerge() {
void testTypedefMerge(int i, double d) {
T1 *ip = &i;
- // in other file: expected-note{{candidate found by name lookup is 'T2'}}
// FIXME: Typedefs aren't actually merged in the sense of other merges, because
// we should only merge them when the types are identical.
- // in other file: expected-note{{candidate found by name lookup is 'T2'}}
- // in other file: expected-note{{candidate function}}
+ // in other file: expected-note@60{{candidate found by name lookup is 'T2'}}
+ // in other file: expected-note@63{{candidate found by name lookup is 'T2'}}
T2 *dp = &d; // expected-error{{reference to 'T2' is ambiguous}}
}
void testFuncMerge(int i) {
func0(i);
- // in other file: expected-note{{candidate function}}
func1(i);
+ // in other file: expected-note@64{{candidate function}}
+ // in other file: expected-note@70{{candidate function}}
func2(i); // expected-error{{call to 'func2' is ambiguous}}
}
void testVarMerge(int i) {
var1 = i;
- // in other files: expected-note 2{{candidate found by name lookup is 'var2'}}
+ // in other files: expected-note@77 2{{candidate found by name lookup is 'var2'}}
var2 = i; // expected-error{{reference to 'var2' is ambiguous}}
- // in other files: expected-note 2{{candidate found by name lookup is 'var3'}}
+ // in other files: expected-note@79 2{{candidate found by name lookup is 'var3'}}
var3 = i; // expected-error{{reference to 'var3' is ambiguous}}
}
@@ -146,13 +145,6 @@ void g(A *a) {
id<P4> p4;
id<P3> p3;
-#ifdef __cplusplus
-void testVector() {
- Vector<int> vec_int;
- vec_int.push_back(0);
-}
-#endif
-
// Make sure we don't get conflicts with 'id'.
funcptr_with_id fid;
id id_global;
diff --git a/test/Modules/redeclarations.m b/test/Modules/redeclarations.m
index 3f3e6954cc2c..221e154cb274 100644
--- a/test/Modules/redeclarations.m
+++ b/test/Modules/redeclarations.m
@@ -8,4 +8,5 @@
// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=redeclarations_left %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=redeclarations_right %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t %s -verify
+// expected-no-diagnostics
diff --git a/test/Modules/submodules.m b/test/Modules/submodules.m
index e014bead73b2..a758abc248dd 100644
--- a/test/Modules/submodules.m
+++ b/test/Modules/submodules.m
@@ -1,6 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// expected-no-diagnostics
// Note: transitively imports Module.Sub2.
@__experimental_modules_import Module.Sub;
diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm
new file mode 100644
index 000000000000..45417401d86f
--- /dev/null
+++ b/test/Modules/templates.mm
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs -verify %s -Wno-objc-root-class
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | grep Emit | FileCheck %s
+// expected-no-diagnostics
+
+@__experimental_modules_import templates_left;
+@__experimental_modules_import templates_right;
+
+
+void testTemplateClasses() {
+ Vector<int> vec_int;
+ vec_int.push_back(0);
+
+ List<bool> list_bool;
+ list_bool.push_back(false);
+
+ N::Set<char> set_char;
+ set_char.insert('A');
+}
+
+void testPendingInstantiations() {
+ // CHECK: call {{.*pendingInstantiationEmit}}
+ // CHECK: call {{.*pendingInstantiationEmit}}
+ // CHECK: define {{.*pendingInstantiationEmit.*[(]i}}
+ // CHECK: define {{.*pendingInstantiationEmit.*[(]double}}
+ triggerPendingInstantiation();
+ triggerPendingInstantiationToo();
+}
+
+void testRedeclDefinition() {
+ // CHECK: define {{.*redeclDefinitionEmit}}
+ redeclDefinitionEmit();
+}
+
+// CHECK: call {{.*pendingInstantiation}}
+// CHECK: call {{.*redeclDefinitionEmit}}
diff --git a/test/PCH/Inputs/badpch-dir.h.gch/.keep b/test/PCH/Inputs/badpch-dir.h.gch/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/PCH/Inputs/badpch-dir.h.gch/.keep
diff --git a/test/PCH/Inputs/badpch-empty.h.gch b/test/PCH/Inputs/badpch-empty.h.gch
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/PCH/Inputs/badpch-empty.h.gch
diff --git a/test/PCH/Inputs/case-insensitive-include.h b/test/PCH/Inputs/case-insensitive-include.h
new file mode 100644
index 000000000000..60bdf36dbb7f
--- /dev/null
+++ b/test/PCH/Inputs/case-insensitive-include.h
@@ -0,0 +1,5 @@
+#pragma once
+
+struct S {
+ int x;
+};
diff --git a/test/PCH/Inputs/chain-macro-override1.h b/test/PCH/Inputs/chain-macro-override1.h
index d956396f9160..7532d7ef58d6 100644
--- a/test/PCH/Inputs/chain-macro-override1.h
+++ b/test/PCH/Inputs/chain-macro-override1.h
@@ -3,3 +3,7 @@ void g();
#define g() f()
#define h() f()
#define x x
+#define h2() f()
+
+#define h3()
+#undef h3
diff --git a/test/PCH/Inputs/chain-macro-override2.h b/test/PCH/Inputs/chain-macro-override2.h
index e4bff77294fd..1e0e3b967156 100644
--- a/test/PCH/Inputs/chain-macro-override2.h
+++ b/test/PCH/Inputs/chain-macro-override2.h
@@ -3,3 +3,6 @@
#undef h
#define h() g()
int x;
+#undef h2
+
+int h3();
diff --git a/test/PCH/Inputs/cxx11-statement-attributes.h b/test/PCH/Inputs/cxx11-statement-attributes.h
new file mode 100644
index 000000000000..f4d0619a3f98
--- /dev/null
+++ b/test/PCH/Inputs/cxx11-statement-attributes.h
@@ -0,0 +1,14 @@
+// To be used with cxx11-statement-attributes.cpp.
+template<const int N>
+int f(int n) {
+ switch (n * N) {
+ case 0:
+ n += 15;
+ [[clang::fallthrough]]; // This shouldn't generate a warning.
+ case 1:
+ n += 20;
+ [[clang::fallthrough]]; // This should generate a warning: "fallthrough annotation does not directly precede switch label".
+ break;
+ }
+ return n;
+}
diff --git a/test/PCH/__va_list_tag.c b/test/PCH/__va_list_tag.c
index 23c54ea8fb8e..efe5c1b36630 100644
--- a/test/PCH/__va_list_tag.c
+++ b/test/PCH/__va_list_tag.c
@@ -7,6 +7,8 @@
// RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -emit-pch -x c-header -o %t %S/Inputs/__va_list_tag.h
// RUN: %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include-pch %t %s -verify
+// expected-no-diagnostics
+
int myvprintf(const char *fmt, va_list args) {
return myvfprintf(fmt, args);
}
diff --git a/test/PCH/asm.c b/test/PCH/asm.c
index 99bc14dc2fb4..160829b7a6e7 100644
--- a/test/PCH/asm.c
+++ b/test/PCH/asm.c
@@ -5,6 +5,7 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t %S/asm.h
// RUN: %clang_cc1 -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
void call_f(void) { f(); }
diff --git a/test/PCH/badpch.c b/test/PCH/badpch.c
index e687ef324682..f34e3d6a158b 100644
--- a/test/PCH/badpch.c
+++ b/test/PCH/badpch.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -include-pch %S/badpch-empty.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-EMPTY %s
-// RUN: %clang_cc1 -fsyntax-only -include-pch %S/badpch-dir.h.gch %s 2>&1 | FileCheck -check-prefix=CHECK-DIR %s
+// 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
// The purpose of this test is to verify that various invalid PCH files are
// reported as such.
@@ -10,4 +10,4 @@
// submitted on 2012-02-06 introduced a segfault in the case where the PCH is
// an empty file and clang was built with assertions.
// CHECK-EMPTY: error: input is not a PCH file: '{{.*[/\\]}}badpch-empty.h.gch'
-// CHECK-DIR: error: unable to read PCH file {{.*[/\\]}}badpch-dir.h.gch:
+// CHECK-DIR:error: no suitable precompiled header file found in directory '{{.*[/\\]}}badpch-dir.h.gch
diff --git a/test/PCH/builtins.c b/test/PCH/builtins.c
index eed2224d415f..da9eef7496cd 100644
--- a/test/PCH/builtins.c
+++ b/test/PCH/builtins.c
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -emit-pch -o %t %S/builtins.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void hello() {
printf("Hello, World!");
}
diff --git a/test/PCH/case-insensitive-include.c b/test/PCH/case-insensitive-include.c
new file mode 100644
index 000000000000..707de702f15d
--- /dev/null
+++ b/test/PCH/case-insensitive-include.c
@@ -0,0 +1,29 @@
+// REQUIRES: case-insensitive-filesystem
+
+// Test this without pch.
+// RUN: cp %S/Inputs/case-insensitive-include.h %T
+// RUN: %clang_cc1 -fsyntax-only %s -include %s -I %T -verify
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s -I %T
+
+// Modify inode of the header.
+// RUN: cp %T/case-insensitive-include.h %t.copy
+// RUN: touch -r %T/case-insensitive-include.h %t.copy
+// RUN: mv %t.copy %T/case-insensitive-include.h
+
+// RUN: %clang_cc1 -fsyntax-only %s -include-pch %t.pch -I %T -verify
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#include "case-insensitive-include.h"
+#include "Case-Insensitive-Include.h"
+
+#else
+
+#include "Case-Insensitive-Include.h"
+
+#endif
diff --git a/test/PCH/chain-categories.m b/test/PCH/chain-categories.m
index 1b91c732b4d0..7836e09d88fe 100644
--- a/test/PCH/chain-categories.m
+++ b/test/PCH/chain-categories.m
@@ -4,6 +4,8 @@
// With PCH
// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+// expected-no-diagnostics
+
#ifndef HEADER1
#define HEADER1
//===----------------------------------------------------------------------===//
diff --git a/test/PCH/chain-class-extension.m b/test/PCH/chain-class-extension.m
index c99d6d43ae5e..03fdee70b850 100644
--- a/test/PCH/chain-class-extension.m
+++ b/test/PCH/chain-class-extension.m
@@ -4,6 +4,8 @@
// With PCH
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 -fobjc-arc %s -chain-include %s -chain-include %s
+// expected-no-diagnostics
+
#ifndef HEADER1
#define HEADER1
//===----------------------------------------------------------------------===//
diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp
index 0d50e61c5a95..4b64f51143df 100644
--- a/test/PCH/chain-cxx.cpp
+++ b/test/PCH/chain-cxx.cpp
@@ -6,6 +6,8 @@
// With PCH
// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+// expected-no-diagnostics
+
#ifndef HEADER1
#define HEADER1
//===----------------------------------------------------------------------===//
diff --git a/test/PCH/chain-decls.c b/test/PCH/chain-decls.c
index f5724c4c1343..bffa09228f90 100644
--- a/test/PCH/chain-decls.c
+++ b/test/PCH/chain-decls.c
@@ -7,6 +7,8 @@
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
+// expected-no-diagnostics
+
// CHECK: void f();
// CHECK: void g();
diff --git a/test/PCH/chain-macro-override.c b/test/PCH/chain-macro-override.c
index 2713e7084a9d..24a7b3edf640 100644
--- a/test/PCH/chain-macro-override.c
+++ b/test/PCH/chain-macro-override.c
@@ -10,5 +10,7 @@ int foo() {
f();
g();
h();
+ h2(); // expected-warning{{implicit declaration of function 'h2' is invalid in C99}}
+ h3();
return x;
}
diff --git a/test/PCH/chain-macro.c b/test/PCH/chain-macro.c
index 18356f75a0e2..b0fd63de46d5 100644
--- a/test/PCH/chain-macro.c
+++ b/test/PCH/chain-macro.c
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -emit-pch -o %t2 -detailed-preprocessing-record %S/Inputs/chain-macro2.h -include-pch %t1
// RUN: %clang_cc1 -fsyntax-only -verify -include-pch %t2 %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
+// expected-no-diagnostics
// CHECK: void f();
FOOBAR
diff --git a/test/PCH/chain-remap-types.m b/test/PCH/chain-remap-types.m
index 585da4486502..13f2e39b148d 100644
--- a/test/PCH/chain-remap-types.m
+++ b/test/PCH/chain-remap-types.m
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -emit-pch -x objective-c-header -o %t2 %S/Inputs/chain-remap-types2.h -include-pch %t1
// RUN: %clang_cc1 -include-pch %t2 -fsyntax-only -verify %s
// RUN: %clang_cc1 -ast-print -include-pch %t2 %s | FileCheck %s
+// expected-no-diagnostics
// CHECK: @class X;
// CHECK: struct Y
diff --git a/test/PCH/cmdline-include.c b/test/PCH/cmdline-include.c
index ad4519279ae3..556c28ea0f5a 100644
--- a/test/PCH/cmdline-include.c
+++ b/test/PCH/cmdline-include.c
@@ -2,5 +2,6 @@
// RUN: %clang_cc1 %s -include-pch %t -fsyntax-only -verify
// RUN: %clang_cc1 -x c-header %S/cmdline-include1.h -emit-pch -o %t
// RUN: %clang_cc1 %s -include-pch %t -include %S/cmdline-include2.h -fsyntax-only -verify
+// expected-no-diagnostics
int g = x1 + x2;
diff --git a/test/PCH/cxx-exprs.cpp b/test/PCH/cxx-exprs.cpp
index 9cd31941e356..b7707e0b9347 100644
--- a/test/PCH/cxx-exprs.cpp
+++ b/test/PCH/cxx-exprs.cpp
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
+// expected-no-diagnostics
+
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/cxx-for-range.h b/test/PCH/cxx-for-range.h
index f15c7e73df39..8f50f2f26928 100644
--- a/test/PCH/cxx-for-range.h
+++ b/test/PCH/cxx-for-range.h
@@ -9,11 +9,12 @@ struct T { };
char *begin(T);
char *end(T);
-struct U { };
-namespace std {
+namespace NS {
+ struct U { };
char *begin(U);
char *end(U);
}
+using NS::U;
void f() {
char a[3] = { 0, 1, 2 };
diff --git a/test/PCH/cxx-friends.cpp b/test/PCH/cxx-friends.cpp
index bdba42bbcb51..f7d45cea8df4 100644
--- a/test/PCH/cxx-friends.cpp
+++ b/test/PCH/cxx-friends.cpp
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
class F {
void m() {
A* a;
diff --git a/test/PCH/cxx-functions.cpp b/test/PCH/cxx-functions.cpp
index 74df01a094b3..3b4fe77c044a 100644
--- a/test/PCH/cxx-functions.cpp
+++ b/test/PCH/cxx-functions.cpp
@@ -4,6 +4,8 @@
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-functions.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void test_foo() {
foo();
diff --git a/test/PCH/cxx-implicit-moves.cpp b/test/PCH/cxx-implicit-moves.cpp
index ccdc874cb1fa..ff6322d49d68 100644
--- a/test/PCH/cxx-implicit-moves.cpp
+++ b/test/PCH/cxx-implicit-moves.cpp
@@ -1,6 +1,7 @@
// Test with PCH
// RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -o %t %s
// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+// expected-no-diagnostics
// PR10847
#ifndef HEADER
diff --git a/test/PCH/cxx-method.cpp b/test/PCH/cxx-method.cpp
index 6ec65b248618..40490ea681fa 100644
--- a/test/PCH/cxx-method.cpp
+++ b/test/PCH/cxx-method.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -x c++ -emit-pch %S/Inputs/cxx-method.h -o %t
// RUN: %clang_cc1 -include-pch %t -verify %s
+// expected-no-diagnostics
void S::m(int x) { }
diff --git a/test/PCH/cxx-ms-function-specialization-class-scope.cpp b/test/PCH/cxx-ms-function-specialization-class-scope.cpp
index 1803a11b96b8..afbb80b7376e 100644
--- a/test/PCH/cxx-ms-function-specialization-class-scope.cpp
+++ b/test/PCH/cxx-ms-function-specialization-class-scope.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -x c++-header -emit-pch -o %t %S/cxx-ms-function-specialization-class-scope.h
// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
void test2()
diff --git a/test/PCH/cxx-namespaces.cpp b/test/PCH/cxx-namespaces.cpp
index 0fd3de7f6c88..e0ff27c020c4 100644
--- a/test/PCH/cxx-namespaces.cpp
+++ b/test/PCH/cxx-namespaces.cpp
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-namespaces.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void m() {
N::x = 0;
}
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index 7ce247721f8f..d27e9ca93c43 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,11 +1,13 @@
// Test this without pch.
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -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 -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
// Test with pch.
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// 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 - | FileCheck %s
+
+// expected-no-diagnostics
// CHECK: define weak_odr void @_ZN2S4IiE1mEv
// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
@@ -68,3 +70,12 @@ Foo< D >& Foo< D >::operator=( const Foo& other )
{
return *this;
}
+
+namespace TestNestedExpansion {
+ struct Int {
+ Int(int);
+ friend Int operator+(Int, Int);
+ };
+ Int &g(Int, int, double);
+ Int &test = NestedExpansion<char, char, char>().f(0, 1, 2, Int(3), 4, 5.0);
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index 152e8cef5464..756f208b76fd 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -215,3 +215,8 @@ class Foo : protected T
public:
Foo& operator=( const Foo& other );
};
+
+template<typename...A> struct NestedExpansion {
+ template<typename...B> auto f(A...a, B...b) -> decltype(g(a + b...));
+};
+template struct NestedExpansion<char, char, char>;
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index 3df34794f2e2..938f36f2c279 100644
--- a/test/PCH/cxx-traits.cpp
+++ b/test/PCH/cxx-traits.cpp
@@ -4,6 +4,8 @@
// 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
+// expected-no-diagnostics
+
bool _Is_pod_comparator = __is_pod<int>::__value;
bool _Is_empty_check = __is_empty<int>::__value;
diff --git a/test/PCH/cxx-typeid.cpp b/test/PCH/cxx-typeid.cpp
index 41dd544807ea..d1e0f9ded751 100644
--- a/test/PCH/cxx-typeid.cpp
+++ b/test/PCH/cxx-typeid.cpp
@@ -4,6 +4,8 @@
// RUN: %clang -ccc-pch-is-pch -x c++-header -o %t.gch %S/cxx-typeid.h
// RUN: %clang -ccc-pch-is-pch -include %t -fsyntax-only -Xclang -verify %s
+// expected-no-diagnostics
+
void f() {
(void)typeid(int);
}
diff --git a/test/PCH/cxx-variadic-templates.cpp b/test/PCH/cxx-variadic-templates.cpp
index 5b586931d541..dc00758aa520 100644
--- a/test/PCH/cxx-variadic-templates.cpp
+++ b/test/PCH/cxx-variadic-templates.cpp
@@ -7,5 +7,11 @@
// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s -ast-dump -o -
// RUN: %clang_cc1 -std=c++11 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
// CHECK: allocate_shared
shared_ptr<int> spi = shared_ptr<int>::allocate_shared(1, 2);
+
+template<int> struct A {};
+template<int> struct B {};
+outer<int, int>::inner<1, 2, A, B> i(A<1>{}, B<2>{});
diff --git a/test/PCH/cxx-variadic-templates.h b/test/PCH/cxx-variadic-templates.h
index f6ee7876c2c2..50596cdf5dbf 100644
--- a/test/PCH/cxx-variadic-templates.h
+++ b/test/PCH/cxx-variadic-templates.h
@@ -16,3 +16,10 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args)
shared_ptr<_Tp> __r;
return __r;
}
+
+template<typename...Ts> struct outer {
+ template<Ts...Vs, template<Ts> class ...Cs> struct inner {
+ inner(Cs<Vs>...);
+ };
+};
+template struct outer<int, int>;
diff --git a/test/PCH/cxx11-constexpr.cpp b/test/PCH/cxx11-constexpr.cpp
index ce43206d3960..8b722ce98095 100644
--- a/test/PCH/cxx11-constexpr.cpp
+++ b/test/PCH/cxx11-constexpr.cpp
@@ -20,6 +20,13 @@ struct D : B {
int k;
};
+constexpr int value = 7;
+
+template<typename T>
+constexpr T plus_seven(T other) {
+ return value + other;
+}
+
#else
static_assert(D(4).k == 9, "");
@@ -28,4 +35,6 @@ constexpr int f(C c) { return 0; } // expected-error {{not a literal type}}
constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}}
// expected-note@9 {{here}}
+static_assert(plus_seven(3) == 10, "");
+
#endif
diff --git a/test/PCH/cxx11-exception-spec.cpp b/test/PCH/cxx11-exception-spec.cpp
index 3fca4e48acf8..446619ed1c94 100644
--- a/test/PCH/cxx11-exception-spec.cpp
+++ b/test/PCH/cxx11-exception-spec.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+// expected-no-diagnostics
#ifndef HEADER_INCLUDED
diff --git a/test/PCH/cxx11-statement-attributes.cpp b/test/PCH/cxx11-statement-attributes.cpp
new file mode 100644
index 000000000000..3bb7b40aa96a
--- /dev/null
+++ b/test/PCH/cxx11-statement-attributes.cpp
@@ -0,0 +1,12 @@
+// Sanity check.
+// RUN: %clang_cc1 -include %S/Inputs/cxx11-statement-attributes.h -std=c++11 -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
+// Run the same tests, this time with the attributes loaded from the PCH file.
+// RUN: %clang_cc1 -x c++-header -emit-pch -std=c++11 -o %t %S/Inputs/cxx11-statement-attributes.h
+// RUN: %clang_cc1 -include-pch %t -std=c++11 -Wimplicit-fallthrough -fsyntax-only %s -o - -verify
+
+// Warning from Inputs/cxx11-statement-attributes.h:
+// expected-warning@10 {{fallthrough annotation does not directly precede switch label}}
+
+void g(int n) {
+ f<1>(n); // expected-note {{in instantiation of function template specialization 'f<1>' requested here}}
+}
diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp
index 4cd9bae1fa4c..0fb7590c68b5 100644
--- a/test/PCH/cxx_exprs.cpp
+++ b/test/PCH/cxx_exprs.cpp
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -std=c++11 -emit-pch -o %t %S/cxx_exprs.h
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-dump
+// expected-no-diagnostics
+
int integer;
double floating;
char character;
@@ -37,3 +39,9 @@ cxx_null_ptr_result null_ptr = nullptr;
// CXXTypeidExpr
typeid_result1 typeid_1 = 0;
typeid_result2 typeid_2 = 0;
+
+// CharacterLiteral variants
+static_assert(char_value == 97, "char_value is correct");
+static_assert(wchar_t_value == 305, "wchar_t_value is correct");
+static_assert(char16_t_value == 231, "char16_t_value is correct");
+static_assert(char32_t_value == 8706, "char32_t_value is correct");
diff --git a/test/PCH/cxx_exprs.h b/test/PCH/cxx_exprs.h
index 67ab4a6d34db..35db82efaeec 100644
--- a/test/PCH/cxx_exprs.h
+++ b/test/PCH/cxx_exprs.h
@@ -81,3 +81,8 @@ CtorStruct create_CtorStruct() {
return CtorStruct(1, 3.14f); // CXXTemporaryObjectExpr
};
+// CharacterLiteral variants
+const char char_value = 'a';
+const wchar_t wchar_t_value = L'ı';
+const char16_t char16_t_value = u'ç';
+const char32_t char32_t_value = U'∂';
diff --git a/test/PCH/empty-with-headers.c b/test/PCH/empty-with-headers.c
index 751be1c9eb39..b51f0ce25848 100644
--- a/test/PCH/empty-with-headers.c
+++ b/test/PCH/empty-with-headers.c
@@ -24,4 +24,4 @@ typedef int my_int;
// This should only fire if the header is not included,
// either explicitly or as a prefix header.
-// expected-error{{ISO C requires a translation unit to contain at least one declaration.}}
+// expected-error{{ISO C requires a translation unit to contain at least one declaration}}
diff --git a/test/PCH/enum.c b/test/PCH/enum.c
index 10ceb7c60b0a..81dbd907ac78 100644
--- a/test/PCH/enum.c
+++ b/test/PCH/enum.c
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -emit-pch -o %t %S/enum.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
int i = Red;
int return_enum_constant() {
diff --git a/test/PCH/exprs.c b/test/PCH/exprs.c
index 5928abda58f3..c0b279f88a38 100644
--- a/test/PCH/exprs.c
+++ b/test/PCH/exprs.c
@@ -3,7 +3,11 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -fblocks -o %t %S/exprs.h
-// RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s -DWITH_PCH
+
+#ifdef WITH_PCH
+// expected-no-diagnostics
+#endif
__SIZE_TYPE__ size_type_value;
int integer;
diff --git a/test/PCH/field-designator.c b/test/PCH/field-designator.c
new file mode 100644
index 000000000000..763cfdab28da
--- /dev/null
+++ b/test/PCH/field-designator.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -cc1 %s -include %s
+// RUN: %clang_cc1 -cc1 %s -emit-pch -o %t.pch
+// RUN: %clang_cc1 -cc1 %s -include-pch %t.pch
+
+// rdar://12239321 Make sure we don't emit a bogus
+// error: field designator 'e' does not refer to a non-static data member
+
+#ifndef HEADER
+#define HEADER
+//===----------------------------------------------------------------------===//
+
+struct U {
+ union {
+ struct {
+ int e;
+ int f;
+ };
+
+ int a;
+ };
+};
+
+//===----------------------------------------------------------------------===//
+#else
+#if !defined(HEADER)
+# error Header inclusion order messed up
+#endif
+//===----------------------------------------------------------------------===//
+
+void bar() {
+ static const struct U plan = { .e = 1 };
+}
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/friend-template.cpp b/test/PCH/friend-template.cpp
new file mode 100644
index 000000000000..989819b64fbe
--- /dev/null
+++ b/test/PCH/friend-template.cpp
@@ -0,0 +1,46 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %s -fsyntax-only -verify %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+// rdar://12627738
+namespace rdar12627738 {
+
+class RecyclerTag {
+ template <typename T> friend class Recycler;
+};
+
+}
+
+#else
+
+namespace rdar12627738 {
+
+template<typename TTag>
+class CRN {
+ template <typename T> friend class Recycler;
+};
+
+
+template<typename T>
+class Recycler {
+public:
+ Recycler ();
+};
+
+
+template<typename T>
+Recycler<T>::Recycler ()
+{
+}
+
+}
+
+#endif
diff --git a/test/PCH/fuzzy-pch.c b/test/PCH/fuzzy-pch.c
index 567575346ce1..7296d1dc893b 100644
--- a/test/PCH/fuzzy-pch.c
+++ b/test/PCH/fuzzy-pch.c
@@ -1,8 +1,14 @@
// Test with pch.
// RUN: %clang_cc1 -emit-pch -DFOO -o %t %S/variables.h
// RUN: %clang_cc1 -DBAR=int -include-pch %t -fsyntax-only -pedantic %s
-// RUN: %clang_cc1 -DFOO -DBAR=int -include-pch %t -Werror %s
-// RUN: not %clang_cc1 -DFOO -DBAR=int -DX=5 -include-pch %t -Werror %s
+// RUN: %clang_cc1 -DFOO -DBAR=int -include-pch %t %s
+// RUN: not %clang_cc1 -DFOO=blah -DBAR=int -include-pch %t %s 2> %t.err
+// RUN: FileCheck -check-prefix=CHECK-FOO %s < %t.err
+// RUN: not %clang_cc1 -UFOO -include-pch %t %s 2> %t.err
+// RUN: FileCheck -check-prefix=CHECK-NOFOO %s < %t.err
+
+// RUN: not %clang_cc1 -DFOO -undef -include-pch %t %s 2> %t.err
+// RUN: FileCheck -check-prefix=CHECK-UNDEF %s < %t.err
BAR bar = 17;
@@ -17,3 +23,9 @@ BAR bar = 17;
#ifndef BAR
# error BAR was not defined
#endif
+
+// CHECK-FOO: definition of macro 'FOO' differs between the precompiled header ('1') and the command line ('blah')
+// CHECK-NOFOO: macro 'FOO' was defined in the precompiled header but undef'd on the command line
+
+// CHECK-UNDEF: command line contains '-undef' but precompiled header was not built with it
+
diff --git a/test/PCH/missing-file.cpp b/test/PCH/missing-file.cpp
index 7d5cd111101c..7dd11d4561a8 100644
--- a/test/PCH/missing-file.cpp
+++ b/test/PCH/missing-file.cpp
@@ -4,19 +4,14 @@
// RUN: echo 'struct S{char c; int i; }; void foo() {}' > %t.h
// RUN: echo 'template <typename T> void tf() { T::foo(); }' >> %t.h
// RUN: %clang_cc1 -x c++ -emit-pch -o %t.h.pch %t.h
-// RUN: rm %t.h
-// Check diagnostic with location in original source:
-// RUN: %clang_cc1 -include-pch %t.h.pch -Wpadded -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'bytes to align' %t.stderr
-
-// Check diagnostic with 2nd location in original source:
-// RUN: not %clang_cc1 -DREDECL -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'previous definition is here' %t.stderr
+// %t.h might be touched by scanners as a hot file on Windows,
+// to fail to remove %.h with single run.
+// RUN: rm %t.h || rm %t.h || rm %t.h
-// Check diagnostic with instantiation location in original source:
-// RUN: not %clang_cc1 -DINSTANTIATION -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'cannot be used prior to' %t.stderr
+// Check diagnostic with location in original source:
+// RUN: not %clang_cc1 -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'could not find file' %t.stderr
void qq(S*) {}
diff --git a/test/PCH/objc_container.m b/test/PCH/objc_container.m
index 1e59054a2e54..07371caeaf71 100644
--- a/test/PCH/objc_container.m
+++ b/test/PCH/objc_container.m
@@ -4,8 +4,10 @@
// 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=PRINT %s
+// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+
+// expected-no-diagnostics
// CHECK-PRINT: id oldObject = array[10];
// CHECK-PRINT: array[10] = oldObject;
diff --git a/test/PCH/objc_import.m b/test/PCH/objc_import.m
index 277c6dd6c2f0..c7dd805b3e47 100644
--- a/test/PCH/objc_import.m
+++ b/test/PCH/objc_import.m
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_import.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
#import "objc_import.h"
void func() {
diff --git a/test/PCH/objc_literals.m b/test/PCH/objc_literals.m
index cce3173bba02..b73c3bebb8c4 100644
--- a/test/PCH/objc_literals.m
+++ b/test/PCH/objc_literals.m
@@ -1,7 +1,9 @@
-// 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 -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
+
+// expected-no-diagnostics
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/objc_literals.mm b/test/PCH/objc_literals.mm
index 8ef335115030..ef95294d7aa7 100644
--- a/test/PCH/objc_literals.mm
+++ b/test/PCH/objc_literals.mm
@@ -1,7 +1,9 @@
-// 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 -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
+
+// expected-no-diagnostics
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m
index e8aab843dc51..ea40460fb8df 100644
--- a/test/PCH/objc_methods.m
+++ b/test/PCH/objc_methods.m
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_methods.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void func() {
TestPCH *xx;
TestForwardClassDecl *yy;
diff --git a/test/PCH/objc_property.m b/test/PCH/objc_property.m
index b51cd90927ae..88a091928050 100644
--- a/test/PCH/objc_property.m
+++ b/test/PCH/objc_property.m
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_property.h
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void func() {
TestProperties *xx = [TestProperties alloc];
xx.value = 5;
diff --git a/test/PCH/pch-dir.c b/test/PCH/pch-dir.c
new file mode 100644
index 000000000000..ae841ce0a7a4
--- /dev/null
+++ b/test/PCH/pch-dir.c
@@ -0,0 +1,28 @@
+// RUN: mkdir -p %t.h.gch
+// RUN: %clang -x c-header %S/pch-dir.h -DFOO=foo -o %t.h.gch/c.gch
+// 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: %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: %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: not %clang -x c++ -std=c++11 -include %t.h -fsyntax-only %s 2> %t.cpp11log
+// RUN: FileCheck -check-prefix=CPP11 %s < %t.cpp11log
+
+// CHECK-CBAR: int bar
+int FOO;
+
+int get() {
+#ifdef __cplusplus
+ // CHECK-CPP: .h.gch{{[/\\]}}cpp.gch
+ return i;
+#else
+ // CHECK-C: .h.gch{{[/\\]}}c.gch
+ return j;
+#endif
+}
+
+// CHECK-CPP11: no suitable precompiled header file found in directory
diff --git a/test/PCH/pch-dir.h b/test/PCH/pch-dir.h
new file mode 100644
index 000000000000..e94a8c7ad90a
--- /dev/null
+++ b/test/PCH/pch-dir.h
@@ -0,0 +1,5 @@
+#ifdef __cplusplus
+extern int i;
+#else
+extern int j;
+#endif
diff --git a/test/PCH/pending-ids.m b/test/PCH/pending-ids.m
index b612d89e9452..2ca0e6e93568 100644
--- a/test/PCH/pending-ids.m
+++ b/test/PCH/pending-ids.m
@@ -7,6 +7,8 @@
// RUN: %clang_cc1 %s -emit-pch -o %t
// RUN: %clang_cc1 -emit-llvm-only -verify %s -include-pch %t -g
+// expected-no-diagnostics
+
#ifndef HEADER
#define HEADER
//===----------------------------------------------------------------------===//
diff --git a/test/PCH/pragma-diag-section.cpp b/test/PCH/pragma-diag-section.cpp
index 5b996bb2f0d1..627156f15398 100644
--- a/test/PCH/pragma-diag-section.cpp
+++ b/test/PCH/pragma-diag-section.cpp
@@ -11,7 +11,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
template <typename T>
-struct TS {
+struct TS1 {
void m() {
T a = 0;
T b = a==a;
@@ -21,9 +21,22 @@ struct TS {
#else
+
+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}}
+ }
+};
+
void f() {
- TS<int> ts;
- ts.m();
+ TS1<int> ts1;
+ ts1.m();
+
+
+ TS2<int> ts2;
+ ts2.m();
}
#endif
diff --git a/test/PCH/pragma-diag.c b/test/PCH/pragma-diag.c
index b304c4bf8c35..601c940cee9b 100644
--- a/test/PCH/pragma-diag.c
+++ b/test/PCH/pragma-diag.c
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 %s -emit-pch -o %t
// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only
+// expected-no-diagnostics
+
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/rdar8852495.c b/test/PCH/rdar8852495.c
index fb465a37ce38..7639f1f0db65 100644
--- a/test/PCH/rdar8852495.c
+++ b/test/PCH/rdar8852495.c
@@ -5,6 +5,8 @@
// RUN: %clang_cc1 %s -emit-pch -o %t -Wsign-compare -Wtautological-compare
// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only -Wno-sign-compare -Wtautological-compare
+// expected-no-diagnostics
+
// This tests that diagnostic mappings from PCH are propagated for #pragma
// diagnostics but not for command-line flags.
diff --git a/test/PCH/reinclude.cpp b/test/PCH/reinclude.cpp
index 97e22cf9d6f1..4bec0508b149 100644
--- a/test/PCH/reinclude.cpp
+++ b/test/PCH/reinclude.cpp
@@ -7,4 +7,6 @@
// RUN: %clang_cc1 -x c++-header %S/reinclude2.h -include-pch %t1 -emit-pch -o %t2
// RUN: %clang_cc1 %s -include-pch %t2 -fsyntax-only -verify
+// expected-no-diagnostics
+
int q2 = A::y;
diff --git a/test/PCH/single-token-macro.c b/test/PCH/single-token-macro.c
index 29edb753e41a..52873bfc2441 100644
--- a/test/PCH/single-token-macro.c
+++ b/test/PCH/single-token-macro.c
@@ -7,6 +7,8 @@
// RUN: %clang_cc1 %s -emit-pch -o %t
// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only
+// expected-no-diagnostics
+
#ifndef HEADER
#define HEADER
diff --git a/test/PCH/target-options.c b/test/PCH/target-options.c
new file mode 100644
index 000000000000..2b85efe07abf
--- /dev/null
+++ b/test/PCH/target-options.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-pch -o %t.pch %S/target-options.h
+// RUN: not %clang_cc1 -triple=x86_64-unknown-freebsd7.0 -include-pch %t.pch %s -emit-llvm -o - > %t.err 2>&1
+// RUN: FileCheck %s < %t.err
+
+// CHECK: for the target
diff --git a/test/PCH/target-options.h b/test/PCH/target-options.h
new file mode 100644
index 000000000000..2c3edf6aa2e7
--- /dev/null
+++ b/test/PCH/target-options.h
@@ -0,0 +1,2 @@
+enum { apple_cc = __APPLE_CC__ };
+
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index 6219e29f597a..fd38dca19419 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -174,13 +174,21 @@ void redundant_typename() {
__interface MicrosoftInterface;
__interface MicrosoftInterface {
- virtual void foo1() = 0;
+ void foo1() = 0;
virtual void foo2() = 0;
};
+__interface MicrosoftDerivedInterface : public MicrosoftInterface {
+ void foo1();
+ void foo2() override;
+ void foo3();
+};
+
void interface_test() {
MicrosoftInterface* a;
a->foo1();
+ MicrosoftDerivedInterface* b;
+ b->foo2();
}
__int64 x7 = __int64(0);
@@ -230,29 +238,29 @@ __if_not_exists(IF_EXISTS::Type_not) {
int __if_exists_init_list() {
- int array1[] = {
- 0,
- __if_exists(IF_EXISTS::Type) {2, }
- 3
- };
-
- int array2[] = {
- 0,
- __if_exists(IF_EXISTS::Type_not) { this wont compile }
- 3
- };
-
- int array3[] = {
- 0,
- __if_not_exists(IF_EXISTS::Type_not) {2, }
- 3
- };
-
- int array4[] = {
- 0,
- __if_not_exists(IF_EXISTS::Type) { this wont compile }
- 3
- };
+ int array1[] = {
+ 0,
+ __if_exists(IF_EXISTS::Type) {2, }
+ 3
+ };
+
+ int array2[] = {
+ 0,
+ __if_exists(IF_EXISTS::Type_not) { this wont compile }
+ 3
+ };
+
+ int array3[] = {
+ 0,
+ __if_not_exists(IF_EXISTS::Type_not) {2, }
+ 3
+ };
+
+ int array4[] = {
+ 0,
+ __if_not_exists(IF_EXISTS::Type) { this wont compile }
+ 3
+ };
}
diff --git a/test/Parser/block-block-storageclass.c b/test/Parser/block-block-storageclass.c
index 97ba11349217..53cd99725225 100644
--- a/test/Parser/block-block-storageclass.c
+++ b/test/Parser/block-block-storageclass.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// expected-no-diagnostics
int printf(const char *, ...);
void _Block_byref_release(void*src){}
diff --git a/test/Parser/block-pointer-decl.c b/test/Parser/block-pointer-decl.c
index a8cc258ca375..d88daf3a870d 100644
--- a/test/Parser/block-pointer-decl.c
+++ b/test/Parser/block-pointer-decl.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s
+// expected-no-diagnostics
int printf(char const *, ...);
diff --git a/test/Parser/builtin_classify_type.c b/test/Parser/builtin_classify_type.c
index a7c08555c905..ff483b20974b 100644
--- a/test/Parser/builtin_classify_type.c
+++ b/test/Parser/builtin_classify_type.c
@@ -10,7 +10,7 @@ int main() {
static int ary[__builtin_classify_type(a)];
static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
- static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{variable length array declaration can not have 'static' storage duration}}
+ static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{builtin functions must be directly called}}
int result;
diff --git a/test/Parser/check-objc2-syntax-1.m b/test/Parser/check-objc2-syntax-1.m
index 3cdf2b05cf85..9aff96377404 100644
--- a/test/Parser/check-objc2-syntax-1.m
+++ b/test/Parser/check-objc2-syntax-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface Subclass
+ (int)magicNumber;
diff --git a/test/Parser/colon-colon-parentheses.cpp b/test/Parser/colon-colon-parentheses.cpp
new file mode 100644
index 000000000000..55948fdb0051
--- /dev/null
+++ b/test/Parser/colon-colon-parentheses.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x c++ -fixit %t
+// RUN: %clang_cc1 -x c++ %t
+
+struct S { static int a,b,c;};
+int S::(a); // expected-error{{unexpected parenthesis after '::'}}
+int S::(b; // expected-error{{unexpected parenthesis after '::'}}
+int S::c;
+int S::(*d); // expected-error{{unexpected parenthesis after '::'}}
+int S::(*e; // expected-error{{unexpected parenthesis after '::'}}
+int S::*f;
+int g = S::(a); // expected-error{{unexpected parenthesis after '::'}}
+int h = S::(b; // expected-error{{unexpected parenthesis after '::'}}
+int i = S::c;
+
+void foo() {
+ int a;
+ a = ::(g); // expected-error{{unexpected parenthesis after '::'}}
+ a = ::(h; // expected-error{{unexpected parenthesis after '::'}}
+ a = ::i;
+}
diff --git a/test/Parser/compound_literal.c b/test/Parser/compound_literal.c
index 4f3609dc29f4..9a0e4a64a654 100644
--- a/test/Parser/compound_literal.c
+++ b/test/Parser/compound_literal.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int main() {
char *s;
s = (char []){"whatever"};
diff --git a/test/Parser/cxx-ambig-decl-expr.cpp b/test/Parser/cxx-ambig-decl-expr.cpp
index b5ff728b47c9..feb185fbe3f2 100644
--- a/test/Parser/cxx-ambig-decl-expr.cpp
+++ b/test/Parser/cxx-ambig-decl-expr.cpp
@@ -7,4 +7,7 @@ struct X {
void f() {
void (*ptr)(int, int) = &X::f<int, int>;
+
+ unknown *p = 0; // expected-error {{unknown type name 'unknown'}}
+ unknown * p + 0; // expected-error {{undeclared identifier 'unknown'}}
}
diff --git a/test/Parser/cxx-attributes.cpp b/test/Parser/cxx-attributes.cpp
index 8603b3090016..5ea0ce227595 100644
--- a/test/Parser/cxx-attributes.cpp
+++ b/test/Parser/cxx-attributes.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
class c {
virtual void f1(const char* a, ...)
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index 42ad12ee94f3..01980d334176 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -58,9 +58,9 @@ void test2(char x, struct B * b) {
expected-error {{expected ']'}}
#define LC <:
#define C :
- test1::A LC:B> c; // expected-error {{cannot refer to class template 'A' without a template argument list}} expected-error 2{{}} expected-note{{}}
+ test1::A LC:B> c; // expected-error {{class template test1::A requires template arguments}} expected-error 2{{}}
(void)static_cast LC:c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
- test1::A<:C B> d; // expected-error {{cannot refer to class template 'A' without a template argument list}} expected-error 2{{}} expected-note{{}}
+ test1::A<:C B> d; // expected-error {{class template test1::A requires template arguments}} expected-error 2{{}}
(void)static_cast<:C c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
#define LCC <::
@@ -85,8 +85,10 @@ void test3() {
E< ::F>();
// Make sure that parser doesn't expand '[:' to '< ::'
- ::D[:F> A5; // expected-error {{cannot refer to class template 'D' without a template argument list}} \
+ ::D[:F> A5; // expected-error {{class template ::D requires template arguments}} \
// expected-error {{expected expression}} \
- // expected-error {{expected ']'}} \
- // expected-note {{to match this '['}}
+ // expected-error {{expected unqualified-id}}
}
+
+// PR13619. Must be at end of file.
+int n = reinterpret_cast // expected-error {{expected '<'}} expected-error {{expected ';'}}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index feccba85cf00..8ed5882a2821 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -88,6 +88,20 @@ namespace ctor_error {
// expected-error{{unknown type name 'UnknownType'}}
}
+// PR13775: Don't assert here.
+namespace PR13775 {
+ class bar
+ {
+ public:
+ void foo ();
+ void baz ();
+ };
+ void bar::foo ()
+ {
+ baz x(); // expected-error 3{{}}
+ }
+}
+
// PR11109 must appear at the end of the source file
class pr11109r3 { // expected-note{{to match this '{'}}
public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 951cd3dfd1e1..290b947de2b7 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic %s
+const char const *x10; // expected-warning {{duplicate 'const' declaration specifier}}
+
int x(*g); // expected-error {{use of undeclared identifier 'g'}}
struct Type {
@@ -119,6 +121,9 @@ void CodeCompleteConsumer::() { // expected-error {{xpected unqualified-id}}
;
+// PR4111
+void f(sqrgl); // expected-error {{unknown type name 'sqrgl'}}
+
// PR8380
extern "" // expected-error {{unknown linkage language}}
test6a { ;// expected-error {{C++ requires a type specifier for all declarations}} \
diff --git a/test/Parser/cxx-extern-c-array.cpp b/test/Parser/cxx-extern-c-array.cpp
index 14912fd1067b..11092ad0c1cc 100644
--- a/test/Parser/cxx-extern-c-array.cpp
+++ b/test/Parser/cxx-extern-c-array.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern "C" int myarray[];
int myarray[12] = {0};
diff --git a/test/Parser/cxx-stmt.cpp b/test/Parser/cxx-stmt.cpp
index 7677ca880128..c2fa0a4df0df 100644
--- a/test/Parser/cxx-stmt.cpp
+++ b/test/Parser/cxx-stmt.cpp
@@ -58,3 +58,11 @@ void f5() {
asm volatile ("":: :"memory");
asm volatile ("": ::"memory");
}
+
+int f6() {
+ int k, // expected-note {{change this ',' to a ';' to call 'f6'}}
+ f6(), // expected-error {{expected ';'}} expected-warning {{interpreted as a function declaration}} expected-note {{replace paren}}
+ int n = 0, // expected-error {{expected ';'}}
+ return f5(), // ok
+ int(n);
+}
diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp
index 5479961d563d..afe318df7a1a 100644
--- a/test/Parser/cxx-template-argument.cpp
+++ b/test/Parser/cxx-template-argument.cpp
@@ -25,3 +25,20 @@ namespace greatergreater {
(void)(&t<S<int>>==p); // expected-error {{use '> >'}} expected-error {{use '> ='}}
}
}
+
+namespace PR5925 {
+ template <typename x>
+ class foo { // expected-note {{here}}
+ };
+ void bar(foo *X) { // expected-error {{requires template arguments}}
+ }
+}
+
+namespace PR13210 {
+ template <class T>
+ class C {}; // expected-note {{here}}
+
+ void f() {
+ new C(); // expected-error {{requires template arguments}}
+ }
+}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index a0b8467bcca3..58e42bffcff3 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -44,10 +44,15 @@ int & [[]] ref_attr = after_attr;
int && [[]] rref_attr = 0;
int array_attr [1] [[]];
alignas(8) int aligned_attr;
-[[test::valid(for 42 [very] **** '+' symbols went on a trip and had a "good"_time; the end.)]]
- int garbage_attr;
-[[,,,static, class, namespace,, inline, constexpr, mutable,, bi\
-tand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr;
+[[test::valid(for 42 [very] **** '+' symbols went on a trip and had a "good"_time; the end.)]] int garbage_attr; // expected-warning {{unknown attribute 'valid' ignored}}
+[[,,,static, class, namespace,, inline, constexpr, mutable,, bitand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr; // expected-warning {{unknown attribute 'static' ignored}} \
+ // expected-warning {{unknown attribute 'class' ignored}} \
+ // expected-warning {{unknown attribute 'namespace' ignored}} \
+ // expected-warning {{unknown attribute 'inline' ignored}} \
+ // expected-warning {{unknown attribute 'constexpr' ignored}} \
+ // expected-warning {{unknown attribute 'mutable' ignored}} \
+ // expected-warning {{unknown attribute 'bitand' ignored}} \
+ // expected-warning {{unknown attribute 'compl' ignored}}
[[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected ']'}}
void fn_attr () [[]];
void noexcept_fn_attr () noexcept [[]];
@@ -212,3 +217,16 @@ enum class __attribute__((visibility("hidden"))) SecretKeepers {
one, /* rest are deprecated */ two, three
};
enum class [[]] EvenMoreSecrets {};
+
+namespace arguments {
+ // FIXME: remove the sema warnings after migrating existing gnu attributes to c++11 syntax.
+ void f(const char*, ...) [[gnu::format(printf, 1, 2)]]; // expected-warning {{unknown attribute 'format' ignored}}
+ void g() [[unknown::foo(currently arguments of attributes from unknown namespace other than 'gnu' namespace are ignored... blah...)]]; // expected-warning {{unknown attribute 'foo' ignored}}
+}
+
+// forbid attributes on decl specifiers
+unsigned [[gnu::used]] static int [[gnu::unused]] v1; // expected-warning {{attribute 'unused' ignored, because it is not attached to a declaration}} \
+ expected-error {{an attribute list cannot appear here}}
+typedef [[gnu::used]] unsigned long [[gnu::unused]] v2; // expected-warning {{attribute 'unused' ignored, because it is not attached to a declaration}} \
+ expected-error {{an attribute list cannot appear here}}
+int [[carries_dependency]] foo(int [[carries_dependency]] x); // expected-warning 2{{attribute 'carries_dependency' ignored, because it is not attached to a declaration}}
diff --git a/test/Parser/cxx0x-condition.cpp b/test/Parser/cxx0x-condition.cpp
index e45cd866ff21..8b64bcf1273d 100644
--- a/test/Parser/cxx0x-condition.cpp
+++ b/test/Parser/cxx0x-condition.cpp
@@ -27,10 +27,11 @@ void f() {
if (S b(n) = 0) {} // expected-error {{a function type is not allowed here}}
if (S b(n) == 0) {} // expected-error {{a function type is not allowed here}} expected-error {{did you mean '='?}}
- if (S{a}) {} // ok
- if (S a{a}) {} // ok
- if (S a = {a}) {} // ok
- if (S a == {a}) {} // expected-error {{did you mean '='?}}
+ S s(a);
+ if (S{s}) {} // ok
+ if (S a{s}) {} // ok
+ if (S a = {s}) {} // ok
+ if (S a == {s}) {} // expected-error {{did you mean '='?}}
if (S(b){a}) {} // ok
if (S(b) = {a}) {} // ok
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index a6fc49cb9e9d..3af73f95c78f 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -std=c++11 -pedantic %s
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c++11 -pedantic-errors %s
// Make sure we know these are legitimate commas and not typos for ';'.
namespace Commas {
@@ -23,8 +23,14 @@ class ExtraSemiAfterMemFn {
void f() = delete // expected-error {{expected ';' after delete}}
void g() = delete; // ok
void h() = delete;; // ok
- void i() = delete;;; // expected-warning {{extra ';' after member function definition}}
+ void i() = delete;;; // expected-error {{extra ';' after member function definition}}
};
-int *const const p = 0; // ok
-const const int *q = 0; // expected-warning {{duplicate 'const' declaration specifier}}
+int *const const p = 0; // expected-error {{duplicate 'const' declaration specifier}}
+const const int *q = 0; // expected-error {{duplicate 'const' declaration specifier}}
+
+struct MultiCV {
+ void f() const const; // expected-error {{duplicate 'const' declaration specifier}}
+};
+
+static_assert(something, ""); // expected-error {{undeclared identifier}}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index 7e9d4751e6ef..642c69a532ee 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -26,6 +26,7 @@ class C {
[] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
[] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
+ [](int) -> {}; // PR13652 expected-error {{expected a type}}
return 1;
}
@@ -33,7 +34,7 @@ class C {
typedef int T;
const int b = 0;
const int c = 1;
- int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from 'C::<lambda}}
+ int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '<lambda}}
int a2[1] = {[b] = 1 };
int a3[1] = {[b,c] = 1 }; // expected-error{{expected body of lambda expression}}
int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
diff --git a/test/Parser/cxx0x-override-control-keywords.cpp b/test/Parser/cxx0x-override-control-keywords.cpp
index 444862a5c853..be79db36e0df 100644
--- a/test/Parser/cxx0x-override-control-keywords.cpp
+++ b/test/Parser/cxx0x-override-control-keywords.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
struct Base {
virtual void override();
diff --git a/test/Parser/cxx11-brace-initializers.cpp b/test/Parser/cxx11-brace-initializers.cpp
new file mode 100644
index 000000000000..a2102056bc1a
--- /dev/null
+++ b/test/Parser/cxx11-brace-initializers.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
+
+struct S {
+ S(int, int) {}
+};
+
+void f(int, S const&, int) {}
+
+void test1()
+{
+ S X1{1, 1,};
+ S X2 = {1, 1,};
+
+ f(0, {1, 1}, 0);
+}
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index fab56218eb84..f26db7989f14 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -2,53 +2,78 @@
void foo(int i) {
- [[unknown_attribute]] ;
- [[unknown_attribute]] { }
- [[unknown_attribute]] if (0) { }
- [[unknown_attribute]] for (;;);
- [[unknown_attribute]] do {
- [[unknown_attribute]] continue;
+ [[unknown_attribute]] ; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] { } // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] if (0) { } // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] for (;;); // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] do { // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] continue; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
} while (0);
- [[unknown_attribute]] while (0);
+ [[unknown_attribute]] while (0); // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
- [[unknown_attribute]] switch (i) {
- [[unknown_attribute]] case 0:
- [[unknown_attribute]] default:
- [[unknown_attribute]] break;
+ [[unknown_attribute]] switch (i) { // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] case 0: // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] default: // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] break; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
}
- [[unknown_attribute]] goto here;
- [[unknown_attribute]] here:
+ [[unknown_attribute]] goto here; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+ [[unknown_attribute]] here: // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
- [[unknown_attribute]] try {
+ [[unknown_attribute]] try { // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
} catch (...) {
}
- [[unknown_attribute]] return;
-
+ [[unknown_attribute]] return; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+
alignas(8) ; // expected-warning {{attribute aligned cannot be specified on a statement}}
[[noreturn]] { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
[[noreturn]] if (0) { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
[[noreturn]] for (;;); // expected-warning {{attribute noreturn cannot be specified on a statement}}
[[noreturn]] do { // expected-warning {{attribute noreturn cannot be specified on a statement}}
- [[unavailable]] continue; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
+ [[unavailable]] continue; // expected-warning {{unknown attribute 'unavailable' ignored}}
+ } while (0);
+ [[unknown_attributqqq]] while (0); // expected-warning {{unknown attribute 'unknown_attributqqq' ignored}}
+ // TODO: remove 'qqq' part and enjoy 'empty loop body' warning here (DiagnoseEmptyLoopBody)
+
+ [[unknown_attribute]] while (0); // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
+
+ [[unused]] switch (i) { // expected-warning {{unknown attribute 'unused' ignored}}
+ [[uuid]] case 0: // expected-warning {{unknown attribute 'uuid' ignored}}
+ [[visibility]] default: // expected-warning {{unknown attribute 'visibility' ignored}}
+ [[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ }
+
+ [[fastcall]] goto there; // expected-warning {{unknown attribute 'fastcall' ignored}}
+ [[noinline]] there: // expected-warning {{unknown attribute 'noinline' ignored}}
+
+ [[lock_returned]] try { // expected-warning {{unknown attribute 'lock_returned' ignored}}
+ } catch (...) {
+ }
+
+ [[weakref]] return; // expected-warning {{unknown attribute 'weakref' ignored}}
+
+ [[carries_dependency]] ; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] if (0) { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] for (;;); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] do { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] continue; // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
} while (0);
- [[unknown_attributqqq]] while (0); // TODO: remove 'qqq' part and enjoy 'empty loop body' warning here (DiagnoseEmptyLoopBody)
- [[unknown_attribute]] while (0); // no warning here yet, just an unknown attribute
+ [[carries_dependency]] while (0); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[unused]] switch (i) { // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
- [[uuid]] case 0: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
- [[visibility]] default: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
+ [[carries_dependency]] switch (i) { // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
+ [[carries_dependency]] case 0: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] default: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
[[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
}
- [[fastcall]] goto there; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
- [[noinline]] there: // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
+ [[carries_dependency]] goto here; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[lock_returned]] try { // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
+ [[carries_dependency]] try { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
} catch (...) {
}
- [[weakref]] return; // TODO: only noreturn, alignas and carries_dependency are parsed in C++ 11 syntax at the moment, hence no warning here
+ [[carries_dependency]] return; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
}
diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp
index 49fea01eefe9..613c0b9ec6ee 100644
--- a/test/Parser/cxx11-user-defined-literals.cpp
+++ b/test/Parser/cxx11-user-defined-literals.cpp
@@ -102,9 +102,10 @@ void operator R"xyzzy()xyzzy" _foo(long double); // ok
void operator"" "" R"()" "" _foo(const char *); // ok
+void operator ""_no_space(const char *); // ok
+
// Ensure we diagnose the bad cases.
void operator "\0" _non_empty(const char *); // expected-error {{must be '""'}}
-void operator ""_no_space(const char *); // expected-error {{C++11 requires a space}}
void operator L"" _not_char(const char *); // expected-error {{cannot have an encoding prefix}}
void operator "" ""
U"" // expected-error {{cannot have an encoding prefix}}
diff --git a/test/Parser/empty-translation-unit.c b/test/Parser/empty-translation-unit.c
index 0dbf37e447c3..04e57f69ce87 100644
--- a/test/Parser/empty-translation-unit.c
+++ b/test/Parser/empty-translation-unit.c
@@ -7,4 +7,4 @@
#define A_MACRO_IS_NOT_GOOD_ENOUGH 1
// In C we should get this warning, but in C++ we shouldn't.
-// expected-warning{{ISO C requires a translation unit to contain at least one declaration.}}
+// expected-warning{{ISO C requires a translation unit to contain at least one declaration}}
diff --git a/test/Parser/encode.m b/test/Parser/encode.m
index 7b8022e78dc0..056cee1ac06b 100644
--- a/test/Parser/encode.m
+++ b/test/Parser/encode.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int main(void) {
const char ch = @encode(char *)[0];
diff --git a/test/Parser/enhanced-proto-1.m b/test/Parser/enhanced-proto-1.m
index fa6e4138f1c1..bad5c7c258d2 100644
--- a/test/Parser/enhanced-proto-1.m
+++ b/test/Parser/enhanced-proto-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol MyProto1
@optional
diff --git a/test/Parser/if-scope-c90.c b/test/Parser/if-scope-c90.c
index c368fabb80ed..61119eacc9ee 100644
--- a/test/Parser/if-scope-c90.c
+++ b/test/Parser/if-scope-c90.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c90 %s
+// expected-no-diagnostics
int f (int z)
{
diff --git a/test/Parser/knr_parameter_attributes.c b/test/Parser/knr_parameter_attributes.c
index fb975cbf3327..b11a75ed2075 100644
--- a/test/Parser/knr_parameter_attributes.c
+++ b/test/Parser/knr_parameter_attributes.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -W -Wall -Werror -verify %s
+// expected-no-diagnostics
int f(int i __attribute__((__unused__)))
{
diff --git a/test/Parser/ms-inline-asm.c b/test/Parser/ms-inline-asm.c
index 5326ce4d2417..0e8b317e56b0 100644
--- a/test/Parser/ms-inline-asm.c
+++ b/test/Parser/ms-inline-asm.c
@@ -6,7 +6,7 @@
void t1(void) { M } // expected-warning {{MS-style inline assembly is not supported}}
void t2(void) { __asm int 0x2c } // expected-warning {{MS-style inline assembly is not supported}}
void t3(void) { __asm M2 0x2c } // expected-warning {{MS-style inline assembly is not supported}}
-void* t4(void) { __asm mov eax, fs:[0x10] } // expected-warning {{MS-style inline assembly is not supported}}
+void t4(void) { __asm mov eax, fs:[0x10] } // expected-warning {{MS-style inline assembly is not supported}}
void t5() {
__asm { // expected-warning {{MS-style inline assembly is not supported}}
int 0x2c ; } asm comments are fun! }{
@@ -20,7 +20,7 @@ int t6() {
__asm int 4 // expected-warning {{MS-style inline assembly is not supported}}
return 10;
}
-int t7() {
+void t7() {
__asm { // expected-warning {{MS-style inline assembly is not supported}}
push ebx
mov ebx, 0x07
@@ -34,5 +34,5 @@ void t9() {
__asm nop __asm nop ; __asm nop // expected-warning {{MS-style inline assembly is not supported}}
}
int t_fail() { // expected-note {{to match this}}
- __asm
- __asm { // expected-error 3 {{expected}} expected-note {{to match this}}
+ __asm // expected-warning {{MS-style inline assembly is not supported}}
+ __asm { // expected-warning {{MS-style inline assembly is not supported}} expected-error 3 {{expected}} expected-note {{to match this}}
diff --git a/test/Parser/namelookup-bug-1.c b/test/Parser/namelookup-bug-1.c
index 8667a71657cc..31d17a9d7de9 100644
--- a/test/Parser/namelookup-bug-1.c
+++ b/test/Parser/namelookup-bug-1.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
typedef int Object;
diff --git a/test/Parser/namelookup-bug-2.c b/test/Parser/namelookup-bug-2.c
index 84850ffafb17..4598da05cd02 100644
--- a/test/Parser/namelookup-bug-2.c
+++ b/test/Parser/namelookup-bug-2.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
typedef int Object;
diff --git a/test/Parser/namespaces.cpp b/test/Parser/namespaces.cpp
index b8c7819a019f..6491cfd446b3 100644
--- a/test/Parser/namespaces.cpp
+++ b/test/Parser/namespaces.cpp
@@ -6,3 +6,7 @@ namespace g { enum { o = 0 }; }
void foo() {
namespace a { typedef g::o o; } // expected-error{{namespaces can only be defined in global or namespace scope}}
}
+
+// PR14085
+namespace PR14085 {}
+namespace = PR14085; // expected-error {{expected identifier}}
diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm
index 1b9bf66fad9a..ad5420828682 100644
--- a/test/Parser/objcxx11-attributes.mm
+++ b/test/Parser/objcxx11-attributes.mm
@@ -31,9 +31,13 @@ void f(X *noreturn) {
// An attribute is OK.
[[]];
- [[int(), noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}}
- [[class, test(foo 'x' bar),,,]];
- [[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}}
+ [[int(), noreturn]]; // expected-warning {{unknown attribute 'int' ignored}} \
+ // expected-warning {{attribute noreturn cannot be specified on a statement}}
+ [[class, test(foo 'x' bar),,,]]; // expected-warning {{unknown attribute 'test' ignored}}\
+ // expected-warning {{unknown attribute 'class' ignored}}
+
+ [[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}} \
+ expected-warning {{unknown attribute 'bitand' ignored}}
// FIXME: Suppress vexing parse warning
[[noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
@@ -52,7 +56,11 @@ void f(X *noreturn) {
}
template<typename...Ts> void f(Ts ...x) {
- [[test::foo(bar, baz)...]];
- [[used(x)...]];
+ [[test::foo(bar, baz)...]]; // expected-error {{attribute 'foo' cannot be used as an attribute pack}} \
+ // expected-warning {{unknown attribute 'foo' ignored}}
+
+ [[used(x)...]]; // expected-error {{attribute 'used' cannot be used as an attribute pack}} \
+ // expected-warning {{unknown attribute 'used' ignored}}
+
[[x...] { return [ X alloc ]; }() init];
}
diff --git a/test/Parser/opencl-kernel.cl b/test/Parser/opencl-kernel.cl
index 3abb62b6169c..01c7ed6b5ab6 100644
--- a/test/Parser/opencl-kernel.cl
+++ b/test/Parser/opencl-kernel.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
__kernel void test()
{
diff --git a/test/Parser/parmvardecl_conversion.c b/test/Parser/parmvardecl_conversion.c
index 9fa8a6880a21..f6afd1205879 100644
--- a/test/Parser/parmvardecl_conversion.c
+++ b/test/Parser/parmvardecl_conversion.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
void f (int p[]) { p++; }
diff --git a/test/Parser/pragma-fp-contract.c b/test/Parser/pragma-fp-contract.c
new file mode 100644
index 000000000000..568c0a0a88ba
--- /dev/null
+++ b/test/Parser/pragma-fp-contract.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+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}} */
+#pragma STDC FP_CONTRACT ON
+}
+
+void f2(void) {
+ #pragma STDC FP_CONTRACT OFF
+ #pragma STDC FP_CONTRACT ON
+}
diff --git a/test/Parser/pragma-options.cpp b/test/Parser/pragma-options.cpp
new file mode 100644
index 000000000000..84cd38dfb3cd
--- /dev/null
+++ b/test/Parser/pragma-options.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+class C {
+#pragma options align=natural
+};
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
index ff687583c253..732b9aee1632 100644
--- a/test/Parser/recovery.cpp
+++ b/test/Parser/recovery.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
8gi///===--- recovery.cpp ---===// // expected-error {{unqualified-id}}
namespace Std { // expected-note {{here}}
@@ -23,12 +23,15 @@ void g() {
struct S {
int a, b, c;
S();
+ int x // expected-error {{expected ';'}}
+ friend void f()
};
8S::S() : a{ 5 }, b{ 6 }, c{ 2 } { // expected-error {{unqualified-id}}
return;
}
int k;
-int l = k;
+int l = k // expected-error {{expected ';'}}
+constexpr int foo();
5int m = { l }, n = m; // expected-error {{unqualified-id}}
diff --git a/test/Parser/recursion-limits.cpp b/test/Parser/recursion-limits.cpp
index ea25dea0dacc..bb7354f550cc 100644
--- a/test/Parser/recursion-limits.cpp
+++ b/test/Parser/recursion-limits.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify
+// expected-no-diagnostics
class outer {
class inner1 { inner1(); };
class inner2 { inner2(); };
diff --git a/test/Parser/selector-1.m b/test/Parser/selector-1.m
index 5ba2da9931cf..3e2a86d9e9b2 100644
--- a/test/Parser/selector-1.m
+++ b/test/Parser/selector-1.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://8366474
int main() {
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
index 3a123d6001bd..8215f4c92a60 100644
--- a/test/Parser/statements.c
+++ b/test/Parser/statements.c
@@ -62,3 +62,18 @@ void test8() {
// Should not skip '}' and produce a "expected '}'" error.
undecl // expected-error {{use of undeclared identifier 'undecl'}}
}
+
+int test9() {
+ int T[] = {1, 2, };
+
+ int X;
+ X = 0, // expected-error {{expected ';' after expression}}
+ {
+ }
+
+ X = 0, // expected-error {{expected ';' after expression}}
+ if (0)
+ ;
+
+ return 4, // expected-error {{expected ';' after return statement}}
+}
diff --git a/test/Parser/top-level-semi-cxx0x.cpp b/test/Parser/top-level-semi-cxx0x.cpp
index be342a225704..472686e8b345 100644
--- a/test/Parser/top-level-semi-cxx0x.cpp
+++ b/test/Parser/top-level-semi-cxx0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify %s
+// expected-no-diagnostics
void foo();
diff --git a/test/Parser/types.c b/test/Parser/types.c
index 53b9dd5e9eca..db8c08303f57 100644
--- a/test/Parser/types.c
+++ b/test/Parser/types.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// Test the X can be overloaded inside the struct.
typedef int X;
diff --git a/test/Preprocessor/comment_save_if.c b/test/Preprocessor/comment_save_if.c
index 4946122a3f0c..b972d914ebdb 100644
--- a/test/Preprocessor/comment_save_if.c
+++ b/test/Preprocessor/comment_save_if.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -E -CC -pedantic -verify
+// expected-no-diagnostics
#if 1 /*bar */
diff --git a/test/Preprocessor/cxx_true.cpp b/test/Preprocessor/cxx_true.cpp
index b123e0cb681a..39cb349b2a81 100644
--- a/test/Preprocessor/cxx_true.cpp
+++ b/test/Preprocessor/cxx_true.cpp
@@ -1,7 +1,9 @@
/* RUN: %clang_cc1 -E %s -x c++ | grep block_1
RUN: %clang_cc1 -E %s -x c++ | not grep block_2
RUN: %clang_cc1 -E %s -x c | not grep block
+ RUN: %clang_cc1 -E %s -x c++ -verify -Wundef
*/
+// expected-no-diagnostics
#if true
block_1
diff --git a/test/Preprocessor/expr_define_expansion.c b/test/Preprocessor/expr_define_expansion.c
index 38c0384092ae..3e5a2c4b0e67 100644
--- a/test/Preprocessor/expr_define_expansion.c
+++ b/test/Preprocessor/expr_define_expansion.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -E -CC -pedantic -verify
+// expected-no-diagnostics
#define FOO && 1
#if defined FOO FOO
diff --git a/test/Preprocessor/expr_multichar.c b/test/Preprocessor/expr_multichar.c
index 8ab12d9ab8aa..39155e41501e 100644
--- a/test/Preprocessor/expr_multichar.c
+++ b/test/Preprocessor/expr_multichar.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 < %s -E -verify -triple i686-pc-linux-gnu
+// expected-no-diagnostics
#if (('1234' >> 24) != '1')
#error Bad multichar constant calculation!
diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c
index 13c8d566223f..10f7795fc34a 100644
--- a/test/Preprocessor/has_include.c
+++ b/test/Preprocessor/has_include.c
@@ -67,7 +67,7 @@
// Try badly formed expressions.
// FIXME: We can recover better in almost all of these cases. (PR13335)
-// expected-error@+1 {{missing '(' after '__has_include'}} expected-error@+1 {{expected end of line}}
+// expected-error@+1 {{missing '(' after '__has_include'}}
#if __has_include "stdint.h")
#endif
@@ -83,11 +83,11 @@
#if __has_include)
#endif
-// expected-error@+1 {{missing '(' after '__has_include'}} expected-error@+1 {{token is not a valid binary operator in a preprocessor subexpression}}
+// expected-error@+1 {{missing '(' after '__has_include'}}
#if __has_include<stdint.h>)
#endif
-// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} expected-warning@+1 {{missing terminating '"' character}}
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} expected-warning@+1 {{missing terminating '"' character}} expected-error@+1 {{invalid token at start of a preprocessor expression}}
#if __has_include("stdint.h)
#endif
@@ -99,11 +99,25 @@
#if __has_include(stdint.h>)
#endif
+// expected-error@+1 {{missing '(' after '__has_include'}}
+__has_include
+
+// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}}
+#if __has_include("stdint.h"
+#endif
-// FIXME: These test cases cause the compiler to crash. (PR13334)
-//#if __has_include("stdint.h"
-//#if __has_include(
-//#if __has_include
-//#if __has_include(<stdint.h>
-//#if __has_include(<stdint.h)
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} // expected-error@+1 {{expected value in expression}}
+#if __has_include(
+#endif
+// expected-error@+1 {{missing '(' after '__has_include'}} // expected-error@+1 {{expected value in expression}}
+#if __has_include
+#endif
+
+// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}}
+#if __has_include(<stdint.h>
+#endif
+
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} // expected-error@+1 {{expected value in expression}}
+#if __has_include(<stdint.h)
+#endif
diff --git a/test/Preprocessor/import_self.c b/test/Preprocessor/import_self.c
index 8ba0b19c94ae..494d95f0f8d6 100644
--- a/test/Preprocessor/import_self.c
+++ b/test/Preprocessor/import_self.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E -I. %s | grep BODY_OF_FILE | wc -l | grep 1
+// RUN: %clang_cc1 -E -I%S %s | grep BODY_OF_FILE | wc -l | grep 1
// This #import should have no effect, as we're importing the current file.
#import <import_self.c>
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index e7321e063099..33a21a3ef9d6 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -212,19 +212,19 @@
// ARM:#define __INTPTR_TYPE__ long int
// ARM:#define __INTPTR_WIDTH__ 32
// ARM:#define __INT_MAX__ 2147483647
-// ARM:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// ARM:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// ARM:#define __LDBL_DIG__ 15
-// ARM:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// ARM:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// ARM:#define __LDBL_HAS_DENORM__ 1
// ARM:#define __LDBL_HAS_INFINITY__ 1
// ARM:#define __LDBL_HAS_QUIET_NAN__ 1
// ARM:#define __LDBL_MANT_DIG__ 53
// ARM:#define __LDBL_MAX_10_EXP__ 308
// ARM:#define __LDBL_MAX_EXP__ 1024
-// ARM:#define __LDBL_MAX__ 1.7976931348623157e+308
+// ARM:#define __LDBL_MAX__ 1.7976931348623157e+308L
// ARM:#define __LDBL_MIN_10_EXP__ (-307)
// ARM:#define __LDBL_MIN_EXP__ (-1021)
-// ARM:#define __LDBL_MIN__ 2.2250738585072014e-308
+// ARM:#define __LDBL_MIN__ 2.2250738585072014e-308L
// ARM:#define __LITTLE_ENDIAN__ 1
// ARM:#define __LONG_LONG_MAX__ 9223372036854775807LL
// ARM:#define __LONG_MAX__ 2147483647L
@@ -260,6 +260,215 @@
// ARM:#define __WINT_WIDTH__ 32
// ARM:#define __arm 1
// ARM:#define __arm__ 1
+
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-linux-gnueabi -target-feature +soft-float -target-feature +soft-float-abi < /dev/null | FileCheck -check-prefix ARMEABISOFTFP %s
+//
+// ARM-NOT:#define _LP64
+// ARMEABISOFTFP:#define __APCS_32__ 1
+// ARMEABISOFTFP:#define __ARMEL__ 1
+// ARMEABISOFTFP:#define __ARM_ARCH 6
+// ARMEABISOFTFP:#define __ARM_ARCH_6J__ 1
+// ARMEABISOFTFP:#define __ARM_EABI__ 1
+// ARMEABISOFTFP:#define __ARM_PCS 1
+// ARMEABISOFTFP-NOT:#define __ARM_PCS_VFP 1
+// ARMEABISOFTFP:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// ARMEABISOFTFP:#define __CHAR16_TYPE__ unsigned short
+// ARMEABISOFTFP:#define __CHAR32_TYPE__ unsigned int
+// ARMEABISOFTFP:#define __CHAR_BIT__ 8
+// ARMEABISOFTFP:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// ARMEABISOFTFP:#define __DBL_DIG__ 15
+// ARMEABISOFTFP:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// ARMEABISOFTFP:#define __DBL_HAS_DENORM__ 1
+// ARMEABISOFTFP:#define __DBL_HAS_INFINITY__ 1
+// ARMEABISOFTFP:#define __DBL_HAS_QUIET_NAN__ 1
+// ARMEABISOFTFP:#define __DBL_MANT_DIG__ 53
+// ARMEABISOFTFP:#define __DBL_MAX_10_EXP__ 308
+// ARMEABISOFTFP:#define __DBL_MAX_EXP__ 1024
+// ARMEABISOFTFP:#define __DBL_MAX__ 1.7976931348623157e+308
+// ARMEABISOFTFP:#define __DBL_MIN_10_EXP__ (-307)
+// ARMEABISOFTFP:#define __DBL_MIN_EXP__ (-1021)
+// ARMEABISOFTFP:#define __DBL_MIN__ 2.2250738585072014e-308
+// ARMEABISOFTFP:#define __DECIMAL_DIG__ 17
+// ARMEABISOFTFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// ARMEABISOFTFP:#define __FLT_DIG__ 6
+// ARMEABISOFTFP:#define __FLT_EPSILON__ 1.19209290e-7F
+// ARMEABISOFTFP:#define __FLT_EVAL_METHOD__ 0
+// ARMEABISOFTFP:#define __FLT_HAS_DENORM__ 1
+// ARMEABISOFTFP:#define __FLT_HAS_INFINITY__ 1
+// ARMEABISOFTFP:#define __FLT_HAS_QUIET_NAN__ 1
+// ARMEABISOFTFP:#define __FLT_MANT_DIG__ 24
+// ARMEABISOFTFP:#define __FLT_MAX_10_EXP__ 38
+// ARMEABISOFTFP:#define __FLT_MAX_EXP__ 128
+// ARMEABISOFTFP:#define __FLT_MAX__ 3.40282347e+38F
+// ARMEABISOFTFP:#define __FLT_MIN_10_EXP__ (-37)
+// ARMEABISOFTFP:#define __FLT_MIN_EXP__ (-125)
+// ARMEABISOFTFP:#define __FLT_MIN__ 1.17549435e-38F
+// ARMEABISOFTFP:#define __FLT_RADIX__ 2
+// ARMEABISOFTFP:#define __INT16_TYPE__ short
+// ARMEABISOFTFP:#define __INT32_TYPE__ int
+// ARMEABISOFTFP:#define __INT64_C_SUFFIX__ LL
+// ARMEABISOFTFP:#define __INT64_TYPE__ long long int
+// ARMEABISOFTFP:#define __INT8_TYPE__ char
+// ARMEABISOFTFP:#define __INTMAX_MAX__ 9223372036854775807LL
+// ARMEABISOFTFP:#define __INTMAX_TYPE__ long long int
+// ARMEABISOFTFP:#define __INTMAX_WIDTH__ 64
+// ARMEABISOFTFP:#define __INTPTR_TYPE__ long int
+// ARMEABISOFTFP:#define __INTPTR_WIDTH__ 32
+// ARMEABISOFTFP:#define __INT_MAX__ 2147483647
+// ARMEABISOFTFP:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
+// ARMEABISOFTFP:#define __LDBL_DIG__ 15
+// ARMEABISOFTFP:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
+// ARMEABISOFTFP:#define __LDBL_HAS_DENORM__ 1
+// ARMEABISOFTFP:#define __LDBL_HAS_INFINITY__ 1
+// ARMEABISOFTFP:#define __LDBL_HAS_QUIET_NAN__ 1
+// ARMEABISOFTFP:#define __LDBL_MANT_DIG__ 53
+// ARMEABISOFTFP:#define __LDBL_MAX_10_EXP__ 308
+// ARMEABISOFTFP:#define __LDBL_MAX_EXP__ 1024
+// ARMEABISOFTFP:#define __LDBL_MAX__ 1.7976931348623157e+308L
+// ARMEABISOFTFP:#define __LDBL_MIN_10_EXP__ (-307)
+// ARMEABISOFTFP:#define __LDBL_MIN_EXP__ (-1021)
+// ARMEABISOFTFP:#define __LDBL_MIN__ 2.2250738585072014e-308L
+// ARMEABISOFTFP:#define __LITTLE_ENDIAN__ 1
+// ARMEABISOFTFP:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// ARMEABISOFTFP:#define __LONG_MAX__ 2147483647L
+// ARMEABISOFTFP-NOT:#define __LP64__
+// ARMEABISOFTFP:#define __POINTER_WIDTH__ 32
+// ARMEABISOFTFP:#define __PTRDIFF_TYPE__ int
+// ARMEABISOFTFP:#define __PTRDIFF_WIDTH__ 32
+// ARMEABISOFTFP:#define __REGISTER_PREFIX__
+// ARMEABISOFTFP:#define __SCHAR_MAX__ 127
+// ARMEABISOFTFP:#define __SHRT_MAX__ 32767
+// ARMEABISOFTFP:#define __SIG_ATOMIC_WIDTH__ 32
+// ARMEABISOFTFP:#define __SIZEOF_DOUBLE__ 8
+// ARMEABISOFTFP:#define __SIZEOF_FLOAT__ 4
+// ARMEABISOFTFP:#define __SIZEOF_INT__ 4
+// ARMEABISOFTFP:#define __SIZEOF_LONG_DOUBLE__ 8
+// ARMEABISOFTFP:#define __SIZEOF_LONG_LONG__ 8
+// ARMEABISOFTFP:#define __SIZEOF_LONG__ 4
+// ARMEABISOFTFP:#define __SIZEOF_POINTER__ 4
+// ARMEABISOFTFP:#define __SIZEOF_PTRDIFF_T__ 4
+// ARMEABISOFTFP:#define __SIZEOF_SHORT__ 2
+// ARMEABISOFTFP:#define __SIZEOF_SIZE_T__ 4
+// ARMEABISOFTFP:#define __SIZEOF_WCHAR_T__ 4
+// ARMEABISOFTFP:#define __SIZEOF_WINT_T__ 4
+// ARMEABISOFTFP:#define __SIZE_TYPE__ unsigned int
+// ARMEABISOFTFP:#define __SIZE_WIDTH__ 32
+// ARMEABISOFTFP:#define __SOFTFP__ 1
+// ARMEABISOFTFP:#define __THUMB_INTERWORK__ 1
+// ARMEABISOFTFP:#define __UINTMAX_TYPE__ long long unsigned int
+// ARMEABISOFTFP:#define __USER_LABEL_PREFIX__
+// ARMEABISOFTFP:#define __WCHAR_MAX__ 4294967295U
+// ARMEABISOFTFP:#define __WCHAR_TYPE__ unsigned int
+// ARMEABISOFTFP:#define __WCHAR_WIDTH__ 32
+// ARMEABISOFTFP:#define __WINT_TYPE__ unsigned int
+// ARMEABISOFTFP:#define __WINT_WIDTH__ 32
+// ARMEABISOFTFP:#define __arm 1
+// ARMEABISOFTFP:#define __arm__ 1
+
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-linux-gnueabi < /dev/null | FileCheck -check-prefix ARMEABIHARDFP %s
+//
+// ARM-NOT:#define _LP64
+// ARMEABIHARDFP:#define __APCS_32__ 1
+// ARMEABIHARDFP:#define __ARMEL__ 1
+// ARMEABIHARDFP:#define __ARM_ARCH 6
+// ARMEABIHARDFP:#define __ARM_ARCH_6J__ 1
+// ARMEABIHARDFP:#define __ARM_EABI__ 1
+// ARMEABIHARDFP:#define __ARM_PCS 1
+// ARMEABIHARDFP:#define __ARM_PCS_VFP 1
+// ARMEABIHARDFP:#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// ARMEABIHARDFP:#define __CHAR16_TYPE__ unsigned short
+// ARMEABIHARDFP:#define __CHAR32_TYPE__ unsigned int
+// ARMEABIHARDFP:#define __CHAR_BIT__ 8
+// ARMEABIHARDFP:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// ARMEABIHARDFP:#define __DBL_DIG__ 15
+// ARMEABIHARDFP:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// ARMEABIHARDFP:#define __DBL_HAS_DENORM__ 1
+// ARMEABIHARDFP:#define __DBL_HAS_INFINITY__ 1
+// ARMEABIHARDFP:#define __DBL_HAS_QUIET_NAN__ 1
+// ARMEABIHARDFP:#define __DBL_MANT_DIG__ 53
+// ARMEABIHARDFP:#define __DBL_MAX_10_EXP__ 308
+// ARMEABIHARDFP:#define __DBL_MAX_EXP__ 1024
+// ARMEABIHARDFP:#define __DBL_MAX__ 1.7976931348623157e+308
+// ARMEABIHARDFP:#define __DBL_MIN_10_EXP__ (-307)
+// ARMEABIHARDFP:#define __DBL_MIN_EXP__ (-1021)
+// ARMEABIHARDFP:#define __DBL_MIN__ 2.2250738585072014e-308
+// ARMEABIHARDFP:#define __DECIMAL_DIG__ 17
+// ARMEABIHARDFP:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// ARMEABIHARDFP:#define __FLT_DIG__ 6
+// ARMEABIHARDFP:#define __FLT_EPSILON__ 1.19209290e-7F
+// ARMEABIHARDFP:#define __FLT_EVAL_METHOD__ 0
+// ARMEABIHARDFP:#define __FLT_HAS_DENORM__ 1
+// ARMEABIHARDFP:#define __FLT_HAS_INFINITY__ 1
+// ARMEABIHARDFP:#define __FLT_HAS_QUIET_NAN__ 1
+// ARMEABIHARDFP:#define __FLT_MANT_DIG__ 24
+// ARMEABIHARDFP:#define __FLT_MAX_10_EXP__ 38
+// ARMEABIHARDFP:#define __FLT_MAX_EXP__ 128
+// ARMEABIHARDFP:#define __FLT_MAX__ 3.40282347e+38F
+// ARMEABIHARDFP:#define __FLT_MIN_10_EXP__ (-37)
+// ARMEABIHARDFP:#define __FLT_MIN_EXP__ (-125)
+// ARMEABIHARDFP:#define __FLT_MIN__ 1.17549435e-38F
+// ARMEABIHARDFP:#define __FLT_RADIX__ 2
+// ARMEABIHARDFP:#define __INT16_TYPE__ short
+// ARMEABIHARDFP:#define __INT32_TYPE__ int
+// ARMEABIHARDFP:#define __INT64_C_SUFFIX__ LL
+// ARMEABIHARDFP:#define __INT64_TYPE__ long long int
+// ARMEABIHARDFP:#define __INT8_TYPE__ char
+// ARMEABIHARDFP:#define __INTMAX_MAX__ 9223372036854775807LL
+// ARMEABIHARDFP:#define __INTMAX_TYPE__ long long int
+// ARMEABIHARDFP:#define __INTMAX_WIDTH__ 64
+// ARMEABIHARDFP:#define __INTPTR_TYPE__ long int
+// ARMEABIHARDFP:#define __INTPTR_WIDTH__ 32
+// ARMEABIHARDFP:#define __INT_MAX__ 2147483647
+// ARMEABIHARDFP:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
+// ARMEABIHARDFP:#define __LDBL_DIG__ 15
+// ARMEABIHARDFP:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
+// ARMEABIHARDFP:#define __LDBL_HAS_DENORM__ 1
+// ARMEABIHARDFP:#define __LDBL_HAS_INFINITY__ 1
+// ARMEABIHARDFP:#define __LDBL_HAS_QUIET_NAN__ 1
+// ARMEABIHARDFP:#define __LDBL_MANT_DIG__ 53
+// ARMEABIHARDFP:#define __LDBL_MAX_10_EXP__ 308
+// ARMEABIHARDFP:#define __LDBL_MAX_EXP__ 1024
+// ARMEABIHARDFP:#define __LDBL_MAX__ 1.7976931348623157e+308L
+// ARMEABIHARDFP:#define __LDBL_MIN_10_EXP__ (-307)
+// ARMEABIHARDFP:#define __LDBL_MIN_EXP__ (-1021)
+// ARMEABIHARDFP:#define __LDBL_MIN__ 2.2250738585072014e-308L
+// ARMEABIHARDFP:#define __LITTLE_ENDIAN__ 1
+// ARMEABIHARDFP:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// ARMEABIHARDFP:#define __LONG_MAX__ 2147483647L
+// ARMEABIHARDFP-NOT:#define __LP64__
+// ARMEABIHARDFP:#define __POINTER_WIDTH__ 32
+// ARMEABIHARDFP:#define __PTRDIFF_TYPE__ int
+// ARMEABIHARDFP:#define __PTRDIFF_WIDTH__ 32
+// ARMEABIHARDFP:#define __REGISTER_PREFIX__
+// ARMEABIHARDFP:#define __SCHAR_MAX__ 127
+// ARMEABIHARDFP:#define __SHRT_MAX__ 32767
+// ARMEABIHARDFP:#define __SIG_ATOMIC_WIDTH__ 32
+// ARMEABIHARDFP:#define __SIZEOF_DOUBLE__ 8
+// ARMEABIHARDFP:#define __SIZEOF_FLOAT__ 4
+// ARMEABIHARDFP:#define __SIZEOF_INT__ 4
+// ARMEABIHARDFP:#define __SIZEOF_LONG_DOUBLE__ 8
+// ARMEABIHARDFP:#define __SIZEOF_LONG_LONG__ 8
+// ARMEABIHARDFP:#define __SIZEOF_LONG__ 4
+// ARMEABIHARDFP:#define __SIZEOF_POINTER__ 4
+// ARMEABIHARDFP:#define __SIZEOF_PTRDIFF_T__ 4
+// ARMEABIHARDFP:#define __SIZEOF_SHORT__ 2
+// ARMEABIHARDFP:#define __SIZEOF_SIZE_T__ 4
+// ARMEABIHARDFP:#define __SIZEOF_WCHAR_T__ 4
+// ARMEABIHARDFP:#define __SIZEOF_WINT_T__ 4
+// ARMEABIHARDFP:#define __SIZE_TYPE__ unsigned int
+// ARMEABIHARDFP:#define __SIZE_WIDTH__ 32
+// ARMEABIHARDFP-NOT:#define __SOFTFP__ 1
+// ARMEABIHARDFP:#define __THUMB_INTERWORK__ 1
+// ARMEABIHARDFP:#define __UINTMAX_TYPE__ long long unsigned int
+// ARMEABIHARDFP:#define __USER_LABEL_PREFIX__
+// ARMEABIHARDFP:#define __WCHAR_MAX__ 4294967295U
+// ARMEABIHARDFP:#define __WCHAR_TYPE__ unsigned int
+// ARMEABIHARDFP:#define __WCHAR_WIDTH__ 32
+// ARMEABIHARDFP:#define __WINT_TYPE__ unsigned int
+// ARMEABIHARDFP:#define __WINT_WIDTH__ 32
+// ARMEABIHARDFP:#define __arm 1
+// ARMEABIHARDFP:#define __arm__ 1
+
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-none-none < /dev/null | FileCheck -check-prefix I386 %s
//
@@ -461,6 +670,8 @@
// MIPS32BE:#define _ABIO32 1
// MIPS32BE-NOT:#define _LP64
// MIPS32BE:#define _MIPSEB 1
+// MIPS32BE:#define _MIPS_ARCH "mips32"
+// MIPS32BE:#define _MIPS_ARCH_MIPS32 1
// MIPS32BE:#define _MIPS_SIM _ABIO32
// MIPS32BE:#define _MIPS_SZINT 32
// MIPS32BE:#define _MIPS_SZLONG 32
@@ -510,19 +721,19 @@
// MIPS32BE:#define __INTPTR_TYPE__ long int
// MIPS32BE:#define __INTPTR_WIDTH__ 32
// MIPS32BE:#define __INT_MAX__ 2147483647
-// MIPS32BE:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32BE:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// MIPS32BE:#define __LDBL_DIG__ 15
-// MIPS32BE:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32BE:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// MIPS32BE:#define __LDBL_HAS_DENORM__ 1
// MIPS32BE:#define __LDBL_HAS_INFINITY__ 1
// MIPS32BE:#define __LDBL_HAS_QUIET_NAN__ 1
// MIPS32BE:#define __LDBL_MANT_DIG__ 53
// MIPS32BE:#define __LDBL_MAX_10_EXP__ 308
// MIPS32BE:#define __LDBL_MAX_EXP__ 1024
-// MIPS32BE:#define __LDBL_MAX__ 1.7976931348623157e+308
+// MIPS32BE:#define __LDBL_MAX__ 1.7976931348623157e+308L
// MIPS32BE:#define __LDBL_MIN_10_EXP__ (-307)
// MIPS32BE:#define __LDBL_MIN_EXP__ (-1021)
-// MIPS32BE:#define __LDBL_MIN__ 2.2250738585072014e-308
+// MIPS32BE:#define __LDBL_MIN__ 2.2250738585072014e-308L
// MIPS32BE:#define __LONG_LONG_MAX__ 9223372036854775807LL
// MIPS32BE:#define __LONG_MAX__ 2147483647L
// MIPS32BE-NOT:#define __LP64__
@@ -575,6 +786,8 @@
// MIPS32EL:#define _ABIO32 1
// MIPS32EL-NOT:#define _LP64
// MIPS32EL:#define _MIPSEL 1
+// MIPS32EL:#define _MIPS_ARCH "mips32"
+// MIPS32EL:#define _MIPS_ARCH_MIPS32 1
// MIPS32EL:#define _MIPS_SIM _ABIO32
// MIPS32EL:#define _MIPS_SZINT 32
// MIPS32EL:#define _MIPS_SZLONG 32
@@ -624,19 +837,19 @@
// MIPS32EL:#define __INTPTR_TYPE__ long int
// MIPS32EL:#define __INTPTR_WIDTH__ 32
// MIPS32EL:#define __INT_MAX__ 2147483647
-// MIPS32EL:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32EL:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// MIPS32EL:#define __LDBL_DIG__ 15
-// MIPS32EL:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32EL:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// MIPS32EL:#define __LDBL_HAS_DENORM__ 1
// MIPS32EL:#define __LDBL_HAS_INFINITY__ 1
// MIPS32EL:#define __LDBL_HAS_QUIET_NAN__ 1
// MIPS32EL:#define __LDBL_MANT_DIG__ 53
// MIPS32EL:#define __LDBL_MAX_10_EXP__ 308
// MIPS32EL:#define __LDBL_MAX_EXP__ 1024
-// MIPS32EL:#define __LDBL_MAX__ 1.7976931348623157e+308
+// MIPS32EL:#define __LDBL_MAX__ 1.7976931348623157e+308L
// MIPS32EL:#define __LDBL_MIN_10_EXP__ (-307)
// MIPS32EL:#define __LDBL_MIN_EXP__ (-1021)
-// MIPS32EL:#define __LDBL_MIN__ 2.2250738585072014e-308
+// MIPS32EL:#define __LDBL_MIN__ 2.2250738585072014e-308L
// MIPS32EL:#define __LONG_LONG_MAX__ 9223372036854775807LL
// MIPS32EL:#define __LONG_MAX__ 2147483647L
// MIPS32EL-NOT:#define __LP64__
@@ -686,6 +899,8 @@
// MIPS64BE:#define _ABI64 3
// MIPS64BE:#define _LP64 1
// MIPS64BE:#define _MIPSEB 1
+// MIPS64BE:#define _MIPS_ARCH "mips64"
+// MIPS64BE:#define _MIPS_ARCH_MIPS64 1
// MIPS64BE:#define _MIPS_SIM _ABI64
// MIPS64BE:#define _MIPS_SZINT 32
// MIPS64BE:#define _MIPS_SZLONG 64
@@ -785,6 +1000,8 @@
// MIPS64BE:#define __clang__ 1
// MIPS64BE:#define __llvm__ 1
// MIPS64BE:#define __mips 1
+// MIPS64BE:#define __mips64 1
+// MIPS64BE:#define __mips64__ 1
// MIPS64BE:#define __mips__ 1
// MIPS64BE:#define __mips_hard_float 1
// MIPS64BE:#define __mips_n64 1
@@ -797,6 +1014,8 @@
// MIPS64EL:#define _ABI64 3
// MIPS64EL:#define _LP64 1
// MIPS64EL:#define _MIPSEL 1
+// MIPS64EL:#define _MIPS_ARCH "mips64"
+// MIPS64EL:#define _MIPS_ARCH_MIPS64 1
// MIPS64EL:#define _MIPS_SIM _ABI64
// MIPS64EL:#define _MIPS_SZINT 32
// MIPS64EL:#define _MIPS_SZLONG 64
@@ -896,6 +1115,8 @@
// MIPS64EL:#define __clang__ 1
// MIPS64EL:#define __llvm__ 1
// MIPS64EL:#define __mips 1
+// MIPS64EL:#define __mips64 1
+// MIPS64EL:#define __mips64__ 1
// MIPS64EL:#define __mips__ 1
// MIPS64EL:#define __mips_hard_float 1
// MIPS64EL:#define __mips_n64 1
@@ -993,19 +1214,19 @@
// MSP430:#define __INTPTR_TYPE__ short
// MSP430:#define __INTPTR_WIDTH__ 16
// MSP430:#define __INT_MAX__ 32767
-// MSP430:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// MSP430:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// MSP430:#define __LDBL_DIG__ 15
-// MSP430:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// MSP430:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// MSP430:#define __LDBL_HAS_DENORM__ 1
// MSP430:#define __LDBL_HAS_INFINITY__ 1
// MSP430:#define __LDBL_HAS_QUIET_NAN__ 1
// MSP430:#define __LDBL_MANT_DIG__ 53
// MSP430:#define __LDBL_MAX_10_EXP__ 308
// MSP430:#define __LDBL_MAX_EXP__ 1024
-// MSP430:#define __LDBL_MAX__ 1.7976931348623157e+308
+// MSP430:#define __LDBL_MAX__ 1.7976931348623157e+308L
// MSP430:#define __LDBL_MIN_10_EXP__ (-307)
// MSP430:#define __LDBL_MIN_EXP__ (-1021)
-// MSP430:#define __LDBL_MIN__ 2.2250738585072014e-308
+// MSP430:#define __LDBL_MIN__ 2.2250738585072014e-308L
// MSP430:#define __LONG_LONG_MAX__ 9223372036854775807LL
// MSP430:#define __LONG_MAX__ 2147483647L
// MSP430-NOT:#define __LP64__
@@ -1088,19 +1309,19 @@
// NVPTX32:#define __INTPTR_TYPE__ unsigned int
// NVPTX32:#define __INTPTR_WIDTH__ 32
// NVPTX32:#define __INT_MAX__ 2147483647
-// NVPTX32:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// NVPTX32:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// NVPTX32:#define __LDBL_DIG__ 15
-// NVPTX32:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// NVPTX32:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// NVPTX32:#define __LDBL_HAS_DENORM__ 1
// NVPTX32:#define __LDBL_HAS_INFINITY__ 1
// NVPTX32:#define __LDBL_HAS_QUIET_NAN__ 1
// NVPTX32:#define __LDBL_MANT_DIG__ 53
// NVPTX32:#define __LDBL_MAX_10_EXP__ 308
// NVPTX32:#define __LDBL_MAX_EXP__ 1024
-// NVPTX32:#define __LDBL_MAX__ 1.7976931348623157e+308
+// NVPTX32:#define __LDBL_MAX__ 1.7976931348623157e+308L
// NVPTX32:#define __LDBL_MIN_10_EXP__ (-307)
// NVPTX32:#define __LDBL_MIN_EXP__ (-1021)
-// NVPTX32:#define __LDBL_MIN__ 2.2250738585072014e-308
+// NVPTX32:#define __LDBL_MIN__ 2.2250738585072014e-308L
// NVPTX32:#define __LONG_LONG_MAX__ 9223372036854775807LL
// NVPTX32:#define __LONG_MAX__ 9223372036854775807L
// NVPTX32-NOT:#define __LP64__
@@ -1184,19 +1405,19 @@
// NVPTX64:#define __INTPTR_TYPE__ long long unsigned int
// NVPTX64:#define __INTPTR_WIDTH__ 64
// NVPTX64:#define __INT_MAX__ 2147483647
-// NVPTX64:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// NVPTX64:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// NVPTX64:#define __LDBL_DIG__ 15
-// NVPTX64:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// NVPTX64:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// NVPTX64:#define __LDBL_HAS_DENORM__ 1
// NVPTX64:#define __LDBL_HAS_INFINITY__ 1
// NVPTX64:#define __LDBL_HAS_QUIET_NAN__ 1
// NVPTX64:#define __LDBL_MANT_DIG__ 53
// NVPTX64:#define __LDBL_MAX_10_EXP__ 308
// NVPTX64:#define __LDBL_MAX_EXP__ 1024
-// NVPTX64:#define __LDBL_MAX__ 1.7976931348623157e+308
+// NVPTX64:#define __LDBL_MAX__ 1.7976931348623157e+308L
// NVPTX64:#define __LDBL_MIN_10_EXP__ (-307)
// NVPTX64:#define __LDBL_MIN_EXP__ (-1021)
-// NVPTX64:#define __LDBL_MIN__ 2.2250738585072014e-308
+// NVPTX64:#define __LDBL_MIN__ 2.2250738585072014e-308L
// NVPTX64:#define __LONG_LONG_MAX__ 9223372036854775807LL
// NVPTX64:#define __LONG_MAX__ 9223372036854775807L
// NVPTX64:#define __LP64__ 1
@@ -1796,19 +2017,19 @@
// SPARC:#define __INTPTR_TYPE__ long int
// SPARC:#define __INTPTR_WIDTH__ 32
// SPARC:#define __INT_MAX__ 2147483647
-// SPARC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// SPARC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
// SPARC:#define __LDBL_DIG__ 15
-// SPARC:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// SPARC:#define __LDBL_EPSILON__ 2.2204460492503131e-16L
// SPARC:#define __LDBL_HAS_DENORM__ 1
// SPARC:#define __LDBL_HAS_INFINITY__ 1
// SPARC:#define __LDBL_HAS_QUIET_NAN__ 1
// SPARC:#define __LDBL_MANT_DIG__ 53
// SPARC:#define __LDBL_MAX_10_EXP__ 308
// SPARC:#define __LDBL_MAX_EXP__ 1024
-// SPARC:#define __LDBL_MAX__ 1.7976931348623157e+308
+// SPARC:#define __LDBL_MAX__ 1.7976931348623157e+308L
// SPARC:#define __LDBL_MIN_10_EXP__ (-307)
// SPARC:#define __LDBL_MIN_EXP__ (-1021)
-// SPARC:#define __LDBL_MIN__ 2.2250738585072014e-308
+// SPARC:#define __LDBL_MIN__ 2.2250738585072014e-308L
// SPARC:#define __LONG_LONG_MAX__ 9223372036854775807LL
// SPARC:#define __LONG_MAX__ 2147483647L
// SPARC-NOT:#define __LP64__
@@ -1853,19 +2074,19 @@
// TCE:#define __CHAR16_TYPE__ unsigned short
// TCE:#define __CHAR32_TYPE__ unsigned int
// TCE:#define __CHAR_BIT__ 8
-// TCE:#define __DBL_DENORM_MIN__ 1.40129846e-45F
+// TCE:#define __DBL_DENORM_MIN__ 1.40129846e-45
// TCE:#define __DBL_DIG__ 6
-// TCE:#define __DBL_EPSILON__ 1.19209290e-7F
+// TCE:#define __DBL_EPSILON__ 1.19209290e-7
// TCE:#define __DBL_HAS_DENORM__ 1
// TCE:#define __DBL_HAS_INFINITY__ 1
// TCE:#define __DBL_HAS_QUIET_NAN__ 1
// TCE:#define __DBL_MANT_DIG__ 24
// TCE:#define __DBL_MAX_10_EXP__ 38
// TCE:#define __DBL_MAX_EXP__ 128
-// TCE:#define __DBL_MAX__ 3.40282347e+38F
+// TCE:#define __DBL_MAX__ 3.40282347e+38
// TCE:#define __DBL_MIN_10_EXP__ (-37)
// TCE:#define __DBL_MIN_EXP__ (-125)
-// TCE:#define __DBL_MIN__ 1.17549435e-38F
+// TCE:#define __DBL_MIN__ 1.17549435e-38
// TCE:#define __DECIMAL_DIG__ -1
// TCE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// TCE:#define __FLT_DIG__ 6
@@ -1891,19 +2112,19 @@
// TCE:#define __INTPTR_TYPE__ int
// TCE:#define __INTPTR_WIDTH__ 32
// TCE:#define __INT_MAX__ 2147483647
-// TCE:#define __LDBL_DENORM_MIN__ 1.40129846e-45F
+// TCE:#define __LDBL_DENORM_MIN__ 1.40129846e-45L
// TCE:#define __LDBL_DIG__ 6
-// TCE:#define __LDBL_EPSILON__ 1.19209290e-7F
+// TCE:#define __LDBL_EPSILON__ 1.19209290e-7L
// TCE:#define __LDBL_HAS_DENORM__ 1
// TCE:#define __LDBL_HAS_INFINITY__ 1
// TCE:#define __LDBL_HAS_QUIET_NAN__ 1
// TCE:#define __LDBL_MANT_DIG__ 24
// TCE:#define __LDBL_MAX_10_EXP__ 38
// TCE:#define __LDBL_MAX_EXP__ 128
-// TCE:#define __LDBL_MAX__ 3.40282347e+38F
+// TCE:#define __LDBL_MAX__ 3.40282347e+38L
// TCE:#define __LDBL_MIN_10_EXP__ (-37)
// TCE:#define __LDBL_MIN_EXP__ (-125)
-// TCE:#define __LDBL_MIN__ 1.17549435e-38F
+// TCE:#define __LDBL_MIN__ 1.17549435e-38L
// TCE:#define __LONG_LONG_MAX__ 2147483647LL
// TCE:#define __LONG_MAX__ 2147483647L
// TCE-NOT:#define __LP64__
diff --git a/test/Preprocessor/macro_arg_directive.c b/test/Preprocessor/macro_arg_directive.c
index 5c9943d60530..5bc2236f0c45 100644
--- a/test/Preprocessor/macro_arg_directive.c
+++ b/test/Preprocessor/macro_arg_directive.c
@@ -1,5 +1,12 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+#define a(x) enum { x }
+a(n =
+#undef a
+#define a 5
+ a);
+_Static_assert(n == 5, "");
+
// header1.h
void fail(const char *);
#define MUNCH(...) \
diff --git a/test/Preprocessor/macro_fn_comma_swallow2.c b/test/Preprocessor/macro_fn_comma_swallow2.c
new file mode 100644
index 000000000000..93ab2b83664a
--- /dev/null
+++ b/test/Preprocessor/macro_fn_comma_swallow2.c
@@ -0,0 +1,64 @@
+// Test the __VA_ARGS__ comma swallowing extensions of various compiler dialects.
+
+// RUN: %clang_cc1 -E %s | FileCheck -check-prefix=GCC -strict-whitespace %s
+// RUN: %clang_cc1 -E -std=c99 %s | FileCheck -check-prefix=C99 -strict-whitespace %s
+// RUN: %clang_cc1 -E -std=c11 %s | FileCheck -check-prefix=C99 -strict-whitespace %s
+// RUN: %clang_cc1 -E -x c++ %s | FileCheck -check-prefix=GCC -strict-whitespace %s
+// RUN: %clang_cc1 -E -std=gnu99 %s | FileCheck -check-prefix=GCC -strict-whitespace %s
+// RUN: %clang_cc1 -E -fms-compatibility %s | FileCheck -check-prefix=MS -strict-whitespace %s
+// RUN: %clang_cc1 -E -DNAMED %s | FileCheck -check-prefix=GCC -strict-whitespace %s
+// RUN: %clang_cc1 -E -std=c99 -DNAMED %s | FileCheck -check-prefix=C99 -strict-whitespace %s
+
+
+#ifndef NAMED
+# define A(...) [ __VA_ARGS__ ]
+# define B(...) [ , __VA_ARGS__ ]
+# define C(...) [ , ## __VA_ARGS__ ]
+# define D(A,...) [ A , ## __VA_ARGS__ ]
+# define E(A,...) [ __VA_ARGS__ ## A ]
+#else
+// These are the GCC named argument versions of the C99-style variadic macros.
+// Note that __VA_ARGS__ *may* be used as the name, this is not prohibited!
+# define A(__VA_ARGS__...) [ __VA_ARGS__ ]
+# define B(__VA_ARGS__...) [ , __VA_ARGS__ ]
+# define C(__VA_ARGS__...) [ , ## __VA_ARGS__ ]
+# define D(A,__VA_ARGS__...) [ A , ## __VA_ARGS__ ]
+# define E(A,__VA_ARGS__...) [ __VA_ARGS__ ## A ]
+#endif
+
+
+1: A() B() C() D() E()
+2: A(a) B(a) C(a) D(a) E(a)
+3: A(,) B(,) C(,) D(,) E(,)
+4: A(a,b,c) B(a,b,c) C(a,b,c) D(a,b,c) E(a,b,c)
+5: A(a,b,) B(a,b,) C(a,b,) D(a,b,)
+
+// The GCC ", ## __VA_ARGS__" extension swallows the comma when followed by
+// empty __VA_ARGS__. This extension does not apply in -std=c99 mode, but
+// does apply in C++.
+//
+// GCC: 1: [ ] [ , ] [ ] [ ] [ ]
+// GCC: 2: [ a ] [ , a ] [ ,a ] [ a ] [ a ]
+// GCC: 3: [ , ] [ , , ] [ ,, ] [ , ] [ ]
+// GCC: 4: [ a,b,c ] [ , a,b,c ] [ ,a,b,c ] [ a ,b,c ] [ b,ca ]
+// GCC: 5: [ a,b, ] [ , a,b, ] [ ,a,b, ] [ a ,b, ]
+
+// Under C99 standard mode, the GCC ", ## __VA_ARGS__" extension *does not*
+// swallow the comma when followed by empty __VA_ARGS__.
+//
+// C99: 1: [ ] [ , ] [ , ] [ ] [ ]
+// C99: 2: [ a ] [ , a ] [ ,a ] [ a ] [ a ]
+// C99: 3: [ , ] [ , , ] [ ,, ] [ , ] [ ]
+// C99: 4: [ a,b,c ] [ , a,b,c ] [ ,a,b,c ] [ a ,b,c ] [ b,ca ]
+// C99: 5: [ a,b, ] [ , a,b, ] [ ,a,b, ] [ a ,b, ]
+
+// Microsoft's extension is on ", __VA_ARGS__" (without explicit ##) where
+// the comma is swallowed when followed by empty __VA_ARGS__.
+//
+// MS: 1: [ ] [ ] [ ] [ ] [ ]
+// MS: 2: [ a ] [ , a ] [ ,a ] [ a ] [ a ]
+// MS: 3: [ , ] [ , , ] [ ,, ] [ , ] [ ]
+// MS: 4: [ a,b,c ] [ , a,b,c ] [ ,a,b,c ] [ a ,b,c ] [ b,ca ]
+// MS: 5: [ a,b, ] [ , a,b, ] [ ,a,b, ] [ a ,b, ]
+
+// FIXME: Item 3(d) in MS output should be [ ] not [ , ]
diff --git a/test/Preprocessor/macro_paste_identifier_error.c b/test/Preprocessor/macro_paste_identifier_error.c
index 457e6f7fc1aa..bba317239ac6 100644
--- a/test/Preprocessor/macro_paste_identifier_error.c
+++ b/test/Preprocessor/macro_paste_identifier_error.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fms-extensions -Wno-invalid-token-paste %s -verify
// RUN: %clang_cc1 -E -fms-extensions -Wno-invalid-token-paste %s | FileCheck %s
// RUN: %clang_cc1 -E -fms-extensions -Wno-invalid-token-paste -x assembler-with-cpp %s | FileCheck %s
+// expected-no-diagnostics
#define foo a ## b ## = 0
int foo;
diff --git a/test/Preprocessor/microsoft-ext.c b/test/Preprocessor/microsoft-ext.c
new file mode 100644
index 000000000000..ec10374a1d6a
--- /dev/null
+++ b/test/Preprocessor/microsoft-ext.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -E -fms-compatibility %s -o %t
+// RUN: FileCheck %s < %t
+
+# define M2(x, y) x + y
+# define P(x, y) {x, y}
+# define M(x, y) M2(x, P(x, y))
+M(a, b) // CHECK: a + {a, b}
+
+// Regression test for PR13924
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+#define GMOCK_INTERNAL_COUNT_AND_2_VALUE_PARAMS(p0, p1) P2
+
+#define GMOCK_ACTION_CLASS_(name, value_params)\
+ GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params)
+
+#define ACTION_TEMPLATE(name, template_params, value_params)\
+class GMOCK_ACTION_CLASS_(name, value_params) {\
+}
+
+ACTION_TEMPLATE(InvokeArgument,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_2_VALUE_PARAMS(p0, p1));
diff --git a/test/Preprocessor/objc-pp.m b/test/Preprocessor/objc-pp.m
index 0ec288c830a0..3522f739344f 100644
--- a/test/Preprocessor/objc-pp.m
+++ b/test/Preprocessor/objc-pp.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -ffreestanding
+// expected-no-diagnostics
#import <stdint.h> // no warning on #import in objc mode.
diff --git a/test/Preprocessor/optimize.c b/test/Preprocessor/optimize.c
index 97f841a6fbb9..0167e70e0122 100644
--- a/test/Preprocessor/optimize.c
+++ b/test/Preprocessor/optimize.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -Eonly %s -DOPT_O2 -O2 -verify
#ifdef OPT_O2
+ // expected-no-diagnostics
#ifndef __OPTIMIZE__
#error "__OPTIMIZE__ not defined"
#endif
@@ -10,6 +11,7 @@
// RUN: %clang_cc1 -Eonly %s -DOPT_O0 -O0 -verify
#ifdef OPT_O0
+ // expected-no-diagnostics
#ifdef __OPTIMIZE__
#error "__OPTIMIZE__ defined"
#endif
@@ -20,6 +22,7 @@
// RUN: %clang_cc1 -Eonly %s -DOPT_OS -Os -verify
#ifdef OPT_OS
+ // expected-no-diagnostics
#ifndef __OPTIMIZE__
#error "__OPTIMIZE__ not defined"
#endif
diff --git a/test/Preprocessor/pr13851.c b/test/Preprocessor/pr13851.c
new file mode 100644
index 000000000000..537594d28ffb
--- /dev/null
+++ b/test/Preprocessor/pr13851.c
@@ -0,0 +1,11 @@
+// Check that -E -M -MF does not cause an "argument unused" error, by adding
+// -Werror to the clang invocation. Also check the dependency output, if any.
+// RUN: %clang -Werror -E -M -MF %t-M.d %s
+// RUN: FileCheck --input-file=%t-M.d %s
+// CHECK: pr13851.o:
+// CHECK: pr13851.c
+
+// Check that -E -MM -MF does not cause an "argument unused" error, by adding
+// -Werror to the clang invocation. Also check the dependency output, if any.
+// RUN: %clang -Werror -E -MM -MF %t-MM.d %s
+// RUN: FileCheck --input-file=%t-MM.d %s
diff --git a/test/Preprocessor/pragma-pushpop-macro.c b/test/Preprocessor/pragma-pushpop-macro.c
index 08a65704e4cb..0aee074c55c7 100644
--- a/test/Preprocessor/pragma-pushpop-macro.c
+++ b/test/Preprocessor/pragma-pushpop-macro.c
@@ -31,6 +31,22 @@ int pmy1 = Y;
#define Y 4
int pmy2 = Y;
+// The sequence push, define/undef, pop caused problems if macro was not
+// previously defined.
+#pragma push_macro("PREVIOUSLY_UNDEFINED1")
+#undef PREVIOUSLY_UNDEFINED1
+#pragma pop_macro("PREVIOUSLY_UNDEFINED1")
+#ifndef PREVIOUSLY_UNDEFINED1
+int Q;
+#endif
+
+#pragma push_macro("PREVIOUSLY_UNDEFINED2")
+#define PREVIOUSLY_UNDEFINED2
+#pragma pop_macro("PREVIOUSLY_UNDEFINED2")
+#ifndef PREVIOUSLY_UNDEFINED2
+int P;
+#endif
+
// CHECK: int pmx0 = 1
// CHECK: int pmy0 = 2
// CHECK: int pmx1 = 1
@@ -38,4 +54,5 @@ int pmy2 = Y;
// CHECK: int pmx3 = 1
// CHECK: int pmy1 = 3
// CHECK: int pmy2 = 4
-
+// CHECK: int Q;
+// CHECK: int P;
diff --git a/test/Preprocessor/pragma_sysheader.c b/test/Preprocessor/pragma_sysheader.c
index 17080fec53db..075c9803a507 100644
--- a/test/Preprocessor/pragma_sysheader.c
+++ b/test/Preprocessor/pragma_sysheader.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -verify -pedantic %s -fsyntax-only
// RUN: %clang_cc1 -E %s | FileCheck %s
+// expected-no-diagnostics
// rdar://6899937
#include "pragma_sysheader.h"
@@ -9,4 +10,4 @@
// CHECK-NEXT: # 1 "{{.*}}pragma_sysheader.h" 3
// CHECK-NEXT: typedef int x;
// CHECK-NEXT: typedef int x;
-// CHECK-NEXT: # 5 "{{.*}}pragma_sysheader.c" 2
+// CHECK-NEXT: # 6 "{{.*}}pragma_sysheader.c" 2
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 2361abe20cd0..719f945fd6b2 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -516,6 +516,7 @@
// CHECK_CORE_AVX2_M32: #define __PCLMUL__ 1
// CHECK_CORE_AVX2_M32: #define __POPCNT__ 1
// CHECK_CORE_AVX2_M32: #define __RDRND__ 1
+// CHECK_CORE_AVX2_M32: #define __RTM__ 1
// CHECK_CORE_AVX2_M32: #define __SSE2__ 1
// CHECK_CORE_AVX2_M32: #define __SSE3__ 1
// CHECK_CORE_AVX2_M32: #define __SSE4_1__ 1
@@ -541,6 +542,7 @@
// CHECK_CORE_AVX2_M64: #define __PCLMUL__ 1
// CHECK_CORE_AVX2_M64: #define __POPCNT__ 1
// CHECK_CORE_AVX2_M64: #define __RDRND__ 1
+// CHECK_CORE_AVX2_M64: #define __RTM__ 1
// CHECK_CORE_AVX2_M64: #define __SSE2_MATH__ 1
// CHECK_CORE_AVX2_M64: #define __SSE2__ 1
// CHECK_CORE_AVX2_M64: #define __SSE3__ 1
diff --git a/test/Preprocessor/user_defined_system_framework.c b/test/Preprocessor/user_defined_system_framework.c
index 8e3db5619795..2ab2a297ecbc 100644
--- a/test/Preprocessor/user_defined_system_framework.c
+++ b/test/Preprocessor/user_defined_system_framework.c
@@ -1,4 +1,5 @@
-// RUN: %clang -cc1 -fsyntax-only -F %S/Inputs -Wsign-conversion -verify %s
+// RUN: %clang_cc1 -fsyntax-only -F %S/Inputs -Wsign-conversion -verify %s
+// expected-no-diagnostics
// Check that TestFramework is treated as a system header.
#include <TestFramework/TestFramework.h>
diff --git a/test/Rewriter/no-integrated-preprocessing-64bit.m b/test/Rewriter/no-integrated-preprocessing-64bit.m
new file mode 100644
index 000000000000..63184493b3b8
--- /dev/null
+++ b/test/Rewriter/no-integrated-preprocessing-64bit.m
@@ -0,0 +1,26 @@
+// RUN: %clang -target x86_64-unkown-unknown -fms-extensions -rewrite-objc %s -o - | FileCheck %s
+// rdar://12189793
+
+#ifdef __cplusplus
+
+void *sel_registerName(const char *);
+
+@interface Root @end
+
+@interface MYINTF : Root
+@end
+
+#endif
+
+@implementation MYINTF
+- (id) MYMETH { return [self MYMETH]; }
+@end
+
+int main() {
+}
+
+// CHECK: static struct _class_ro_t _OBJC_CLASS_RO_$_MYINTF
+// CHECK-NEXT: 0, 0, 0,
+// CHECK-NEXT: (unsigned int)0,
+// CHECK-NEXT: 0,
+// CHECK-NEXT: "MYINTF",
diff --git a/test/Rewriter/no-integrated-preprocessing.m b/test/Rewriter/no-integrated-preprocessing.m
new file mode 100644
index 000000000000..e4cc301ab4e8
--- /dev/null
+++ b/test/Rewriter/no-integrated-preprocessing.m
@@ -0,0 +1,26 @@
+// RUN: %clang -arch i386 -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck %s < %t-rw.cpp
+// rdar://12189793
+
+#ifdef __cplusplus
+
+void *sel_registerName(const char *);
+
+@interface Root @end
+
+@interface MYINTF : Root
+@end
+
+#endif
+
+@implementation MYINTF
+- (id) MYMETH { return [self MYMETH]; }
+@end
+
+int main() {
+}
+
+// CHECK: static struct _class_ro_t _OBJC_CLASS_RO_$_MYINTF
+// CHECK-NEXT: 0, 0, 0,
+// CHECK-NEXT: 0,
+// CHECK-NEST: "MYINTF",
diff --git a/test/Rewriter/objc-modern-StretAPI-2.mm b/test/Rewriter/objc-modern-StretAPI-2.mm
new file mode 100644
index 000000000000..961fc168be9c
--- /dev/null
+++ b/test/Rewriter/objc-modern-StretAPI-2.mm
@@ -0,0 +1,30 @@
+// 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://12142241
+
+extern "C" void *sel_registerName(const char *);
+typedef unsigned long size_t;
+
+typedef unsigned long NSUInteger;
+typedef struct _NSRange {
+ NSUInteger location;
+ NSUInteger length;
+} NSRange;
+
+
+@interface NSIndexSet
+- (NSRange)rangeAtIndex:(NSUInteger)rangeIndex;
+@end
+
+@interface NSArray
+@end
+
+@implementation NSArray
+- (NSArray *)objectsAtIndexes:(NSIndexSet *)iset {
+
+ NSUInteger ridx = 0;
+ NSRange range = [iset rangeAtIndex:ridx];
+ return 0;
+}
+@end
+
diff --git a/test/Rewriter/objc-modern-boxing.mm b/test/Rewriter/objc-modern-boxing.mm
index 8f8ed751c58e..4997c24961c2 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.1415927));
+// 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 *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-numeric-literal.mm b/test/Rewriter/objc-modern-numeric-literal.mm
index 5f0b1fc3b1ee..5f63d8c52ad2 100644
--- a/test/Rewriter/objc-modern-numeric-literal.mm
+++ b/test/Rewriter/objc-modern-numeric-literal.mm
@@ -61,7 +61,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.1415927);
+// 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 *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);
diff --git a/test/Sema/MicrosoftCompatibility-x64.c b/test/Sema/MicrosoftCompatibility-x64.c
new file mode 100644
index 000000000000..bf595af69939
--- /dev/null
+++ b/test/Sema/MicrosoftCompatibility-x64.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility -triple x86_64-pc-win32
+int __stdcall f(void); /* expected-warning {{calling convention '__stdcall' ignored for this target}} */
+
+/* This should compile without warning because __stdcall is treated
+as __cdecl in MS compatibility mode for x64 compiles*/
+int __cdecl f(void) {
+ return 0;
+}
diff --git a/test/Sema/MicrosoftCompatibility-x86.c b/test/Sema/MicrosoftCompatibility-x86.c
new file mode 100644
index 000000000000..1e3762b3788f
--- /dev/null
+++ b/test/Sema/MicrosoftCompatibility-x86.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility -triple i386-pc-win32
+int __stdcall f(void); /* expected-note {{previous declaration is here}} */
+
+int __cdecl f(void) { /* expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}} */
+ return 0;
+}
diff --git a/test/Sema/MicrosoftCompatibility.c b/test/Sema/MicrosoftCompatibility.c
index 6b137a60c4f0..6330c1566703 100644
--- a/test/Sema/MicrosoftCompatibility.c
+++ b/test/Sema/MicrosoftCompatibility.c
@@ -18,4 +18,4 @@ __declspec(noreturn) void f6( void ) {
__declspec(align(32768)) struct S1 { int a; } s; /* expected-error {{requested alignment must be 8192 bytes or smaller}} */
struct __declspec(aligned) S2 {}; /* expected-warning {{unknown __declspec attribute 'aligned' ignored}} */
-struct __declspec(appdomain) S3 {}; /* expected-warning {{__declspec attribute 'appdomain' is not supported}} */ \ No newline at end of file
+struct __declspec(appdomain) S3 {}; /* expected-warning {{__declspec attribute 'appdomain' is not supported}} */
diff --git a/test/Sema/PR2727.c b/test/Sema/PR2727.c
index 332b0df72835..11282fdea8a4 100644
--- a/test/Sema/PR2727.c
+++ b/test/Sema/PR2727.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -verify -fsyntax-only -std=c90 %s
// RUN: %clang_cc1 -verify -fsyntax-only -std=c99 %s
+// expected-no-diagnostics
int f (int x)
{
diff --git a/test/Sema/PR2728.c b/test/Sema/PR2728.c
index e9f1deaf7cd6..0c994057a1e4 100644
--- a/test/Sema/PR2728.c
+++ b/test/Sema/PR2728.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -verify -fsyntax-only -std=c90 %s
// RUN: %clang_cc1 -verify -fsyntax-only -std=c99 %s
+// expected-no-diagnostics
struct s
{
diff --git a/test/Sema/PR2923.c b/test/Sema/PR2923.c
index f22e70dd8d3d..5741de8e38ec 100644
--- a/test/Sema/PR2923.c
+++ b/test/Sema/PR2923.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Test for absence of crash reported in PR 2923:
//
diff --git a/test/Sema/address-constant.c b/test/Sema/address-constant.c
index e842a7396b8d..c13485b37ba5 100644
--- a/test/Sema/address-constant.c
+++ b/test/Sema/address-constant.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int i;
int a[] = {0};
diff --git a/test/Sema/align-arm-apcs.c b/test/Sema/align-arm-apcs.c
index 0a5d3fe92151..544f53923191 100644
--- a/test/Sema/align-arm-apcs.c
+++ b/test/Sema/align-arm-apcs.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple arm-unknown-unknown -target-abi apcs-gnu -fsyntax-only -verify %s
+// expected-no-diagnostics
struct s0 { double f0; int f1; };
char chk0[__alignof__(struct s0) == 4 ? 1 : -1];
diff --git a/test/Sema/align-x86-64.c b/test/Sema/align-x86-64.c
index edea5d8b7422..09bf63390f35 100644
--- a/test/Sema/align-x86-64.c
+++ b/test/Sema/align-x86-64.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5599
diff --git a/test/Sema/align-x86.c b/test/Sema/align-x86.c
index c6cd7543c21d..6b93a4893d15 100644
--- a/test/Sema/align-x86.c
+++ b/test/Sema/align-x86.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR3433
double g1;
diff --git a/test/Sema/arg-scope-c99.c b/test/Sema/arg-scope-c99.c
index 912776ab8ff6..9b2811ccc759 100644
--- a/test/Sema/arg-scope-c99.c
+++ b/test/Sema/arg-scope-c99.c
@@ -1,2 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -std=c99 -verify %s
+// expected-no-diagnostics
void bb(int sz, int ar[sz][sz]) { }
diff --git a/test/Sema/arg-scope.c b/test/Sema/arg-scope.c
index ed9261941b58..3de672be9f7d 100644
--- a/test/Sema/arg-scope.c
+++ b/test/Sema/arg-scope.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
void aa(int b, int x[sizeof b]) {}
void foo(int i, int A[i]) {}
diff --git a/test/Sema/arm-layout.c b/test/Sema/arm-layout.c
index d017fdb8aa07..4b76515d6257 100644
--- a/test/Sema/arm-layout.c
+++ b/test/Sema/arm-layout.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple armv7-unknown-unknown -target-abi apcs-gnu %s -verify
// RUN: %clang_cc1 -triple armv7-unknown-unknown -target-abi aapcs %s -verify
+// expected-no-diagnostics
#define check(name, cond) int _##name##_check[(cond) ? 1 : -1]
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index cfdf8e2bd7ca..b3cae60495c7 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wgnu -Wc11-extensions -verify %s
+// REQUIRES: LP64
extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 44d83e92143b..155d736b9956 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i386-pc-linux-gnu -verify -fsyntax-only
+// RUN: %clang_cc1 %s -Wno-private-extern -triple i386-pc-linux-gnu -verify -fsyntax-only
void f() {
int i;
diff --git a/test/Sema/assign-null.c b/test/Sema/assign-null.c
index 7f172b195355..ac90850eb7ce 100644
--- a/test/Sema/assign-null.c
+++ b/test/Sema/assign-null.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <stddef.h>
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index f769271631ba..2a935918ac08 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=i686-linux-gnu
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=i686-linux-gnu -std=c11
// Basic parsing/Sema tests for __c11_atomic_*
@@ -162,4 +162,9 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
__atomic_clear(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}}
__atomic_clear(&flag, memory_order_seq_cst);
(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)}}
}
diff --git a/test/Sema/attr-availability-macosx.c b/test/Sema/attr-availability-macosx.c
index 781523a2e06a..468e9303e70d 100644
--- a/test/Sema/attr-availability-macosx.c
+++ b/test/Sema/attr-availability-macosx.c
@@ -10,10 +10,10 @@ void f5(int) __attribute__((availability(ios,introduced=3.2), availability(macos
void test() {
f0(0);
f1(0);
- f2(0); // expected-warning{{'f2' is deprecated: first deprecated in Mac OS X 10.5}}
+ f2(0); // expected-warning{{'f2' is deprecated: first deprecated in OS X 10.5}}
f3(0);
- f4(0); // expected-error{{f4' is unavailable: obsoleted in Mac OS X 10.5}}
- f5(0); // expected-error{{'f5' is unavailable: not available on Mac OS X}}
+ f4(0); // expected-error{{f4' is unavailable: obsoleted in OS X 10.5}}
+ f5(0); // expected-error{{'f5' is unavailable: not available on OS X}}
}
// rdar://10535640
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index b4a6f9616df4..e0c541e8d839 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -verify %s
-void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in Mac OS X version 10.2 before it was introduced in version 10.4; attribute ignored}}
+void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in OS X version 10.2 before it was introduced in version 10.4; attribute ignored}}
void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
void f2() __attribute__((availability(ios,introduced=2.1,deprecated=2.1)));
@@ -14,8 +14,8 @@ extern void
ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduced=8.0,obsoleted=9.0, message="use ATSFontGetFullPostScriptName"))); // expected-note {{function has been explicitly marked unavailable here}}
void test_10095131() {
- ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in Mac OS X 9.0 - use CTFontCopyFullName}}
- ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in Mac OS X 9.0 - use ATSFontGetFullPostScriptName}}
+ ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in OS X 9.0 - use CTFontCopyFullName}}
+ ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in OS X 9.0 - use ATSFontGetFullPostScriptName}}
}
// rdar://10711037
diff --git a/test/Sema/attr-minsize.c b/test/Sema/attr-minsize.c
new file mode 100644
index 000000000000..7b1c6ae66f1b
--- /dev/null
+++ b/test/Sema/attr-minsize.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int foo() __attribute__((__minsize__));
+
+int var1 __attribute__((__minsize__)); // expected-error{{'__minsize__' attribute only applies to functions and methods}}
diff --git a/test/Sema/attr-used.c b/test/Sema/attr-used.c
index 08388169247e..e2dfab141a99 100644
--- a/test/Sema/attr-used.c
+++ b/test/Sema/attr-used.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-private-extern %s
extern int l0 __attribute__((used)); // expected-warning {{used attribute ignored}}
__private_extern__ int l1 __attribute__((used)); // expected-warning {{used attribute ignored}}
diff --git a/test/Sema/bitfield-layout.c b/test/Sema/bitfield-layout.c
index 2655fc70cd4c..d22639147586 100644
--- a/test/Sema/bitfield-layout.c
+++ b/test/Sema/bitfield-layout.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-apple-darwin9
+// expected-no-diagnostics
#define CHECK_SIZE(kind, name, size) extern int name##1[sizeof(kind name) == size ? 1 : -1];
#define CHECK_ALIGN(kind, name, size) extern int name##2[__alignof(kind name) == size ? 1 : -1];
diff --git a/test/Sema/bitfield-promote.c b/test/Sema/bitfield-promote.c
index 4d14ad191e1e..3189cd57e4f3 100644
--- a/test/Sema/bitfield-promote.c
+++ b/test/Sema/bitfield-promote.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct {unsigned x : 2;} x;
__typeof__((x.x+=1)+1) y;
__typeof__(x.x<<1) y;
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 6967955b0878..2ea4d813ab01 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -pedantic -fsyntax-only %s -verify -fblocks
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -pedantic -fsyntax-only %s -verify -fblocks
typedef void (^CL)(void);
diff --git a/test/Sema/block-storageclass.c b/test/Sema/block-storageclass.c
index 9bfbfbd614e5..74f1b0ea77fa 100644
--- a/test/Sema/block-storageclass.c
+++ b/test/Sema/block-storageclass.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+// expected-no-diagnostics
int printf(const char *, ...);
void _Block_byref_release(void*src){}
diff --git a/test/Sema/builtin_objc_msgSend.c b/test/Sema/builtin_objc_msgSend.c
index 357a5bc26eb5..419e92da44eb 100644
--- a/test/Sema/builtin_objc_msgSend.c
+++ b/test/Sema/builtin_objc_msgSend.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://8632525
typedef struct objc_class *Class;
diff --git a/test/Sema/builtins-arm.c b/test/Sema/builtins-arm.c
index 4077240ce490..7b48af155ee8 100644
--- a/test/Sema/builtins-arm.c
+++ b/test/Sema/builtins-arm.c
@@ -1,5 +1,7 @@
// 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 -target-abi apcs-gnu \
+// RUN: -fsyntax-only -verify -DTEST1 %s
#ifdef TEST0
void __clear_cache(char*, char*);
@@ -9,8 +11,24 @@ void __clear_cache(char*, char*);
void __clear_cache(void*, void*);
#endif
-// va_list on ARM is void*.
+#if defined(__ARM_PCS) || defined(__ARM_EABI__)
+// va_list on ARM AAPCS is struct { void* __ap }.
+void test1() {
+ __builtin_va_list ptr;
+ ptr.__ap = "x";
+ *(ptr.__ap) = '0'; // expected-error {{incomplete type 'void' is not assignable}}
+}
+#else
+// va_list on ARM apcs-gnu is void*.
+void test1() {
+ __builtin_va_list ptr;
+ ptr.__ap = "x"; // expected-error {{member reference base type '__builtin_va_list' is not a structure or union}}
+ *(ptr.__ap) = '0';// expected-error {{member reference base type '__builtin_va_list' is not a structure or union}}
+}
+
void test2() {
__builtin_va_list ptr = "x";
*ptr = '0'; // expected-error {{incomplete type 'void' is not assignable}}
}
+
+#endif
diff --git a/test/Sema/builtins-decl.c b/test/Sema/builtins-decl.c
index d6b004aa8820..729dc4599de9 100644
--- a/test/Sema/builtins-decl.c
+++ b/test/Sema/builtins-decl.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-mingw32
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-mingw32
+// expected-no-diagnostics
// mingw-w64's intrin.h has decls below.
// we should accept them.
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index b8b03677fdae..e3b3b7e83178 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -40,7 +40,7 @@ void test9(short v) {
old = __sync_fetch_and_add(); // expected-error {{too few arguments to function call}}
old = __sync_fetch_and_add(&old); // expected-error {{too few arguments to function call}}
- old = __sync_fetch_and_add((unsigned*)0, 42i); // expected-warning {{imaginary constants are an extension}}
+ old = __sync_fetch_and_add((unsigned*)0, 42i); // expected-warning {{imaginary constants are a GNU extension}}
// PR7600: Pointers are implicitly casted to integers and back.
void *old_ptr = __sync_val_compare_and_swap((void**)0, 0, 0);
@@ -51,6 +51,20 @@ void test9(short v) {
}
}
+// overloaded atomics should be declared only once.
+void test9_1(volatile int* ptr, int val) {
+ __sync_fetch_and_add_4(ptr, val);
+}
+void test9_2(volatile int* ptr, int val) {
+ __sync_fetch_and_add(ptr, val);
+}
+void test9_3(volatile int* ptr, int val) {
+ __sync_fetch_and_add_4(ptr, val);
+ __sync_fetch_and_add(ptr, val);
+ __sync_fetch_and_add(ptr, val);
+ __sync_fetch_and_add_4(ptr, val);
+ __sync_fetch_and_add_4(ptr, val);
+}
// rdar://7236819
void test10(void) __attribute__((noreturn));
diff --git a/test/Sema/c89-2.c b/test/Sema/c89-2.c
deleted file mode 100644
index 14b955a6a4b3..000000000000
--- a/test/Sema/c89-2.c
+++ /dev/null
@@ -1,5 +0,0 @@
-/* RUN: %clang_cc1 %s -std=c89 -pedantic-errors -Wno-empty-translation-unit -verify
- */
-
-#if 1LL /* expected-error {{long long}} */
-#endif
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index 110d7e137621..a410a626edac 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -110,3 +110,9 @@ typedef CI *array_of_pointer_to_CI[5];
const array_of_pointer_to_CI mine3;
void main() {} /* expected-error {{'main' must return 'int'}} */
+
+long long ll1 = /* expected-warning {{'long long' is an extension when C99 mode is not enabled}} */
+ -42LL; /* expected-warning {{'long long' is an extension when C99 mode is not enabled}} */
+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}} */
+
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index 6c844a373318..266242d4a3a9 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple i386-unknown-unknown -verify
void __attribute__((fastcall)) foo(float *a) {
}
@@ -40,8 +40,9 @@ int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{attri
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"))) pcs5(void); // no-error
-int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // no-error
+/* 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}}
int __attribute__((pcs("foo"))) pcs7(void); // expected-error {{Invalid PCS type}}
// PR6361
@@ -52,3 +53,4 @@ void __attribute__((cdecl)) ctest3() {}
typedef __attribute__((stdcall)) void (*PROC)();
PROC __attribute__((cdecl)) ctest4(const char *x) {}
+void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
diff --git a/test/Sema/cast-to-union.c b/test/Sema/cast-to-union.c
index c32964dfc0d5..7b995e3d0cb8 100644
--- a/test/Sema/cast-to-union.c
+++ b/test/Sema/cast-to-union.c
@@ -4,16 +4,16 @@ union u { int i; unsigned : 3; };
void f(union u);
void test(int x) {
- f((union u)x); // expected-warning {{C99 forbids casts to union type}}
+ f((union u)x); // expected-warning {{cast to union type is a GNU extension}}
f((union u)&x); // expected-error {{cast to union type from type 'int *' not present in union}}
f((union u)2U); // expected-error {{cast to union type from type 'unsigned int' not present in union}}
}
-union u w = (union u)2; // expected-warning {{C99 forbids casts to union type}}
+union u w = (union u)2; // expected-warning {{cast to union type is a GNU extension}}
union u ww = (union u)1.0; // expected-error{{cast to union type from type 'double' not present in union}}
union u x = 7; // expected-error{{initializing 'union u' with an expression of incompatible type 'int'}}
int i;
-union u zz = (union u)i; // expected-error{{initializer element is not a compile-time constant}} expected-warning {{C99 forbids casts to union type}}
+union u zz = (union u)i; // expected-error{{initializer element is not a compile-time constant}} expected-warning {{cast to union type is a GNU extension}}
struct s {int a, b;};
struct s y = { 1, 5 };
diff --git a/test/Sema/cast.c b/test/Sema/cast.c
index 71c44b4b816b..25ef1d03a4fe 100644
--- a/test/Sema/cast.c
+++ b/test/Sema/cast.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown %s -verify
typedef struct { unsigned long bits[(((1) + (64) - 1) / (64))]; } cpumask_t;
cpumask_t x;
@@ -52,8 +52,8 @@ void testInt(Int v) {
(void) (CLong) v;
(void) (CFloat) v;
(void) (CDouble) v;
- (void) (VoidPtr) v;
- (void) (CharPtr) 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')}}
}
void testLong(Long v) {
@@ -157,3 +157,12 @@ void testCharPtr(CharPtr v) {
(void) (VoidPtr) v;
(void) (CharPtr) v;
}
+
+typedef enum { x_a, x_b } X;
+void *intToPointerCast2(X x) {
+ return (void*)x;
+}
+
+void *intToPointerCast3() {
+ return (void*)(1 + 3);
+}
diff --git a/test/Sema/check-increment.c b/test/Sema/check-increment.c
index 070ea74f6800..ae33c2085666 100644
--- a/test/Sema/check-increment.c
+++ b/test/Sema/check-increment.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int printf(const char *, ...);
typedef int *pint;
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 406ade81aa0d..b5d4ef5d12ca 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -93,8 +93,8 @@ int ints(long a, unsigned long b) {
// (C,b)
(C == (unsigned long) b) +
(C == (unsigned int) b) +
- (C == (unsigned short) b) +
- (C == (unsigned char) b) +
+ (C == (unsigned short) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned short' is always false}}
+ (C == (unsigned char) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned char' is always false}}
((long) C == b) +
((int) C == b) +
((short) C == b) +
@@ -105,8 +105,8 @@ int ints(long a, unsigned long b) {
((signed char) C == (unsigned char) b) +
(C < (unsigned long) b) +
(C < (unsigned int) b) +
- (C < (unsigned short) b) +
- (C < (unsigned char) b) +
+ (C < (unsigned short) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned short' is always false}}
+ (C < (unsigned char) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned char' is always false}}
((long) C < b) +
((int) C < b) +
((short) C < b) +
@@ -123,8 +123,8 @@ int ints(long a, unsigned long b) {
(a == (unsigned char) C) +
((long) a == C) +
((int) a == C) +
- ((short) a == C) +
- ((signed char) a == C) +
+ ((short) a == C) + // expected-warning {{comparison of constant 65536 with expression of type 'short' is always false}}
+ ((signed char) a == C) + // expected-warning {{comparison of constant 65536 with expression of type 'signed char' is always false}}
((long) a == (unsigned long) C) +
((int) a == (unsigned int) C) +
((short) a == (unsigned short) C) +
@@ -135,8 +135,8 @@ int ints(long a, unsigned long b) {
(a < (unsigned char) C) +
((long) a < C) +
((int) a < C) +
- ((short) a < C) +
- ((signed char) a < C) +
+ ((short) a < C) + // expected-warning {{comparison of constant 65536 with expression of type 'short' is always true}}
+ ((signed char) a < C) + // expected-warning {{comparison of constant 65536 with expression of type 'signed char' is always true}}
((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) C) +
@@ -145,8 +145,8 @@ int ints(long a, unsigned long b) {
// (0x80000,b)
(0x80000 == (unsigned long) b) +
(0x80000 == (unsigned int) b) +
- (0x80000 == (unsigned short) b) +
- (0x80000 == (unsigned char) b) +
+ (0x80000 == (unsigned short) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned short' is always false}}
+ (0x80000 == (unsigned char) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned char' is always false}}
((long) 0x80000 == b) +
((int) 0x80000 == b) +
((short) 0x80000 == b) +
@@ -157,8 +157,8 @@ int ints(long a, unsigned long b) {
((signed char) 0x80000 == (unsigned char) b) +
(0x80000 < (unsigned long) b) +
(0x80000 < (unsigned int) b) +
- (0x80000 < (unsigned short) b) +
- (0x80000 < (unsigned char) b) +
+ (0x80000 < (unsigned short) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned short' is always false}}
+ (0x80000 < (unsigned char) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned char' is always false}}
((long) 0x80000 < b) +
((int) 0x80000 < b) +
((short) 0x80000 < b) +
@@ -175,8 +175,8 @@ int ints(long a, unsigned long b) {
(a == (unsigned char) 0x80000) +
((long) a == 0x80000) +
((int) a == 0x80000) +
- ((short) a == 0x80000) +
- ((signed char) a == 0x80000) +
+ ((short) a == 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'short' is always false}}
+ ((signed char) a == 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always false}}
((long) a == (unsigned long) 0x80000) +
((int) a == (unsigned int) 0x80000) +
((short) a == (unsigned short) 0x80000) +
@@ -187,8 +187,8 @@ int ints(long a, unsigned long b) {
(a < (unsigned char) 0x80000) +
((long) a < 0x80000) +
((int) a < 0x80000) +
- ((short) a < 0x80000) +
- ((signed char) a < 0x80000) +
+ ((short) a < 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'short' is always true}}
+ ((signed char) a < 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always true}}
((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) 0x80000) +
diff --git a/test/Sema/complex-promotion.c b/test/Sema/complex-promotion.c
index 23c3b6895314..a59bf718931b 100644
--- a/test/Sema/complex-promotion.c
+++ b/test/Sema/complex-promotion.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// expected-no-diagnostics
float a;
diff --git a/test/Sema/compound-literal.c b/test/Sema/compound-literal.c
index beec6ca66e8f..c5c0c17143fa 100644
--- a/test/Sema/compound-literal.c
+++ b/test/Sema/compound-literal.c
@@ -1,19 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// REQUIRES: LP64
struct foo { int a, b; };
static struct foo t = (struct foo){0,0};
static struct foo t1 = __builtin_choose_expr(0, (struct foo){0,0}, (struct foo){0,0});
static struct foo t2 = {0,0};
-static struct foo t3 = t2; // -expected-error {{initializer element is not a compile-time constant}}
+static struct foo t3 = t2; // expected-error {{initializer element is not a compile-time constant}}
static int *p = (int []){2,4};
static int x = (int){1};
-static int *p2 = (int []){2,x}; // -expected-error {{initializer element is not a compile-time constant}}
-static long *p3 = (long []){2,"x"}; // -expected-warning {{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [2]'}}
+static int *p2 = (int []){2,x}; // expected-error {{initializer element is not a compile-time constant}}
+static long *p3 = (long []){2,"x"}; // expected-warning {{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [2]'}}
-typedef struct { } cache_t; // -expected-warning{{empty struct is a GNU extension}}
-static cache_t clo_I1_cache = ((cache_t) { } ); // -expected-warning{{use of GNU empty initializer extension}}
+typedef struct { } cache_t; // expected-warning{{empty struct is a GNU extension}}
+static cache_t clo_I1_cache = ((cache_t) { } ); // expected-warning{{use of GNU empty initializer extension}}
typedef struct Test {int a;int b;} Test;
static Test* ll = &(Test) {0,0};
@@ -26,11 +27,11 @@ int main(int argc, char **argv) {
}
struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}}
-struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // -expected-error {{variable has incomplete type}}
+struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}}
void IncompleteFunc(unsigned x) {
- struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // -expected-error {{variable-sized object may not be initialized}}
- (void){1,2,3}; // -expected-error {{variable has incomplete type}}
- (void(void)) { 0 }; // -expected-error{{illegal initializer type 'void (void)'}}
+ struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{variable-sized object may not be initialized}}
+ (void){1,2,3}; // expected-error {{variable has incomplete type}}
+ (void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}}
}
// PR6080
diff --git a/test/Sema/const-eval-64.c b/test/Sema/const-eval-64.c
index 5727a93e51fa..1290bf4dd85d 100644
--- a/test/Sema/const-eval-64.c
+++ b/test/Sema/const-eval-64.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s
+// expected-no-diagnostics
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
diff --git a/test/Sema/const-ptr-int-ptr-cast.c b/test/Sema/const-ptr-int-ptr-cast.c
index 8beaf9d4947c..73b4a8a74fd0 100644
--- a/test/Sema/const-ptr-int-ptr-cast.c
+++ b/test/Sema/const-ptr-int-ptr-cast.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// expected-no-diagnostics
#include <stdint.h>
diff --git a/test/Sema/constant-builtins-2.c b/test/Sema/constant-builtins-2.c
index 68b46bf19ad9..13d81fe13cbf 100644
--- a/test/Sema/constant-builtins-2.c
+++ b/test/Sema/constant-builtins-2.c
@@ -48,6 +48,9 @@ extern int f();
int h0 = __builtin_types_compatible_p(int, float);
//int h1 = __builtin_choose_expr(1, 10, f());
//int h2 = __builtin_expect(0, 0);
+int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f();
+int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
+int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
extern long int bi0;
extern __typeof__(__builtin_expect(0, 0)) bi0;
diff --git a/test/Sema/constant-builtins.c b/test/Sema/constant-builtins.c
index 5d67fc7cb717..c98f62dfc5a2 100644
--- a/test/Sema/constant-builtins.c
+++ b/test/Sema/constant-builtins.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify -pedantic
+// expected-no-diagnostics
// Math stuff
@@ -16,6 +17,9 @@ extern int f();
int h0 = __builtin_types_compatible_p(int,float);
//int h1 = __builtin_choose_expr(1, 10, f());
//int h2 = __builtin_expect(0, 0);
+int h3 = __builtin_bswap16(0x1234) == 0x3412 ? 1 : f();
+int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
+int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
short somefunc();
diff --git a/test/Sema/darwin-align-cast.c b/test/Sema/darwin-align-cast.c
index 208097481cdc..bd357edceddf 100644
--- a/test/Sema/darwin-align-cast.c
+++ b/test/Sema/darwin-align-cast.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef long unsigned int __darwin_size_t;
typedef long __darwin_ssize_t;
typedef __darwin_size_t size_t;
diff --git a/test/Sema/enum-packed.c b/test/Sema/enum-packed.c
index 0eb6c14dbe85..b6ba972ed686 100644
--- a/test/Sema/enum-packed.c
+++ b/test/Sema/enum-packed.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR7477
enum __attribute__((packed)) E {
diff --git a/test/Sema/expr-comma-c99.c b/test/Sema/expr-comma-c99.c
index d0883ba202f9..6e97a4fc4957 100644
--- a/test/Sema/expr-comma-c99.c
+++ b/test/Sema/expr-comma-c99.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c99
+// expected-no-diagnostics
// rdar://6095180
struct s { char c[17]; };
diff --git a/test/Sema/expr-comma.c b/test/Sema/expr-comma.c
index d3e4020af637..7902715915a2 100644
--- a/test/Sema/expr-comma.c
+++ b/test/Sema/expr-comma.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c89
+// expected-no-diagnostics
// rdar://6095180
struct s { char c[17]; };
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index a93e12ec390b..df3e25857c40 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -40,7 +40,7 @@ _Complex double test1() {
}
_Complex double test2() {
- return 1.0if; // expected-warning {{imaginary constants are an extension}}
+ return 1.0if; // expected-warning {{imaginary constants are a GNU extension}}
}
// rdar://6097308
diff --git a/test/Sema/format-string-percentm.c b/test/Sema/format-string-percentm.c
index 1ffc439af07a..02fea462946c 100644
--- a/test/Sema/format-string-percentm.c
+++ b/test/Sema/format-string-percentm.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i686-pc-linux-gnu
+// expected-no-diagnostics
// PR 4142 - support glibc extension to printf: '%m' (which prints strerror(errno)).
int printf(char const*,...);
diff --git a/test/Sema/format-strings-darwin.c b/test/Sema/format-strings-darwin.c
new file mode 100644
index 000000000000..5daf3e5c8b67
--- /dev/null
+++ b/test/Sema/format-strings-darwin.c
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -pedantic -DALLOWED %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple thumbv6-apple-ios4.0 -pedantic -DALLOWED %s
+
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-mingw32 -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-pc-win32 -pedantic %s
+
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-gnu -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd -pedantic %s
+
+int printf(const char *restrict, ...);
+int scanf(const char * restrict, ...) ;
+
+void test() {
+ int justRight = 1;
+ long tooLong = 2;
+
+ printf("%D", justRight);
+ printf("%D", tooLong);
+ printf("%U", justRight);
+ printf("%U", tooLong);
+ printf("%O", justRight);
+ printf("%O", tooLong);
+
+#ifdef ALLOWED
+ // expected-warning@-8 {{'D' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'd'?}}
+ // expected-warning@-8 {{'D' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'd'?}} expected-warning@-8 {{format specifies type 'int' but the argument has type 'long'}}
+ // expected-warning@-8 {{'U' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'u'?}}
+ // expected-warning@-8 {{'U' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'u'?}} expected-warning@-8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
+ // expected-warning@-8 {{'O' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'o'?}}
+ // expected-warning@-8 {{'O' conversion specifier is not supported by ISO C}} expected-note@-8 {{did you mean to use 'o'?}} expected-warning@-8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
+#else
+ // expected-warning@-15 {{invalid conversion specifier 'D'}}
+ // expected-warning@-15 {{invalid conversion specifier 'D'}}
+ // expected-warning@-15 {{invalid conversion specifier 'U'}}
+ // expected-warning@-15 {{invalid conversion specifier 'U'}}
+ // expected-warning@-15 {{invalid conversion specifier 'O'}}
+ // expected-warning@-15 {{invalid conversion specifier 'O'}}
+#endif
+}
+
+#ifdef ALLOWED
+void testPrintf(short x, long y) {
+ printf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ printf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ printf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+ printf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+ printf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+ printf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+
+ printf("%+'0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ printf("% '0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ printf("%#0.5lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+ printf("%'0.5lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+}
+
+void testScanf(short *x, long *y) {
+ scanf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ scanf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+ scanf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+ scanf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+ scanf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+ scanf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+}
+#endif
diff --git a/test/Sema/format-strings-gnu.c b/test/Sema/format-strings-gnu.c
new file mode 100644
index 000000000000..f4910856b00f
--- /dev/null
+++ b/test/Sema/format-strings-gnu.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple thumbv6-apple-ios4.0 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-mingw32 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-pc-win32 %s
+
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-gnu -DALLOWED %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-freebsd -DALLOWED %s
+
+int printf(const char *restrict, ...);
+int scanf(const char * restrict, ...) ;
+
+void test() {
+ long notLongEnough = 1;
+ long long quiteLong = 2;
+
+ printf("%Ld", notLongEnough); // expected-warning {{format specifies type 'long long' but the argument has type 'long'}}
+ printf("%Ld", quiteLong);
+
+#ifndef ALLOWED
+ // expected-warning@-4 {{length modifier 'L' results in undefined behavior or no effect with 'd' conversion specifier}}
+ // expected-note@-5 {{did you mean to use 'll'?}}
+
+ // expected-warning@-6 {{length modifier 'L' results in undefined behavior or no effect with 'd' conversion specifier}}
+ // expected-note@-7 {{did you mean to use 'll'?}}
+#endif
+}
+
+void testAlwaysInvalid() {
+ // We should not suggest 'll' here!
+ printf("%Lc", 'a'); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 'c' conversion specifier}}
+ printf("%Ls", "a"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+
+#ifdef ALLOWED
+// PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx
+void printf_longlong(long long x, unsigned long long y) {
+ printf("%Ld", y); // no-warning
+ printf("%Lu", y); // no-warning
+ printf("%Lx", y); // no-warning
+ printf("%Ld", x); // no-warning
+ printf("%Lu", x); // no-warning
+ printf("%Lx", x); // no-warning
+ printf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+
+void scanf_longlong(long long *x, unsigned long long *y) {
+ scanf("%Ld", y); // no-warning
+ scanf("%Lu", y); // no-warning
+ scanf("%Lx", y); // no-warning
+ scanf("%Ld", x); // no-warning
+ scanf("%Lu", x); // no-warning
+ scanf("%Lx", x); // no-warning
+ scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+#endif
diff --git a/test/Sema/format-strings-non-iso.c b/test/Sema/format-strings-non-iso.c
index ed8095f10a4f..ee4594696138 100644
--- a/test/Sema/format-strings-non-iso.c
+++ b/test/Sema/format-strings-non-iso.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c99 -pedantic %s
+// RUN: %clang_cc1 -triple i686-linux-gnu -fsyntax-only -verify -std=c99 -pedantic %s
int printf(const char *restrict, ...);
int scanf(const char * restrict, ...);
@@ -7,8 +7,8 @@ void f(void) {
char *cp;
// The 'q' length modifier.
- printf("%qd", (long long)42); // expected-warning{{'q' length modifier is not supported by ISO C}}
- scanf("%qd", (long long *)0); // expected-warning{{'q' length modifier is not supported by ISO C}}
+ printf("%qd", (long long)42); // expected-warning{{'q' length modifier is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
+ scanf("%qd", (long long *)0); // expected-warning{{'q' length modifier is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
// The 'm' length modifier.
scanf("%ms", &cp); // expected-warning{{'m' length modifier is not supported by ISO C}}
@@ -18,11 +18,11 @@ void f(void) {
printf("%C", L'x'); // expected-warning{{'C' conversion specifier is not supported by ISO C}}
// Combining 'L' with an integer conversion specifier.
- printf("%Li", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'i' is not supported by ISO C}}
- printf("%Lo", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'o' is not supported by ISO C}}
- printf("%Lu", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'u' is not supported by ISO C}}
- printf("%Lx", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'x' is not supported by ISO C}}
- printf("%LX", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'X' is not supported by ISO C}}
+ printf("%Li", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'i' is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
+ printf("%Lo", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'o' is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
+ printf("%Lu", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'u' is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
+ printf("%Lx", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'x' is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
+ printf("%LX", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'X' is not supported by ISO C}} expected-note{{did you mean to use 'll'?}}
// Positional arguments.
printf("%1$d", 42); // expected-warning{{positional arguments are not supported by ISO C}}
diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c
index 235ac11faa1c..d66bed5ffbd6 100644
--- a/test/Sema/format-strings-scanf.c
+++ b/test/Sema/format-strings-scanf.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -Wformat-nonliteral %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral %s
// Test that -Wformat=0 works:
// RUN: %clang_cc1 -fsyntax-only -Werror -Wformat=0 %s
@@ -107,22 +107,12 @@ void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) {
// Test argument type check for the 'm' length modifier.
scanf("%ms", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
- scanf("%mS", fp); // expected-warning{{format specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
+ scanf("%mS", fp); // expected-warning-re{{format specifies type 'wchar_t \*\*' \(aka '[^']+'\) but the argument has type 'float \*'}}
scanf("%mc", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
- scanf("%mC", fp); // expected-warning{{format specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
+ scanf("%mC", fp); // expected-warning-re{{format specifies type 'wchar_t \*\*' \(aka '[^']+'\) but the argument has type 'float \*'}}
scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
}
-void test_longlong(long long *x, unsigned long long *y) {
- scanf("%Ld", y); // no-warning
- scanf("%Lu", y); // no-warning
- scanf("%Lx", y); // no-warning
- scanf("%Ld", x); // no-warning
- scanf("%Lu", x); // no-warning
- scanf("%Lx", x); // no-warning
- scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
-}
-
void test_quad(int *x, long long *llx) {
scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
scanf("%qd", llx); // no-warning
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 86b9296108c6..8fb1218b99ac 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -117,6 +117,7 @@ void check_writeback_specifier()
printf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
printf("%Ln", 0); // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}}
+ // expected-note@-1{{did you mean to use 'll'?}}
}
void check_invalid_specifier(FILE* fp, char *buf)
@@ -531,17 +532,6 @@ void pr9751() {
0.0); // expected-warning{{format specifies}}
}
-// PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx
-void printf_longlong(long long x, unsigned long long y) {
- printf("%Ld", y); // no-warning
- printf("%Lu", y); // no-warning
- printf("%Lx", y); // no-warning
- printf("%Ld", x); // no-warning
- printf("%Lu", x); // no-warning
- printf("%Lx", x); // no-warning
- printf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
-}
-
void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);
void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 7076bdf3bd1f..ff8e003cd722 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -129,3 +129,7 @@ void test_x() {
enum e0 {one};
void f3();
void f3(enum e0 x) {}
+
+enum incomplete_enum;
+void f4(); // expected-note {{previous declaration is here}}
+void f4(enum incomplete_enum); // expected-error {{conflicting types for 'f4'}}
diff --git a/test/Sema/heinous-extensions-on.c b/test/Sema/heinous-extensions-on.c
index 176f4727ef2b..5b00407b1736 100644
--- a/test/Sema/heinous-extensions-on.c
+++ b/test/Sema/heinous-extensions-on.c
@@ -3,7 +3,7 @@
void foo() {
int a;
// PR3788
- asm("nop" : : "m"((int)(a))); // expected-warning {{cast in a inline asm context requiring an l-value}}
+ asm("nop" : : "m"((int)(a))); // expected-warning {{cast in an inline asm context requiring an l-value}}
// PR3794
- asm("nop" : "=r"((unsigned)a)); // expected-warning {{cast in a inline asm context requiring an l-value}}
+ asm("nop" : "=r"((unsigned)a)); // expected-warning {{cast in an inline asm context requiring an l-value}}
}
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index ee61ac34a81a..e7b42c4e9a14 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -ffreestanding -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99
+// RUN: %clang %s -ffreestanding -Wno-int-to-pointer-cast -fsyntax-only -Xclang -verify -pedantic -fpascal-strings -std=c99
#include <stdint.h>
#include <limits.h>
diff --git a/test/Sema/implicit-builtin-freestanding.c b/test/Sema/implicit-builtin-freestanding.c
index 505e5221eff8..385cf1f751ca 100644
--- a/test/Sema/implicit-builtin-freestanding.c
+++ b/test/Sema/implicit-builtin-freestanding.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// expected-no-diagnostics
int malloc(int a) { return a; }
diff --git a/test/Sema/init-struct-qualified.c b/test/Sema/init-struct-qualified.c
index 49ec7cc5e060..9d18e224f8eb 100644
--- a/test/Sema/init-struct-qualified.c
+++ b/test/Sema/init-struct-qualified.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify < %s
+// expected-no-diagnostics
typedef float CGFloat;
typedef struct _NSPoint { CGFloat x; CGFloat y; } NSPoint;
typedef struct _NSSize { CGFloat width; CGFloat height; } NSSize;
diff --git a/test/Sema/init-vector.c b/test/Sema/init-vector.c
index f0cf32bd3f9c..a95e789e3a1b 100644
--- a/test/Sema/init-vector.c
+++ b/test/Sema/init-vector.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef float __attribute__((vector_size (16))) v4f_t;
diff --git a/test/Sema/int-arith-convert.c b/test/Sema/int-arith-convert.c
index c56ab3b76302..0f425bd0e45b 100644
--- a/test/Sema/int-arith-convert.c
+++ b/test/Sema/int-arith-convert.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple=i686-linux-gnu -fsyntax-only -verify %s
+// expected-no-diagnostics
// Check types are the same through redeclaration
unsigned long x;
diff --git a/test/Sema/invalid-decl.c b/test/Sema/invalid-decl.c
index 2699b254926a..b2c2aaf1a0f0 100644
--- a/test/Sema/invalid-decl.c
+++ b/test/Sema/invalid-decl.c
@@ -29,3 +29,12 @@ typedef struct {
void f(StructType *buf) {
buf->fun = 0;
}
+
+// rdar://11743706
+static void bar(hid_t, char); // expected-error {{expected identifier}}
+
+static void bar(hid_t p, char); // expected-error {{unknown type name 'hid_t'}}
+
+void foo() {
+ (void)bar;
+}
diff --git a/test/Sema/knr-variadic-def.c b/test/Sema/knr-variadic-def.c
index 6d5d63208bf0..934f32fd26b1 100644
--- a/test/Sema/knr-variadic-def.c
+++ b/test/Sema/knr-variadic-def.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// expected-no-diagnostics
// PR4287
#include <stdarg.h>
diff --git a/test/Sema/many-logical-ops.c b/test/Sema/many-logical-ops.c
index 09a76841032f..ec3bbda4dd4c 100644
--- a/test/Sema/many-logical-ops.c
+++ b/test/Sema/many-logical-ops.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wconstant-conversion -verify %s
+// expected-no-diagnostics
// rdar://10913206&10941790
// Check that we don't get stack overflow trying to evaluate a huge number of
diff --git a/test/Sema/member-reference.c b/test/Sema/member-reference.c
index 7bda14303a2d..edbbea59ac87 100644
--- a/test/Sema/member-reference.c
+++ b/test/Sema/member-reference.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// expected-no-diagnostics
struct simple { int i; };
diff --git a/test/Sema/mms-bitfields.c b/test/Sema/mms-bitfields.c
new file mode 100644
index 000000000000..d238a7a10d0d
--- /dev/null
+++ b/test/Sema/mms-bitfields.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -mms-bitfields -fsyntax-only -verify -triple x86_64-apple-darwin9 %s
+// expected-no-diagnostics
+
+// The -mms-bitfields commandline parameter should behave the same
+// as the ms_struct attribute.
+struct
+{
+ int a : 1;
+ short b : 1;
+} t;
+
+// MS pads out bitfields between different types.
+static int arr[(sizeof(t) == 8) ? 1 : -1];
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
new file mode 100644
index 000000000000..f6a0fdcb42eb
--- /dev/null
+++ b/test/Sema/ms-inline-asm.c
@@ -0,0 +1,35 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fenable-experimental-ms-inline-asm -Wno-microsoft -verify -fsyntax-only
+
+void t1(void) {
+ __asm __asm // expected-error {{__asm used with no assembly instructions}}
+}
+
+void f() {
+ int foo;
+ __asm {
+ mov eax, eax
+ .unknowndirective // expected-error {{unknown directive}}
+ }
+ f();
+ __asm {
+ mov eax, 1+=2 // expected-error 2 {{unknown token in expression}}
+ }
+ f();
+ __asm {
+ mov eax, 1+++ // expected-error 2 {{unknown token in expression}}
+ }
+ f();
+ __asm {
+ mov eax, TYPE cat // expected-error {{Unable to lookup TYPE of expr!}}
+ }
+ f();
+ __asm {
+ mov eax, SIZE foo // expected-error {{Unsupported directive!}}
+ }
+ f();
+ __asm {
+ mov eax, LENGTH foo // expected-error {{Unsupported directive!}}
+ }
+
+}
diff --git a/test/Sema/ms_wide_predefined_expr.cpp b/test/Sema/ms_wide_predefined_expr.cpp
index 8e816e00b37a..d56d1576cd0c 100644
--- a/test/Sema/ms_wide_predefined_expr.cpp
+++ b/test/Sema/ms_wide_predefined_expr.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions
+// expected-no-diagnostics
// Wide character predefined identifiers
#define _STR2WSTR(str) L##str
diff --git a/test/Sema/no-format-y2k-turnsoff-format.c b/test/Sema/no-format-y2k-turnsoff-format.c
index b206ecdfc155..a26a0ce95709 100644
--- a/test/Sema/no-format-y2k-turnsoff-format.c
+++ b/test/Sema/no-format-y2k-turnsoff-format.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wformat -Wno-format-y2k
+// RUN: %clang_cc1 -verify -fsyntax-only -Wformat -Wno-format-y2k %s
// rdar://9504680
void foo(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
diff --git a/test/Sema/outof-range-constant-compare.c b/test/Sema/outof-range-constant-compare.c
new file mode 100644
index 000000000000..4b1637c46c5e
--- /dev/null
+++ b/test/Sema/outof-range-constant-compare.c
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wtautological-constant-out-of-range-compare -verify %s
+// rdar://12202422
+
+int value(void);
+
+int main()
+{
+ int a = value();
+ if (a == 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a != 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (a < 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (a <= 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (a > 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a >= 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+
+ if (0x1234567812345678L == a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (0x1234567812345678L != a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (0x1234567812345678L < a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (0x1234567812345678L <= a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (0x1234567812345678L > a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (0x1234567812345678L >= a) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (a == 0x1234567812345678LL) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a == -0x1234567812345678L) // expected-warning {{comparison of constant -1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a < -0x1234567812345678L) // expected-warning {{comparison of constant -1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a > -0x1234567812345678L) // expected-warning {{comparison of constant -1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+ if (a <= -0x1234567812345678L) // expected-warning {{comparison of constant -1311768465173141112 with expression of type 'int' is always false}}
+ return 0;
+ if (a >= -0x1234567812345678L) // expected-warning {{comparison of constant -1311768465173141112 with expression of type 'int' is always true}}
+ return 0;
+
+
+ if (a == 0x12345678L) // no warning
+ return 1;
+
+ short s = value();
+ if (s == 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+ if (s != 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ if (s < 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ if (s <= 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ if (s > 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+ if (s >= 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+
+ if (0x1234567812345678L == s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+ if (0x1234567812345678L != s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ if (0x1234567812345678L < s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+ if (0x1234567812345678L <= s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always false}}
+ return 0;
+ if (0x1234567812345678L > s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ if (0x1234567812345678L >= s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
+ return 0;
+ long l = value();
+ if (l == 0x1234567812345678L)
+ return 0;
+ if (l != 0x1234567812345678L)
+ return 0;
+ if (l < 0x1234567812345678L)
+ return 0;
+ if (l <= 0x1234567812345678L)
+ return 0;
+ if (l > 0x1234567812345678L)
+ return 0;
+ if (l >= 0x1234567812345678L)
+ return 0;
+
+ if (0x1234567812345678L == l)
+ return 0;
+ if (0x1234567812345678L != l)
+ return 0;
+ if (0x1234567812345678L < l)
+ return 0;
+ if (0x1234567812345678L <= l)
+ return 0;
+ if (0x1234567812345678L > l)
+ return 0;
+ if (0x1234567812345678L >= l)
+ return 0;
+
+ unsigned un = 0;
+ if (un == 0x0000000000000000L)
+ return 0;
+ if (un != 0x0000000000000000L)
+ return 0;
+ if (un < 0x0000000000000000L)
+ return 0;
+ if (un <= 0x0000000000000000L)
+ return 0;
+ if (un > 0x0000000000000000L)
+ return 0;
+ if (un >= 0x0000000000000000L)
+ return 0;
+
+ if (0x0000000000000000L == un)
+ return 0;
+ if (0x0000000000000000L != un)
+ return 0;
+ if (0x0000000000000000L < un)
+ return 0;
+ if (0x0000000000000000L <= un)
+ return 0;
+ if (0x0000000000000000L > un)
+ return 0;
+ if (0x0000000000000000L >= un)
+ return 0;
+ float fl = 0;
+ if (fl == 0x0000000000000000L) // no warning
+ return 0;
+
+ float dl = 0;
+ if (dl == 0x0000000000000000L) // no warning
+ return 0;
+
+ enum E {
+ yes,
+ no,
+ maybe
+ };
+ enum E e;
+
+ if (e == 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'enum E' is always false}}
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/overloaded-func-transparent-union.c b/test/Sema/overloaded-func-transparent-union.c
index fa0314e946f2..acdc5898b026 100644
--- a/test/Sema/overloaded-func-transparent-union.c
+++ b/test/Sema/overloaded-func-transparent-union.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar:// 9129552
// PR9406
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index 9751336018b7..c3b3aa77c5e6 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -13,13 +13,13 @@ void if_assign(void) {
void bitwise_rel(unsigned i) {
(void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}} \
// expected-note{{place parentheses around the & expression to evaluate it first}} \
- // expected-note{{place parentheses around the == expression to silence this warning}}
+ // expected-note{{place parentheses around the '==' expression to silence this warning}}
(void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}} \
// expected-note{{place parentheses around the & expression to evaluate it first}} \
- // expected-note{{place parentheses around the == expression to silence this warning}}
+ // expected-note{{place parentheses around the '==' expression to silence this warning}}
(void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}} \
// expected-note{{place parentheses around the & expression to evaluate it first}} \
- // expected-note{{place parentheses around the < expression to silence this warning}}
+ // expected-note{{place parentheses around the '<' expression to silence this warning}}
(void)((i & 0x2) == 0);
(void)(i & (0x2 == 0));
// Eager logical op
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
index 767416677e00..8f5f24652dd7 100644
--- a/test/Sema/parentheses.cpp
+++ b/test/Sema/parentheses.cpp
@@ -22,6 +22,8 @@ public:
operator int();
Stream &operator<<(int);
Stream &operator<<(const char*);
+ Stream &operator>>(int);
+ Stream &operator>>(const char*);
};
void f(Stream& s, bool b) {
@@ -45,3 +47,13 @@ void test(S *s, bool (S::*m_ptr)()) {
// Don't crash on unusual member call expressions.
(void)((s->*m_ptr)() ? "foo" : "bar");
}
+
+void test(int a, int b, int c) {
+ (void)(a >> b + c); // expected-warning {{operator '>>' has lower precedence than '+'; '+' will be evaluated first}} \
+ expected-note {{place parentheses around the '+' expression to silence this warning}}
+ (void)(a - b << c); // expected-warning {{operator '<<' has lower precedence than '-'; '-' will be evaluated first}} \
+ expected-note {{place parentheses around the '-' expression to silence this warning}}
+ Stream() << b + c;
+ Stream() >> b + c; // expected-warning {{operator '>>' has lower precedence than '+'; '+' will be evaluated first}} \
+ expected-note {{place parentheses around the '+' expression to silence this warning}}
+}
diff --git a/test/Sema/pragma-align-mac68k.c b/test/Sema/pragma-align-mac68k.c
index fb8da515bbc7..fd93fcbd5ca4 100644
--- a/test/Sema/pragma-align-mac68k.c
+++ b/test/Sema/pragma-align-mac68k.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <stddef.h>
@@ -96,3 +97,15 @@ extern int a11_0[offsetof(struct s11, f0) == 0 ? 1 : -1];
extern int a11_1[offsetof(struct s11, f1) == 2 ? 1 : -1];
extern int a11_2[sizeof(struct s11) == 10 ? 1 : -1];
extern int a11_3[__alignof(struct s11) == 2 ? 1 : -1];
+
+#pragma options align=reset
+
+void f12(void) {
+ #pragma options align=mac68k
+ struct s12 {
+ char f0;
+ int f1;
+ };
+ #pragma options align=reset
+ extern int a12[sizeof(struct s12) == 6 ? 1 : -1];
+}
diff --git a/test/Sema/pragma-align-packed.c b/test/Sema/pragma-align-packed.c
index 74fbd13d162b..b8daf40b2c82 100644
--- a/test/Sema/pragma-align-packed.c
+++ b/test/Sema/pragma-align-packed.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
#pragma pack(push, 1)
struct s0 {
diff --git a/test/Sema/pragma-ms_struct.c b/test/Sema/pragma-ms_struct.c
index d76ee8bab3eb..6533320e518d 100644
--- a/test/Sema/pragma-ms_struct.c
+++ b/test/Sema/pragma-ms_struct.c
@@ -31,6 +31,12 @@ struct S {
unsigned long bf_2 : 12;
} __attribute__((ms_struct)) t2;
+enum
+{
+ A = 0,
+ B,
+ C
+} __attribute__((ms_struct)) e1; // expected-warning {{'ms_struct' attribute ignored}}
// rdar://10513599
#pragma ms_struct on
diff --git a/test/Sema/pragma-pack-2.c b/test/Sema/pragma-pack-2.c
index 4a4c202c71ad..3696a22d5aa5 100644
--- a/test/Sema/pragma-pack-2.c
+++ b/test/Sema/pragma-pack-2.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
+// expected-no-diagnostics
#include <stddef.h>
diff --git a/test/Sema/pragma-pack-3.c b/test/Sema/pragma-pack-3.c
index d97359e45b71..e7a6cee55057 100644
--- a/test/Sema/pragma-pack-3.c
+++ b/test/Sema/pragma-pack-3.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
+// expected-no-diagnostics
// Stack: [], Alignment: 8
diff --git a/test/Sema/pragma-pack-4.c b/test/Sema/pragma-pack-4.c
index b06fc0eaf15f..6a09e14d88cf 100644
--- a/test/Sema/pragma-pack-4.c
+++ b/test/Sema/pragma-pack-4.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://problem/7095436
#pragma pack(4)
diff --git a/test/Sema/pragma-pack-5.c b/test/Sema/pragma-pack-5.c
index 95bbe1fe7e94..24bd4cd7d922 100644
--- a/test/Sema/pragma-pack-5.c
+++ b/test/Sema/pragma-pack-5.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -fsyntax-only -verify -ffreestanding
+// expected-no-diagnostics
// <rdar://problem/10494810> and PR9560
// Check #pragma pack handling with bitfields.
diff --git a/test/Sema/pragma-pack-6.c b/test/Sema/pragma-pack-6.c
index 40659c23bda8..c87c99d5dab9 100644
--- a/test/Sema/pragma-pack-6.c
+++ b/test/Sema/pragma-pack-6.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
+// expected-no-diagnostics
// Pragma pack handling with tag declarations
diff --git a/test/Sema/pragma-pack-and-options-align.c b/test/Sema/pragma-pack-and-options-align.c
index ebf1adee02f3..5bc7c83594cd 100644
--- a/test/Sema/pragma-pack-and-options-align.c
+++ b/test/Sema/pragma-pack-and-options-align.c
@@ -38,5 +38,16 @@ struct s3 {
};
extern int a[sizeof(struct s3) == 8 ? 1 : -1];
+#pragma pack(push,2)
+#pragma options align=power
+struct s4 {
+ char c;
+ int x;
+};
+#pragma pack(pop)
+#pragma options align=reset
+extern int a[sizeof(struct s4) == 8 ? 1 : -1];
+
/* expected-warning {{#pragma options align=reset failed: stack empty}} */ #pragma options align=reset
/* expected-warning {{#pragma pack(pop, ...) failed: stack empty}} */ #pragma pack(pop)
+
diff --git a/test/Sema/private-extern.c b/test/Sema/private-extern.c
index 25591dc5b1f2..e480f3f22481 100644
--- a/test/Sema/private-extern.c
+++ b/test/Sema/private-extern.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-private-extern %s
static int g0; // expected-note{{previous definition}}
int g0; // expected-error{{non-static declaration of 'g0' follows static declaration}}
diff --git a/test/Sema/return-silent.c b/test/Sema/return-silent.c
index eb9641b7f3be..83c3a0a17905 100644
--- a/test/Sema/return-silent.c
+++ b/test/Sema/return-silent.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -Wno-return-type -fsyntax-only -verify
+// expected-no-diagnostics
int t14() {
return;
diff --git a/test/Sema/short-enums.c b/test/Sema/short-enums.c
index 6605c4e8fc07..9bf0064646a7 100644
--- a/test/Sema/short-enums.c
+++ b/test/Sema/short-enums.c
@@ -1,5 +1,6 @@
// RUN: not %clang_cc1 -fsyntax-only %s -verify
// RUN: %clang_cc1 -fshort-enums -fsyntax-only %s -verify
+// expected-no-diagnostics
enum x { A };
int t0[sizeof(enum x) == 1 ? 1 : -1];
diff --git a/test/Sema/stdcall-fastcall-x64.c b/test/Sema/stdcall-fastcall-x64.c
new file mode 100644
index 000000000000..d2a475eda1b8
--- /dev/null
+++ b/test/Sema/stdcall-fastcall-x64.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
+
+// CC qualifier can be applied only to functions
+int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' only applies to function types; type here is 'int'}}
+int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies to function types; type here is 'int'}}
+
+// Different CC qualifiers are not compatible
+void __attribute__((stdcall, fastcall)) foo3(void); // expected-warning{{calling convention 'stdcall' ignored for this target}} expected-warning {{calling convention 'fastcall' ignored for this target}}
+void __attribute__((stdcall)) foo4(); // expected-warning{{calling convention 'stdcall' ignored for this target}}
+void __attribute__((fastcall)) foo4(void); // expected-warning {{calling convention 'fastcall' ignored for this target}}
+
+// rdar://8876096
+void rdar8876096foo1(int i, int j) __attribute__((fastcall, cdecl)); // expected-warning{{calling convention 'fastcall' ignored for this target}}
+void rdar8876096foo2(int i, int j) __attribute__((fastcall, stdcall)); // expected-warning{{calling convention 'stdcall' ignored for this target}} expected-warning {{calling convention 'fastcall' ignored for this target}}
+void rdar8876096foo3(int i, int j) __attribute__((fastcall, regparm(2))); // expected-warning {{calling convention 'fastcall' ignored for this target}}
+void rdar8876096foo4(int i, int j) __attribute__((stdcall, cdecl)); // expected-warning{{calling convention 'stdcall' ignored for this target}}
+void rdar8876096foo5(int i, int j) __attribute__((stdcall, fastcall)); // expected-warning{{calling convention 'stdcall' ignored for this target}} expected-warning {{calling convention 'fastcall' ignored for this target}}
+void rdar8876096foo6(int i, int j) __attribute__((cdecl, fastcall)); // expected-warning {{calling convention 'fastcall' ignored for this target}}
+void rdar8876096foo7(int i, int j) __attribute__((cdecl, stdcall)); // expected-warning{{calling convention 'stdcall' ignored for this target}}
+void rdar8876096foo8(int i, int j) __attribute__((regparm(2), fastcall)); // expected-warning {{calling convention 'fastcall' ignored for this target}}
diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c
index eeacf94eb482..dea1fc5e7af7 100644
--- a/test/Sema/stdcall-fastcall.c
+++ b/test/Sema/stdcall-fastcall.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin10 %s
// CC qualifier can be applied only to functions
diff --git a/test/Sema/struct-cast.c b/test/Sema/struct-cast.c
index 30ef89242afc..8aa7ca90dd13 100644
--- a/test/Sema/struct-cast.c
+++ b/test/Sema/struct-cast.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify
+// expected-no-diagnostics
struct S {
int one;
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
index 6ca6a6096c4e..166d5eb1ff8d 100644
--- a/test/Sema/struct-packed-align.c
+++ b/test/Sema/struct-packed-align.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// Packed structs.
struct s {
diff --git a/test/Sema/surpress-deprecated.c b/test/Sema/surpress-deprecated.c
index dd673b9646ea..db9ab3f4eeb6 100644
--- a/test/Sema/surpress-deprecated.c
+++ b/test/Sema/surpress-deprecated.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-declarations -verify %s
+// expected-no-diagnostics
extern void OldFunction() __attribute__((deprecated));
int main (int argc, const char * argv[]) {
diff --git a/test/Sema/template-specialization.cpp b/test/Sema/template-specialization.cpp
new file mode 100644
index 000000000000..ae7bc332fcce
--- /dev/null
+++ b/test/Sema/template-specialization.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+// Verify the absence of assertion failures when solving calls to unresolved
+// template member functions.
+
+struct A {
+ template <typename T>
+ static void bar(int) { } // expected-note {{candidate template ignored: couldn't infer template argument 'T'}}
+};
+
+struct B {
+ template <int i>
+ static void foo() {
+ int array[i];
+ A::template bar(array[0]); // expected-error {{no matching function for call to 'bar'}}
+ }
+};
+
+int main() {
+ B::foo<4>(); // expected-note {{in instantiation of function template specialization 'B::foo<4>'}}
+ return 0;
+}
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
index e14540ba8417..bf2b1e4ee6a5 100644
--- a/test/Sema/tentative-decls.c
+++ b/test/Sema/tentative-decls.c
@@ -33,7 +33,8 @@ static int i3 = 5;
extern int i3;
// rdar://7703982
-__private_extern__ int pExtern; // expected-warning {{Use of __private_extern__ on tentative definition has unexpected behaviour}}
+__private_extern__ int pExtern; // expected-warning {{use of __private_extern__ on a declaration may not produce external symbol private to the linkage unit and is deprecated}} \
+// expected-note {{use __attribute__((visibility("hidden"))) attribute instead}}
int pExtern = 0;
int i4;
diff --git a/test/Sema/thread-specifier.c b/test/Sema/thread-specifier.c
index 0d439b1669c1..8c40fcd0a645 100644
--- a/test/Sema/thread-specifier.c
+++ b/test/Sema/thread-specifier.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-private-extern -verify -pedantic %s
__thread int t1;
__thread extern int t2; // expected-warning {{'__thread' before 'extern'}}
@@ -21,3 +21,10 @@ __thread int t15; // expected-note {{previous definition is here}}
int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
int t16; // expected-note {{previous definition is here}}
__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
+
+// PR13720
+__thread int thread_int;
+int *thread_int_ptr = &thread_int; // expected-error{{initializer element is not a compile-time constant}}
+void g() {
+ int *p = &thread_int; // This is perfectly fine, though.
+}
diff --git a/test/Sema/tls.c b/test/Sema/tls.c
index 3b2a441bfea8..4e5cfef0a3f3 100644
--- a/test/Sema/tls.c
+++ b/test/Sema/tls.c
@@ -17,4 +17,7 @@
// RUN: not %clang_cc1 -triple x86_64-pc-openbsd -fsyntax-only %s
// RUN: not %clang_cc1 -triple i386-pc-openbsd -fsyntax-only %s
+// Haiku does not suppport TLS.
+// RUN: not %clang_cc1 -triple i586-pc-haiku -fsyntax-only %s
+
__thread int x;
diff --git a/test/Sema/transparent-union-pointer.c b/test/Sema/transparent-union-pointer.c
index 31c93914b819..bf1fb17ac6f8 100644
--- a/test/Sema/transparent-union-pointer.c
+++ b/test/Sema/transparent-union-pointer.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
typedef union {
union wait *__uptr;
diff --git a/test/Sema/typedef-prototype.c b/test/Sema/typedef-prototype.c
index 8372154ce0ef..98b1ab809997 100644
--- a/test/Sema/typedef-prototype.c
+++ b/test/Sema/typedef-prototype.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef int unary_int_func(int arg);
unary_int_func add_one;
diff --git a/test/Sema/types.c b/test/Sema/types.c
index 3bec83e528b2..6ae1a92e0543 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -43,7 +43,7 @@ int i[(short)1];
enum e { e_1 };
extern int j[sizeof(enum e)]; // expected-note {{previous definition}}
-int j[42]; // expected-error {{redefinition of 'j' with a different type}}
+int j[42]; // expected-error {{redefinition of 'j' with a different type: 'int [42]' vs 'int [4]'}}
// rdar://6880104
_Decimal32 x; // expected-error {{GNU decimal type extension not supported}}
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index 634ae0dc4284..9e3dd9d2875b 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -508,3 +508,26 @@ int self_init_in_cond(int *p) {
int n = ((p && (0 || 1)) && (n = *p)) ? n : -1; // ok
return n;
}
+
+void test_analyzer_noreturn_aux() __attribute__((analyzer_noreturn));
+
+void test_analyzer_noreturn(int y) {
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
+ if (y) {
+ test_analyzer_noreturn_aux();
+ ++x; // no-warning
+ }
+ else {
+ ++x; // expected-warning {{variable 'x' is uninitialized when used here}}
+ }
+}
+void test_analyzer_noreturn_2(int y) {
+ int x;
+ if (y) {
+ test_analyzer_noreturn_aux();
+ }
+ else {
+ x = 1;
+ }
+ ++x; // no-warning
+}
diff --git a/test/Sema/unnamed-bitfield-init.c b/test/Sema/unnamed-bitfield-init.c
index f3cc49c34bf2..6fa18014179e 100644
--- a/test/Sema/unnamed-bitfield-init.c
+++ b/test/Sema/unnamed-bitfield-init.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef struct {
int a; int : 24; char b;
} S;
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 056d09a8713b..aa81febdbbde 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -122,3 +122,14 @@ void f(int i, ...) {
// PR8371
int fn5() __attribute__ ((__const));
+
+// OpenSSL has some macros like this; we shouldn't warn on the cast.
+#define M1(a, b) (long)foo((a), (b))
+// But, we should still warn on other subexpressions of casts in macros.
+#define M2 (long)0;
+void t11(int i, int j) {
+ M1(i, j); // no warning
+ M2; // expected-warning {{expression result unused}}
+}
+#undef M1
+#undef M2
diff --git a/test/Sema/va_arg_x86_64.c b/test/Sema/va_arg_x86_64.c
index 9f514c1f59e4..2659a1b6d4cd 100644
--- a/test/Sema/va_arg_x86_64.c
+++ b/test/Sema/va_arg_x86_64.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple=x86_64-unknown-freebsd7.0 %s
+// expected-no-diagnostics
// PR2631
char* foo(char *fmt, __builtin_va_list ap)
diff --git a/test/Sema/variadic-block.c b/test/Sema/variadic-block.c
index ba4bb71c9750..4f23cb8e0814 100644
--- a/test/Sema/variadic-block.c
+++ b/test/Sema/variadic-block.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only -fblocks
+// expected-no-diagnostics
#include <stdarg.h>
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index f1cf0134dc13..7fa6e86aa10e 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -10,22 +10,22 @@ void f()
t2 v2;
t3 v3;
- v2 = (t2)v1; // -expected-error {{invalid conversion between vector type \
+ v2 = (t2)v1; // expected-error {{invalid conversion between vector type \
't2' and 't1' of different size}}
- v1 = (t1)v2; // -expected-error {{invalid conversion between vector type \
+ v1 = (t1)v2; // expected-error {{invalid conversion between vector type \
't1' and 't2' of different size}}
v3 = (t3)v2;
- v1 = (t1)(char *)10; // -expected-error {{invalid conversion between vector \
+ v1 = (t1)(char *)10; // expected-error {{invalid conversion between vector \
type 't1' and scalar type 'char *'}}
v1 = (t1)(long long)10;
- v1 = (t1)(short)10; // -expected-error {{invalid conversion between vector \
+ v1 = (t1)(short)10; // expected-error {{invalid conversion between vector \
type 't1' and integer type 'short' of different size}}
long long r1 = (long long)v1;
- short r2 = (short)v1; // -expected-error {{invalid conversion between vector \
+ short r2 = (short)v1; // expected-error {{invalid conversion between vector \
type 't1' and integer type 'short' of different size}}
- char *r3 = (char *)v1; // -expected-error {{invalid conversion between vector\
+ char *r3 = (char *)v1; // expected-error {{invalid conversion between vector\
type 't1' and scalar type 'char *'}}
}
diff --git a/test/Sema/vfprintf-valid-redecl.c b/test/Sema/vfprintf-valid-redecl.c
index 14fbbc47ddbc..5c5ce8d12b00 100644
--- a/test/Sema/vfprintf-valid-redecl.c
+++ b/test/Sema/vfprintf-valid-redecl.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -pedantic -verify
+// expected-no-diagnostics
// PR4290
// The following declaration is compatible with vfprintf, so we shouldn't
diff --git a/test/Sema/warn-bad-function-cast.c b/test/Sema/warn-bad-function-cast.c
new file mode 100644
index 000000000000..41a3f7824e91
--- /dev/null
+++ b/test/Sema/warn-bad-function-cast.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wbad-function-cast -triple x86_64-unknown-unknown -verify
+// rdar://9103192
+
+void vf(void);
+int if1(void);
+char if2(void);
+long if3(void);
+float rf1(void);
+double rf2(void);
+_Complex double cf(void);
+enum e { E1 } ef(void);
+_Bool bf(void);
+char *pf1(void);
+int *pf2(void);
+
+void
+foo(void)
+{
+ /* Casts to void types are always OK. */
+ (void)vf();
+ (void)if1();
+ (void)cf();
+ (const void)bf();
+ /* Casts to the same type or similar types are OK. */
+ (int)if1();
+ (long)if2();
+ (char)if3();
+ (float)rf1();
+ (long double)rf2();
+ (_Complex float)cf();
+ (enum f { F1 })ef();
+ (_Bool)bf();
+ (void *)pf1();
+ (char *)pf2();
+ /* All following casts issue warning */
+ (float)if1(); /* expected-warning {{cast from function call of type 'int' to non-matching type 'float'}} */
+ (double)if2(); /* expected-warning {{cast from function call of type 'char' to non-matching type 'double'}} */
+ (_Bool)if3(); /* expected-warning {{cast from function call of type 'long' to non-matching type '_Bool'}} */
+ (int)rf1(); /* expected-warning {{cast from function call of type 'float' to non-matching type 'int'}} */
+ (long)rf2(); /* expected-warning {{cast from function call of type 'double' to non-matching type 'long'}} */
+ (double)cf(); /* expected-warning {{cast from function call of type '_Complex double' to non-matching type 'double'}} */
+ (int)ef(); /* expected-warning {{cast from function call of type 'enum e' to non-matching type 'int'}} */
+ (int)bf(); /* expected-warning {{cast from function call of type '_Bool' to non-matching type 'int'}} */
+ (__SIZE_TYPE__)pf1(); /* expected-warning {{cast from function call of type 'char *' to non-matching type 'unsigned long'}} */
+ (__PTRDIFF_TYPE__)pf2(); /* expected-warning {{cast from function call of type 'int *' to non-matching type 'long'}} */
+}
+
diff --git a/test/Sema/warn-documentation-fixits.cpp b/test/Sema/warn-documentation-fixits.cpp
index 732b44db027a..a47b77637506 100644
--- a/test/Sema/warn-documentation-fixits.cpp
+++ b/test/Sema/warn-documentation-fixits.cpp
@@ -20,8 +20,52 @@ void test3(T aaa);
template<typename SomeTy, typename OtherTy>
void test4(SomeTy aaa, OtherTy bbb);
+// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+/// \deprecated
+void test_deprecated_1();
+
+// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+/// \deprecated
+void test_deprecated_2(int a);
+
+struct test_deprecated_3 {
+ // expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+ /// \deprecated
+ void test_deprecated_4();
+
+ // expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+ /// \deprecated
+ void test_deprecated_5() {
+ }
+};
+
+template<typename T>
+struct test_deprecated_6 {
+ // expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+ /// \deprecated
+ void test_deprecated_7();
+
+ // expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+ /// \deprecated
+ void test_deprecated_8() {
+ }
+};
+
+#define MY_ATTR_DEPRECATED __attribute__((deprecated))
+
+// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}}
+/// \deprecated
+void test_deprecated_9(int a);
+
// CHECK: fix-it:"{{.*}}":{5:12-5:22}:"a"
// CHECK: fix-it:"{{.*}}":{9:12-9:15}:"aaa"
// CHECK: fix-it:"{{.*}}":{13:13-13:23}:"T"
// CHECK: fix-it:"{{.*}}":{18:13-18:18}:"SomeTy"
+// CHECK: fix-it:"{{.*}}":{25:25-25:25}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{29:30-29:30}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{34:27-34:27}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{38:27-38:27}:" __attribute__((deprecated))"
+// 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"
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index d99520b6733e..5678fd94cb73 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -38,13 +38,13 @@ int test_html7(int);
int test_html8(int);
// expected-warning@+2 {{HTML start tag prematurely ended, expected attribute name or '>'}} expected-note@+1 {{HTML tag started here}}
-/** Aaa bbb<ccc ddd eee
+/** Aaa bbb<img ddd eee
* fff ggg.
*/
int test_html9(int);
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
-/** Aaa bbb<ccc ddd eee 42%
+/** Aaa bbb<img ddd eee 42%
* fff ggg.
*/
int test_html10(int);
@@ -218,9 +218,32 @@ int test_param12(int a);
/// \param aab Blah blah.
int test_param13(int aaa, int bbb);
+// expected-warning@+2 {{parameter 'aab' not found in the function declaration}} expected-note@+2 {{did you mean 'bbb'?}}
+/// \param aaa Blah blah.
+/// \param aab Blah blah.
+int test_param14(int aaa, int bbb);
+
// expected-warning@+1 {{parameter 'aab' not found in the function declaration}}
/// \param aab Blah blah.
-int test_param14(int bbb, int ccc);
+int test_param15(int bbb, int ccc);
+
+// expected-warning@+1 {{parameter 'aab' not found in the function declaration}}
+/// \param aab Ccc.
+/// \param aaa Aaa.
+/// \param bbb Bbb.
+int test_param16(int aaa, int bbb);
+
+// expected-warning@+2 {{parameter 'aab' not found in the function declaration}}
+/// \param aaa Aaa.
+/// \param aab Ccc.
+/// \param bbb Bbb.
+int test_param17(int aaa, int bbb);
+
+// expected-warning@+3 {{parameter 'aab' not found in the function declaration}}
+/// \param aaa Aaa.
+/// \param bbb Bbb.
+/// \param aab Ccc.
+int test_param18(int aaa, int bbb);
class C {
// expected-warning@+1 {{parameter 'aaa' not found in the function declaration}}
@@ -229,26 +252,56 @@ class C {
// expected-warning@+1 {{parameter 'aaa' not found in the function declaration}}
/// \param aaa Blah blah.
- int test_param15(int bbb, int ccc);
+ int test_param19(int bbb, int ccc);
};
// expected-warning@+1 {{parameter 'aab' not found in the function declaration}}
/// \param aab Blah blah.
template<typename T>
-void test_param16(int bbb, int ccc);
+void test_param20(int bbb, int ccc);
// expected-warning@+3 {{parameter 'a' is already documented}}
// expected-note@+1 {{previous documentation}}
/// \param a Aaa.
/// \param a Aaa.
-int test_param17(int a);
+int test_param21(int a);
// expected-warning@+4 {{parameter 'x2' is already documented}}
// expected-note@+2 {{previous documentation}}
/// \param x1 Aaa.
/// \param x2 Bbb.
/// \param x2 Ccc.
-int test_param18(int x1, int x2, int x3);
+int test_param22(int x1, int x2, int x3);
+
+// expected-warning@+2 {{parameter 'bbb' not found in the function declaration}} expected-note@+2 {{did you mean 'ccc'?}}
+/// \param aaa Meow.
+/// \param bbb Bbb.
+/// \returns aaa.
+typedef int test_param23(int aaa, int ccc);
+
+// expected-warning@+2 {{parameter 'bbb' not found in the function declaration}} expected-note@+2 {{did you mean 'ccc'?}}
+/// \param aaa Meow.
+/// \param bbb Bbb.
+/// \returns aaa.
+typedef int (*test_param24)(int aaa, int ccc);
+
+// expected-warning@+2 {{parameter 'bbb' not found in the function declaration}} expected-note@+2 {{did you mean 'ccc'?}}
+/// \param aaa Meow.
+/// \param bbb Bbb.
+/// \returns aaa.
+typedef int (* const test_param25)(int aaa, int ccc);
+
+// expected-warning@+2 {{parameter 'bbb' not found in the function declaration}} expected-note@+2 {{did you mean 'ccc'?}}
+/// \param aaa Meow.
+/// \param bbb Bbb.
+/// \returns aaa.
+typedef int (C::*test_param26)(int aaa, int ccc);
+
+typedef int (*test_param27)(int aaa);
+
+// expected-warning@+1 {{'\param' command used in a comment that is not attached to a function declaration}}
+/// \param aaa Meow.
+typedef test_param27 test_param28;
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
@@ -324,6 +377,52 @@ using test_tparam14 = test_tparam13<T, int>;
template<typename T>
using test_tparam15 = test_tparam13<T, int>;
+
+/// Aaa
+/// \deprecated Bbb
+void test_deprecated_1(int a) __attribute__((deprecated));
+
+// We don't want \deprecated to warn about empty paragraph. It is fine to use
+// \deprecated by itself without explanations.
+
+/// Aaa
+/// \deprecated
+void test_deprecated_2(int a) __attribute__((deprecated));
+
+/// Aaa
+/// \deprecated
+void test_deprecated_3(int a) __attribute__((availability(macosx,introduced=10.4)));
+
+/// Aaa
+/// \deprecated
+void test_deprecated_4(int a) __attribute__((unavailable));
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+3 {{add a deprecation attribute to the declaration to silence this warning}}
+/// Aaa
+/// \deprecated
+void test_deprecated_5(int a);
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+3 {{add a deprecation attribute to the declaration to silence this warning}}
+/// Aaa
+/// \deprecated
+void test_deprecated_6(int a) {
+}
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}}
+/// Aaa
+/// \deprecated
+template<typename T>
+void test_deprecated_7(T aaa);
+
+
+/// \invariant aaa
+void test_invariant_1(int a);
+
+// expected-warning@+1 {{empty paragraph passed to '\invariant' command}}
+/// \invariant
+void test_invariant_2(int a);
+
+
// no-warning
/// \returns Aaa
int test_returns_right_decl_1(int);
@@ -403,6 +502,24 @@ enum test_returns_wrong_decl_8 {
namespace test_returns_wrong_decl_10 { };
+// expected-warning@+1 {{'\endverbatim' command does not terminate a verbatim text block}}
+/// \endverbatim
+int test_verbatim_1();
+
+// expected-warning@+1 {{'\endcode' command does not terminate a verbatim text block}}
+/// \endcode
+int test_verbatim_2();
+
+// FIXME: we give a bad diagnostic here because we throw away non-documentation
+// comments early.
+//
+// expected-warning@+3 {{'\endcode' command does not terminate a verbatim text block}}
+/// \code
+// foo
+/// \endcode
+int test_verbatim_3();
+
+
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
int test1; ///< \brief\author Aaa
@@ -714,3 +831,8 @@ inline void test_nocrash6()
*/
typedef const struct test_nocrash7 * test_nocrash8;
+// We used to crash on this.
+
+/// aaa \unknown aaa \unknown aaa
+int test_nocrash9;
+
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index d6af6edcc85d..8a894dca7003 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -Wdocumentation -Wdocumentation-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class -Wdocumentation -Wdocumentation-pedantic -verify %s
@class NSString;
@@ -91,3 +91,9 @@ int b;
- (void)test2:(NSString *)aaa;
@end
+// expected-warning@+2 {{parameter 'bbb' not found in the function declaration}} expected-note@+2 {{did you mean 'ccc'?}}
+/// \param aaa Meow.
+/// \param bbb Bbb.
+/// \returns aaa.
+typedef int (^test_param1)(int aaa, int ccc);
+
diff --git a/test/Sema/warn-gnu-designators.c b/test/Sema/warn-gnu-designators.c
index bdb3374288df..e55cfba0c589 100644
--- a/test/Sema/warn-gnu-designators.c
+++ b/test/Sema/warn-gnu-designators.c
@@ -1,2 +1,3 @@
// RUN: %clang_cc1 -Wno-gnu-designator -verify %s
+// expected-no-diagnostics
struct { int x, y, z[12]; } value = { x:17, .z [3 ... 5] = 7 };
diff --git a/test/Sema/warn-missing-variable-declarations.c b/test/Sema/warn-missing-variable-declarations.c
new file mode 100644
index 000000000000..631d3d213b01
--- /dev/null
+++ b/test/Sema/warn-missing-variable-declarations.c
@@ -0,0 +1,18 @@
+// RUN: %clang -Wmissing-variable-declarations -fsyntax-only -Xclang -verify %s
+
+int vbad1; // expected-warning{{no previous extern declaration for non-static variable 'vbad1'}}
+
+int vbad2;
+int vbad2 = 10; // expected-warning{{no previous extern declaration for non-static variable 'vbad2'}}
+
+struct {
+ int mgood1;
+} vbad3; // expected-warning{{no previous extern declaration for non-static variable 'vbad3'}}
+
+int vbad4;
+int vbad4 = 10; // expected-warning{{no previous extern declaration for non-static variable 'vbad4'}}
+extern int vbad4;
+
+extern int vgood1;
+int vgood1;
+int vgood1 = 10;
diff --git a/test/Sema/warn-type-safety-mpi-hdf5.c b/test/Sema/warn-type-safety-mpi-hdf5.c
index 9c2ee965866d..8c50cb24bb60 100644
--- a/test/Sema/warn-type-safety-mpi-hdf5.c
+++ b/test/Sema/warn-type-safety-mpi-hdf5.c
@@ -147,6 +147,10 @@ void test_mpi_predefined_types(
// Layout-compatible scalar types.
MPI_Send(int_buf, 1, MPI_INT); // no-warning
+ // Null pointer constant.
+ MPI_Send(0, 0, MPI_INT); // no-warning
+ MPI_Send(NULL, 0, MPI_INT); // no-warning
+
// Layout-compatible class types.
MPI_Send(pfi, 1, MPI_FLOAT_INT); // no-warning
MPI_Send(pii, 1, MPI_2INT); // no-warning
diff --git a/test/Sema/warn-type-safety.c b/test/Sema/warn-type-safety.c
index 6f548aa2567d..4ac453d380bd 100644
--- a/test/Sema/warn-type-safety.c
+++ b/test/Sema/warn-type-safety.c
@@ -80,6 +80,14 @@ void test_tag_mismatch(int *ptr)
C_func(ptr, 20); // should warn, but may cause false positives
}
+void test_null_pointer()
+{
+ C_func(0, C_tag); // no-warning
+ C_func((void *) 0, C_tag); // no-warning
+ C_func((int *) 0, C_tag); // no-warning
+ C_func((long *) 0, C_tag); // expected-warning {{argument type 'long *' doesn't match specified 'c' type tag that requires 'int *'}}
+}
+
// Check that we look through typedefs in the special case of allowing 'char'
// to be matched with 'signed char' or 'unsigned char'.
void E_func(void *ptr, int tag) __attribute__(( pointer_with_type_tag(e,1,2) ));
diff --git a/test/Sema/warn-type-safety.cpp b/test/Sema/warn-type-safety.cpp
index d053fbaa21fc..a73a9d9d2acc 100644
--- a/test/Sema/warn-type-safety.cpp
+++ b/test/Sema/warn-type-safety.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
typedef struct ompi_datatype_t *MPI_Datatype;
@@ -52,6 +52,8 @@ void test1(C *c, int *int_buf)
{
c->MPI_Send(int_buf, 1, MPI_INT); // no-warning
c->MPI_Send(int_buf, 1, MPI_FLOAT); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'float *'}}
+ c->MPI_Send(0, 0, MPI_INT); // no-warning
+ c->MPI_Send(nullptr, 0, MPI_INT); // no-warning
OperatorIntStar i;
c->MPI_Send(i, 1, MPI_INT); // no-warning
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 636513f62c70..2fbe1c78eb21 100644
--- a/test/Sema/warn-unreachable.c
+++ b/test/Sema/warn-unreachable.c
@@ -132,3 +132,12 @@ void PR9774(int *s) {
s[i] = 0;
}
+// Test case for <rdar://problem/11005770>. We should treat code guarded
+// by 'x & 0' and 'x * 0' as unreachable.
+void calledFun();
+void test_mul_and_zero(int x) {
+ if (x & 0) calledFun(); // expected-warning {{will never be executed}}
+ if (0 & x) calledFun(); // expected-warning {{will never be executed}}
+ if (x * 0) calledFun(); // expected-warning {{will never be executed}}
+ if (0 * x) calledFun(); // expected-warning {{will never be executed}}
+}
diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c
index 8f4cdcba881e..a334e71e5067 100644
--- a/test/Sema/warn-unused-function.c
+++ b/test/Sema/warn-unused-function.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-function -Wunneeded-internal-declaration -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wused-but-marked-unused -Wunused-function -Wunneeded-internal-declaration -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
@@ -54,3 +54,15 @@ void f13(void) {
char * const __attribute__((cleanup(cleanupMalloc))) a;
(void)a;
}
+
+// rdar://12233989
+extern void a(void) __attribute__((unused));
+extern void b(void) __attribute__((unused));
+
+void b(void)
+{
+}
+void a(void)
+{
+ b();
+}
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
index 28ec2f14ceb7..8708aa0f65c3 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -6,6 +6,8 @@ typedef __WCHAR_TYPE__ wchar_t;
#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
|| defined(_M_X64) || defined(SHORT_WCHAR)
#define WCHAR_T_TYPE unsigned short
+#elif defined(__arm)
+ #define WCHAR_T_TYPE unsigned int
#elif defined(__sun) || defined(__AuroraUX__)
#define WCHAR_T_TYPE long
#else /* Solaris or AuroraUX. */
diff --git a/test/Sema/weak-import-on-enum.c b/test/Sema/weak-import-on-enum.c
index 3a2c0e5b3a14..ad437693a10e 100644
--- a/test/Sema/weak-import-on-enum.c
+++ b/test/Sema/weak-import-on-enum.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://10277579
enum __attribute__((deprecated)) __attribute__((weak_import)) A {
diff --git a/test/SemaCXX/2008-01-11-BadWarning.cpp b/test/SemaCXX/2008-01-11-BadWarning.cpp
index b84e7c1cf862..e27c0848ef37 100644
--- a/test/SemaCXX/2008-01-11-BadWarning.cpp
+++ b/test/SemaCXX/2008-01-11-BadWarning.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+// expected-no-diagnostics
// rdar://5683899
void** f(void **Buckets, unsigned NumBuckets) {
return Buckets + NumBuckets;
diff --git a/test/SemaCXX/MicrosoftCompatibilityNoExceptions.cpp b/test/SemaCXX/MicrosoftCompatibilityNoExceptions.cpp
index d932b5dbbcea..14e5160e090b 100644
--- a/test/SemaCXX/MicrosoftCompatibilityNoExceptions.cpp
+++ b/test/SemaCXX/MicrosoftCompatibilityNoExceptions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-compatibility
+// expected-no-diagnostics
// PR13153
namespace std {}
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 0b72cd3e1fc0..6b43ea205af3 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -verify -fms-extensions -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions
// ::type_info is predeclared with forward class declartion
@@ -112,11 +112,11 @@ const int seventeen = 17;
typedef int Int;
struct X0 {
- enum E1 : Int { SomeOtherValue } field; // expected-warning{{enumeration types with a fixed underlying type are a Microsoft extension}}
+ enum E1 : Int { SomeOtherValue } field; // expected-warning{{enumeration types with a fixed underlying type are a C++11 extension}}
enum E1 : seventeen;
};
-enum : long long { // expected-warning{{enumeration types with a fixed underlying type are a Microsoft extension}}
+enum : long long { // expected-warning{{enumeration types with a fixed underlying type are a C++11 extension}}
SomeValue = 0x100000000
};
@@ -203,3 +203,4 @@ struct PR11150 {
void f() { int __except = 0; }
+void ::f(); // expected-warning{{extra qualification on member 'f'}}
diff --git a/test/SemaCXX/PR10447.cpp b/test/SemaCXX/PR10447.cpp
index 08644ada4a4b..5ba74aaba36c 100644
--- a/test/SemaCXX/PR10447.cpp
+++ b/test/SemaCXX/PR10447.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
// PR12223
namespace test1 {
diff --git a/test/SemaCXX/PR5086-ambig-resolution-enum.cpp b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
index b5aac5f09c16..eeb73f6f56c9 100644
--- a/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
+++ b/test/SemaCXX/PR5086-ambig-resolution-enum.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
class C {
public:
diff --git a/test/SemaCXX/PR6562.cpp b/test/SemaCXX/PR6562.cpp
index 854d9b058bc3..144fde68b178 100644
--- a/test/SemaCXX/PR6562.cpp
+++ b/test/SemaCXX/PR6562.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct X { ~X(); };
template <typename T>
diff --git a/test/SemaCXX/PR9884.cpp b/test/SemaCXX/PR9884.cpp
index ab883c4062c9..bb8bd6a56bff 100644
--- a/test/SemaCXX/PR9884.cpp
+++ b/test/SemaCXX/PR9884.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
class Base {
protected:
Base(int val);
diff --git a/test/SemaCXX/PR9902.cpp b/test/SemaCXX/PR9902.cpp
index 80086e445c5d..a34f99c12287 100644
--- a/test/SemaCXX/PR9902.cpp
+++ b/test/SemaCXX/PR9902.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
template <class _Tp, class _Up, bool = false>
struct __allocator_traits_rebind
diff --git a/test/SemaCXX/PR9908.cpp b/test/SemaCXX/PR9908.cpp
index fc090cc42f92..a15b637a03d2 100644
--- a/test/SemaCXX/PR9908.cpp
+++ b/test/SemaCXX/PR9908.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
template <class _Tp, class _Up>
struct __allocator_traits_rebind
diff --git a/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp
index cb5d38a097ef..a0f503abe6c8 100644
--- a/test/SemaCXX/__try.cpp
+++ b/test/SemaCXX/__try.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fborland-extensions -fcxx-exceptions %s
+// expected-no-diagnostics
// This test is from http://docwiki.embarcadero.com/RADStudio/en/Try
diff --git a/test/SemaCXX/ambiguous-conversion-show-overload.cpp b/test/SemaCXX/ambiguous-conversion-show-overload.cpp
new file mode 100644
index 000000000000..64296512ffd7
--- /dev/null
+++ b/test/SemaCXX/ambiguous-conversion-show-overload.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -fno-caret-diagnostics %s 2>&1 | FileCheck %s
+struct S {
+ S(void*);
+ S(char*);
+ S(unsigned char*);
+ S(signed char*);
+ S(unsigned short*);
+ S(signed short*);
+ S(unsigned int*);
+ S(signed int*);
+};
+void f(const S& s);
+void g() {
+ f(0);
+}
+// CHECK: {{conversion from 'int' to 'const S' is ambiguous}}
+// CHECK-NEXT: {{candidate constructor}}
+// CHECK-NEXT: {{candidate constructor}}
+// CHECK-NEXT: {{candidate constructor}}
+// CHECK-NEXT: {{candidate constructor}}
+// CHECK-NEXT: {{remaining 4 candidates omitted; pass -fshow-overloads=all to show them}}
diff --git a/test/SemaCXX/anonymous-union-cxx11.cpp b/test/SemaCXX/anonymous-union-cxx11.cpp
index 8e682ebcda3d..9f987a9681cd 100644
--- a/test/SemaCXX/anonymous-union-cxx11.cpp
+++ b/test/SemaCXX/anonymous-union-cxx11.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
+// expected-no-diagnostics
namespace PR12866 {
struct bar {
diff --git a/test/SemaCXX/ast-print.cpp b/test/SemaCXX/ast-print.cpp
new file mode 100644
index 000000000000..aeb4039d597d
--- /dev/null
+++ b/test/SemaCXX/ast-print.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -ast-print %s | FileCheck %s
+
+// CHECK: r;
+// CHECK-NEXT: (r->method());
+struct MyClass
+{
+ void method() {}
+};
+
+struct Reference
+{
+ MyClass* object;
+ MyClass* operator ->() { return object; }
+};
+
+void test1() {
+ Reference r;
+ (r->method());
+}
+
+// CHECK: if (int a = 1)
+// CHECK: while (int a = 1)
+// CHECK: switch (int a = 1)
+
+void test2()
+{
+ if (int a = 1) { }
+ while (int a = 1) { }
+ switch (int a = 1) { }
+}
+
+// CHECK: new (1) int;
+void *operator new (typeof(sizeof(1)), int, int = 2);
+void test3() {
+ new (1) int;
+}
+
+// CHECK: new X;
+struct X {
+ void *operator new (typeof(sizeof(1)), int = 2);
+};
+void test4() { new X; }
+
+// CHECK: for (int i = 2097, j = 42; false;)
+void test5() {
+ for (int i = 2097, j = 42; false;) {}
+}
+
+// CHECK: test6fn((int &)y);
+void test6fn(int& x);
+void test6() {
+ unsigned int y = 0;
+ test6fn((int&)y);
+}
+
+// CHECK: S s( 1, 2 );
+
+template <class S> void test7()
+{
+ S s( 1,2 );
+}
+
+
+// CHECK: t.~T();
+
+template <typename T> void test8(T t) { t.~T(); }
+
+
+// CHECK: enum E {
+// CHECK-NEXT: A,
+// CHECK-NEXT: B,
+// CHECK-NEXT: C
+// CHECK-NEXT: };
+// CHECK-NEXT: {{^[ ]+}}E a = A;
+
+struct test9
+{
+ void f()
+ {
+ enum E { A, B, C };
+ E a = A;
+ }
+};
diff --git a/test/SemaCXX/attr-format.cpp b/test/SemaCXX/attr-format.cpp
index da134a136d26..3d5c3391c263 100644
--- a/test/SemaCXX/attr-format.cpp
+++ b/test/SemaCXX/attr-format.cpp
@@ -14,6 +14,8 @@ struct S {
expected-error{{out of bounds}}
const char* h3(const char*) __attribute__((format_arg(1))); // \
expected-error{{invalid for the implicit this argument}}
+
+ void operator() (const char*, ...) __attribute__((format(printf, 2, 3)));
};
// PR5521
@@ -33,3 +35,9 @@ namespace PR8625 {
s.f(str, "%s", str);
}
}
+
+// Make sure we interpret member operator calls as having an implicit
+// this argument.
+void test_operator_call(S s, const char* str) {
+ s("%s", str);
+}
diff --git a/test/SemaCXX/attr-nodebug.cpp b/test/SemaCXX/attr-nodebug.cpp
new file mode 100644
index 000000000000..b441da21f8e7
--- /dev/null
+++ b/test/SemaCXX/attr-nodebug.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+// Note: most of the 'nodebug' tests are in attr-nodebug.c.
+
+// expected-no-diagnostics
+class c {
+ void t3() __attribute__((nodebug));
+};
diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp
index eaf0d0c15ffd..f3d548b793b0 100644
--- a/test/SemaCXX/attr-noreturn.cpp
+++ b/test/SemaCXX/attr-noreturn.cpp
@@ -54,3 +54,29 @@ class xpto {
int xpto::blah() {
return 3; // expected-warning {{function 'blah' declared 'noreturn' should not return}}
}
+
+// PR12948
+
+namespace PR12948 {
+ template<int>
+ void foo() __attribute__((__noreturn__));
+
+ template<int>
+ void foo() {
+ while (1) continue;
+ }
+
+ void bar() __attribute__((__noreturn__));
+
+ void bar() {
+ foo<0>();
+ }
+
+
+ void baz() __attribute__((__noreturn__));
+ typedef void voidfn();
+ voidfn baz;
+
+ template<typename> void wibble() __attribute__((__noreturn__));
+ template<typename> voidfn wibble;
+}
diff --git a/test/SemaCXX/attr-unused.cpp b/test/SemaCXX/attr-unused.cpp
new file mode 100644
index 000000000000..b74bc915ce07
--- /dev/null
+++ b/test/SemaCXX/attr-unused.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -fsyntax-only %s
+
+namespace ns_unused { typedef int Int_unused __attribute__((unused)); }
+namespace ns_not_unused { typedef int Int_not_unused; }
+
+void f() {
+ ns_not_unused::Int_not_unused i1; // expected-warning {{unused variable}}
+ ns_unused::Int_unused i0; // expected-warning {{'Int_unused' was marked unused but was used}}
+}
diff --git a/test/SemaCXX/blocks-1.cpp b/test/SemaCXX/blocks-1.cpp
index 1b1509482af3..02e9cac62ebe 100644
--- a/test/SemaCXX/blocks-1.cpp
+++ b/test/SemaCXX/blocks-1.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11
+// expected-no-diagnostics
extern "C" int exit(int);
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
index adbff553e608..3f81c274d04f 100644
--- a/test/SemaCXX/blocks.cpp
+++ b/test/SemaCXX/blocks.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+// expected-no-diagnostics
void tovoid(void*);
diff --git a/test/SemaCXX/borland-extensions.cpp b/test/SemaCXX/borland-extensions.cpp
index 483153004dcb..1e4bd45612fd 100644
--- a/test/SemaCXX/borland-extensions.cpp
+++ b/test/SemaCXX/borland-extensions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fborland-extensions
+// expected-no-diagnostics
// Borland extensions
diff --git a/test/SemaCXX/builtin-exception-spec.cpp b/test/SemaCXX/builtin-exception-spec.cpp
index 324d20ea6a15..590cd3c35d4e 100644
--- a/test/SemaCXX/builtin-exception-spec.cpp
+++ b/test/SemaCXX/builtin-exception-spec.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <malloc.h>
extern "C" {
diff --git a/test/SemaCXX/builtin-ptrtomember-overload.cpp b/test/SemaCXX/builtin-ptrtomember-overload.cpp
index c7b5173a4fbe..c27d642f9a46 100644
--- a/test/SemaCXX/builtin-ptrtomember-overload.cpp
+++ b/test/SemaCXX/builtin-ptrtomember-overload.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
struct A {};
diff --git a/test/SemaCXX/builtin_objc_msgSend.cpp b/test/SemaCXX/builtin_objc_msgSend.cpp
index 0e90d54f804f..082fb2868c63 100644
--- a/test/SemaCXX/builtin_objc_msgSend.cpp
+++ b/test/SemaCXX/builtin_objc_msgSend.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://8686888
typedef struct objc_selector *SEL;
diff --git a/test/SemaCXX/builtins-arm.cpp b/test/SemaCXX/builtins-arm.cpp
new file mode 100644
index 000000000000..8a0cf8102b35
--- /dev/null
+++ b/test/SemaCXX/builtins-arm.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s
+
+// va_list on ARM AAPCS is struct { void* __ap }.
+int test1(const __builtin_va_list &ap) {
+ return __builtin_va_arg(ap, int); // expected-error {{binding of reference to type '__builtin_va_list' to a value of type 'const __builtin_va_list' drops qualifiers}}
+}
diff --git a/test/SemaCXX/builtins-va_arg.cpp b/test/SemaCXX/builtins-va_arg.cpp
new file mode 100644
index 000000000000..4f549c8db6f0
--- /dev/null
+++ b/test/SemaCXX/builtins-va_arg.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 %s -ffreestanding
+// RUN: %clang_cc1 %s -ffreestanding -triple i686-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple x86_64-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple mips-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple mipsel-unknown-linux
+// RUN: %clang_cc1 %s -ffreestanding -triple armv7-unknown-linux-gnueabi
+// RUN: %clang_cc1 %s -ffreestanding -triple thumbv7-unknown-linux-gnueabi
+
+#include "stdarg.h"
+
+int int_accumulator = 0;
+double double_accumulator = 0;
+
+int test_vprintf(const char *fmt, va_list ap) {
+ char ch;
+ int result = 0;
+ while (*fmt != '\0') {
+ ch = *fmt++;
+ if (ch != '%') {
+ continue;
+ }
+
+ ch = *fmt++;
+ switch (ch) {
+ case 'd':
+ int_accumulator += va_arg(ap, int);
+ result++;
+ break;
+
+ case 'f':
+ double_accumulator += va_arg(ap, double);
+ result++;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ch == '0') {
+ break;
+ }
+ }
+ return result;
+}
+
+int test_printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int result = test_vprintf(fmt, ap);
+ va_end(ap);
+ return result;
+}
diff --git a/test/SemaCXX/builtins.cpp b/test/SemaCXX/builtins.cpp
index 568ba5dde129..6b055cff640d 100644
--- a/test/SemaCXX/builtins.cpp
+++ b/test/SemaCXX/builtins.cpp
@@ -7,3 +7,16 @@ void f() {
}
void a() { __builtin_va_list x, y; ::__builtin_va_copy(x, y); }
+
+// <rdar://problem/10063539>
+template<int (*Compare)(const char *s1, const char *s2)>
+int equal(const char *s1, const char *s2) {
+ return Compare(s1, s2) == 0;
+}
+// FIXME: Our error recovery here sucks
+template int equal<&__builtin_strcmp>(const char*, const char*); // expected-error {{builtin functions must be directly called}} expected-error {{expected unqualified-id}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+// PR13195
+void f2() {
+ __builtin_isnan; // expected-error {{builtin functions must be directly called}}
+}
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
index dd2bc98e02cc..270f96831bd4 100644
--- a/test/SemaCXX/cast-conversion.cpp
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -verify %s -std=c++11
struct R {
R(int);
@@ -45,3 +45,23 @@ protected:
static_cast<float*>(f0<0>()); // expected-error{{ambiguous}}
}
};
+
+void *intToPointer1(short s) {
+ return (void*)s; // expected-warning{{cast to 'void *' from smaller integer type 'short'}}
+}
+
+void *intToPointer2(short s) {
+ return reinterpret_cast<void*>(s);
+}
+
+void *intToPointer3(bool b) {
+ return (void*)b;
+}
+
+void *intToPointer4() {
+ return (void*)(3 + 7);
+}
+
+void *intToPointer5(long l) {
+ return (void*)l;
+}
diff --git a/test/SemaCXX/cast-explicit-ctor.cpp b/test/SemaCXX/cast-explicit-ctor.cpp
index 0052856d2ff9..41d2fa2fbf2c 100644
--- a/test/SemaCXX/cast-explicit-ctor.cpp
+++ b/test/SemaCXX/cast-explicit-ctor.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct B { explicit B(bool); };
void f() {
(void)(B)true;
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
index d81944ab9b3c..f2ff9fcfd7c1 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
+// expected-no-diagnostics
#define SA(n, p) int a##n[(p) ? 1 : -1]
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 4dffc8d9ecb8..972a79bb6090 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -120,7 +120,7 @@ struct C4 {
struct S
{
void f(); // expected-note 1 {{previous declaration}}
- void S::f() {} // expected-warning {{extra qualification on member}} expected-error {{class member cannot be redeclared}} expected-note {{previous declaration}} expected-note {{previous definition}}
+ void S::f() {} // expected-error {{extra qualification on member}} expected-error {{class member cannot be redeclared}} expected-note {{previous declaration}} expected-note {{previous definition}}
void f() {} // expected-error {{class member cannot be redeclared}} expected-error {{redefinition}}
};
diff --git a/test/SemaCXX/comma.cpp b/test/SemaCXX/comma.cpp
index 79ff7d1cde25..3a6162bc473e 100644
--- a/test/SemaCXX/comma.cpp
+++ b/test/SemaCXX/comma.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR6076
void f();
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index 28e2dd0ad51a..432069f60cc0 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -89,8 +89,8 @@ int test0(long a, unsigned long b) {
// (C,b)
(C == (unsigned long) b) +
(C == (unsigned int) b) +
- (C == (unsigned short) b) +
- (C == (unsigned char) b) +
+ (C == (unsigned short) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned short' is always false}}
+ (C == (unsigned char) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned char' is always false}}
((long) C == b) +
((int) C == b) +
((short) C == b) +
@@ -101,8 +101,8 @@ int test0(long a, unsigned long b) {
((signed char) C == (unsigned char) b) +
(C < (unsigned long) b) +
(C < (unsigned int) b) +
- (C < (unsigned short) b) +
- (C < (unsigned char) b) +
+ (C < (unsigned short) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned short' is always false}}
+ (C < (unsigned char) b) + // expected-warning {{comparison of constant 65536 with expression of type 'unsigned char' is always false}}
((long) C < b) +
((int) C < b) +
((short) C < b) +
@@ -119,8 +119,8 @@ int test0(long a, unsigned long b) {
(a == (unsigned char) C) +
((long) a == C) +
((int) a == C) +
- ((short) a == C) +
- ((signed char) a == C) +
+ ((short) a == C) + // expected-warning {{comparison of constant 65536 with expression of type 'short' is always false}}
+ ((signed char) a == C) + // expected-warning {{comparison of constant 65536 with expression of type 'signed char' is always false}}
((long) a == (unsigned long) C) +
((int) a == (unsigned int) C) +
((short) a == (unsigned short) C) +
@@ -131,8 +131,8 @@ int test0(long a, unsigned long b) {
(a < (unsigned char) C) +
((long) a < C) +
((int) a < C) +
- ((short) a < C) +
- ((signed char) a < C) +
+ ((short) a < C) + // expected-warning {{comparison of constant 65536 with expression of type 'short' is always true}}
+ ((signed char) a < C) + // expected-warning {{comparison of constant 65536 with expression of type 'signed char' is always true}}
((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) C) +
@@ -141,8 +141,8 @@ int test0(long a, unsigned long b) {
// (0x80000,b)
(0x80000 == (unsigned long) b) +
(0x80000 == (unsigned int) b) +
- (0x80000 == (unsigned short) b) +
- (0x80000 == (unsigned char) b) +
+ (0x80000 == (unsigned short) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned short' is always false}}
+ (0x80000 == (unsigned char) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned char' is always false}}
((long) 0x80000 == b) +
((int) 0x80000 == b) +
((short) 0x80000 == b) +
@@ -153,8 +153,8 @@ int test0(long a, unsigned long b) {
((signed char) 0x80000 == (unsigned char) b) +
(0x80000 < (unsigned long) b) +
(0x80000 < (unsigned int) b) +
- (0x80000 < (unsigned short) b) +
- (0x80000 < (unsigned char) b) +
+ (0x80000 < (unsigned short) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned short' is always false}}
+ (0x80000 < (unsigned char) b) + // expected-warning {{comparison of constant 524288 with expression of type 'unsigned char' is always false}}
((long) 0x80000 < b) +
((int) 0x80000 < b) +
((short) 0x80000 < b) +
@@ -171,8 +171,8 @@ int test0(long a, unsigned long b) {
(a == (unsigned char) 0x80000) +
((long) a == 0x80000) +
((int) a == 0x80000) +
- ((short) a == 0x80000) +
- ((signed char) a == 0x80000) +
+ ((short) a == 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'short' is always false}}
+ ((signed char) a == 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always false}}
((long) a == (unsigned long) 0x80000) +
((int) a == (unsigned int) 0x80000) +
((short) a == (unsigned short) 0x80000) +
@@ -183,8 +183,8 @@ int test0(long a, unsigned long b) {
(a < (unsigned char) 0x80000) +
((long) a < 0x80000) +
((int) a < 0x80000) +
- ((short) a < 0x80000) +
- ((signed char) a < 0x80000) +
+ ((short) a < 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'short' is always true}}
+ ((signed char) a < 0x80000) + // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always true}}
((long) a < (unsigned long) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) 0x80000) +
diff --git a/test/SemaCXX/complex-init-list.cpp b/test/SemaCXX/complex-init-list.cpp
index e75833a37dbc..f70f9df6c73b 100644
--- a/test/SemaCXX/complex-init-list.cpp
+++ b/test/SemaCXX/complex-init-list.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+// expected-no-diagnostics
// This file tests the clang extension which allows initializing the components
// of a complex number individually using an initialization list. Basically,
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index a80eda416f4e..7595f1dfa1c0 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -57,6 +57,16 @@ struct Ambig {
operator signed char(); // expected-note 2 {{candidate function}}
};
+struct Abstract {
+ virtual ~Abstract() = 0; // expected-note {{unimplemented pure virtual method '~Abstract' in 'Abstract'}}
+};
+
+struct Derived1: Abstract {
+};
+
+struct Derived2: Abstract {
+};
+
void test()
{
// This function tests C++0x 5.16
@@ -206,6 +216,9 @@ void test()
// Note the thing that this does not test: since DR446, various situations
// *must* create a separate temporary copy of class objects. This can only
// be properly tested at runtime, though.
+
+ const Abstract &a = true ? static_cast<const Abstract&>(Derived1()) : Derived2(); // expected-error {{allocating an object of abstract class type 'const Abstract'}}
+ true ? static_cast<const Abstract&>(Derived1()) : throw 3; // expected-error {{allocating an object of abstract class type 'const Abstract'}}
}
namespace PR6595 {
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index a3ead79a8456..f504eb621f6c 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -521,12 +521,18 @@ namespace DependentValues {
struct I { int n; typedef I V[10]; };
I::V x, y;
-template<bool B> struct S {
+int g();
+template<bool B, typename T> struct S : T {
int k;
void f() {
I::V &cells = B ? x : y;
I &i = cells[k];
switch (i.n) {}
+
+ // FIXME: We should be able to diagnose this.
+ constexpr int n = g();
+
+ constexpr int m = this->g(); // ok, could be constexpr
}
};
@@ -741,6 +747,15 @@ constexpr bool check(T a, T b) { return a == b.k; }
static_assert(S(5) == 11, "");
static_assert(check(S(5), 11), "");
+namespace PR14171 {
+
+struct X {
+ constexpr (operator int)() { return 0; }
+};
+static_assert(X() == 0, "");
+
+}
+
}
}
@@ -1374,3 +1389,69 @@ namespace ConditionalLValToRVal {
constexpr A a(4);
static_assert(f(a).v == 4, "");
}
+
+namespace TLS {
+ __thread int n;
+ int m;
+
+ constexpr bool b = &n == &n;
+
+ constexpr int *p = &n; // expected-error{{constexpr variable 'p' must be initialized by a constant expression}}
+
+ constexpr int *f() { return &n; }
+ constexpr int *q = f(); // expected-error{{constexpr variable 'q' must be initialized by a constant expression}}
+ constexpr bool c = f() == f();
+
+ constexpr int *g() { return &m; }
+ constexpr int *r = g();
+}
+
+namespace Void {
+ constexpr void f() { return; } // expected-error{{constexpr function's return type 'void' is not a literal type}}
+
+ void assert_failed(const char *msg, const char *file, int line); // expected-note {{declared here}}
+#define ASSERT(expr) ((expr) ? static_cast<void>(0) : assert_failed(#expr, __FILE__, __LINE__))
+ template<typename T, size_t S>
+ constexpr T get(T (&a)[S], size_t k) {
+ return ASSERT(k > 0 && k < S), a[k]; // expected-note{{non-constexpr function 'assert_failed'}}
+ }
+#undef ASSERT
+ template int get(int (&a)[4], size_t);
+ constexpr int arr[] = { 4, 1, 2, 3, 4 };
+ static_assert(get(arr, 1) == 1, "");
+ static_assert(get(arr, 4) == 4, "");
+ static_assert(get(arr, 0) == 4, ""); // expected-error{{not an integral constant expression}} \
+ // expected-note{{in call to 'get(arr, 0)'}}
+}
+
+namespace std { struct type_info; }
+
+namespace TypeId {
+ struct A { virtual ~A(); };
+ A f();
+ A &g();
+ constexpr auto &x = typeid(f());
+ constexpr auto &y = typeid(g()); // expected-error{{constant expression}} \
+ // expected-note{{typeid applied to expression of polymorphic type 'TypeId::A' is not allowed in a constant expression}}
+}
+
+namespace PR14203 {
+ struct duration {
+ constexpr duration() {}
+ constexpr operator int() const { return 0; }
+ };
+ template<typename T> void f() {
+ // If we want to evaluate this at the point of the template definition, we
+ // need to trigger the implicit definition of the move constructor at that
+ // point.
+ // FIXME: C++ does not permit us to implicitly define it at the appropriate
+ // times, since it is only allowed to be implicitly defined when it is
+ // odr-used.
+ constexpr duration d = duration();
+ }
+ // FIXME: It's unclear whether this is valid. On the one hand, we're not
+ // allowed to generate a move constructor. On the other hand, if we did,
+ // this would be a constant expression. For now, we generate a move
+ // constructor here.
+ int n = sizeof(short{duration(duration())});
+}
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
index ec50cb7d92fc..942bf414742b 100644
--- a/test/SemaCXX/constant-expression.cpp
+++ b/test/SemaCXX/constant-expression.cpp
@@ -115,7 +115,7 @@ int array2[recurse2]; // expected-warning {{variable length array}} expected-war
namespace FloatConvert {
typedef int a[(int)42.3];
typedef int a[(int)42.997];
- typedef int b[(long long)4e20]; // expected-warning {{variable length}} expected-error {{variable length}} expected-warning {{'long long' is an extension}}
+ typedef int b[(long long)4e20]; // expected-warning {{variable length}} expected-error {{variable length}} expected-warning {{'long long' is a C++11 extension}}
}
// PR12626
diff --git a/test/SemaCXX/constexpr-turing.cpp b/test/SemaCXX/constexpr-turing.cpp
index c5153788adfd..07c04eff3083 100644
--- a/test/SemaCXX/constexpr-turing.cpp
+++ b/test/SemaCXX/constexpr-turing.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -std=c++11 %s
+// expected-no-diagnostics
// A direct proof that constexpr is Turing-complete, once DR1454 is implemented.
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index f503d01f360d..ecbe7bf5b9ed 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -135,12 +135,12 @@ class InitializeUsingSelfTest {
TwoInOne D;
int E;
InitializeUsingSelfTest(int F)
- : A(A), // expected-warning {{field is uninitialized when used here}}
- B((((B)))), // expected-warning {{field is uninitialized when used here}}
- C(A && InitializeUsingSelfTest::C), // expected-warning {{field is uninitialized when used here}}
- D(D, // expected-warning {{field is uninitialized when used here}}
- D), // expected-warning {{field is uninitialized when used here}}
- E(IntParam(E)) {} // expected-warning {{field is uninitialized when used here}}
+ : A(A), // expected-warning {{field 'A' is uninitialized when used here}}
+ B((((B)))), // expected-warning {{field 'B' is uninitialized when used here}}
+ C(A && InitializeUsingSelfTest::C), // expected-warning {{field 'C' is uninitialized when used here}}
+ D(D, // expected-warning {{field 'D' is uninitialized when used here}}
+ D), // expected-warning {{field 'D' is uninitialized when used here}}
+ E(IntParam(E)) {} // expected-warning {{field 'E' is uninitialized when used here}}
};
int IntWrapper(int &i) { return 0; };
@@ -160,8 +160,8 @@ class CopyConstructorTest {
bool A, B, C;
CopyConstructorTest(const CopyConstructorTest& rhs)
: A(rhs.A),
- B(B), // expected-warning {{field is uninitialized when used here}}
- C(rhs.C || C) { } // expected-warning {{field is uninitialized when used here}}
+ B(B), // expected-warning {{field 'B' is uninitialized when used here}}
+ C(rhs.C || C) { } // expected-warning {{field 'C' is uninitialized when used here}}
};
// Make sure we aren't marking default constructors when we shouldn't be.
diff --git a/test/SemaCXX/crashes.cpp b/test/SemaCXX/crashes.cpp
index d02704c87c74..f5682bd74d92 100644
--- a/test/SemaCXX/crashes.cpp
+++ b/test/SemaCXX/crashes.cpp
@@ -136,3 +136,38 @@ cc_YCbCr cc_hsl::YCbCr()
}
}
+
+namespace test1 {
+ int getString(const int*);
+ template<int a> class ELFObjectFile {
+ const int* sh;
+ ELFObjectFile() {
+ switch (*sh) {
+ }
+ int SectionName(getString(sh));
+ }
+ };
+}
+
+namespace test2 {
+ struct fltSemantics ;
+ const fltSemantics &foobar();
+ void VisitCastExpr(int x) {
+ switch (x) {
+ case 42:
+ const fltSemantics &Sem = foobar();
+ }
+ }
+}
+
+namespace test3 {
+ struct nsCSSRect {
+ };
+ static int nsCSSRect::* sides;
+ nsCSSRect dimenX;
+ void ParseBoxCornerRadii(int y) {
+ switch (y) {
+ }
+ int& x = dimenX.*sides;
+ }
+}
diff --git a/test/SemaCXX/cstyle-cast.cpp b/test/SemaCXX/cstyle-cast.cpp
index 12495ecdc5c1..468c8ecb23c4 100644
--- a/test/SemaCXX/cstyle-cast.cpp
+++ b/test/SemaCXX/cstyle-cast.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// REQUIRES: LP64
struct A {};
diff --git a/test/SemaCXX/cxx0x-delegating-ctors.cpp b/test/SemaCXX/cxx0x-delegating-ctors.cpp
index 2d49f0fc599d..a34ee4fcb024 100644
--- a/test/SemaCXX/cxx0x-delegating-ctors.cpp
+++ b/test/SemaCXX/cxx0x-delegating-ctors.cpp
@@ -33,7 +33,9 @@ foo::foo (const float &f) : foo(&f) { //expected-error{{creates a delegation cyc
//expected-note{{which delegates to}}
}
-foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}}
+foo::foo (char) :
+ i(3),
+ foo(3) { // expected-error{{must appear alone}}
}
// This should not cause an infinite loop
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index 223e140ffc02..a657ec81a140 100644
--- a/test/SemaCXX/cxx0x-initializer-constructor.cpp
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -304,3 +304,19 @@ namespace init_list_default {
};
B b {}; // calls default constructor
}
+
+
+// <rdar://problem/11974632>
+namespace rdar11974632 {
+ struct X {
+ X(const X&) = delete;
+ X(int);
+ };
+
+ template<typename T>
+ struct Y {
+ X x{1};
+ };
+
+ Y<int> yi;
+}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index f11e19ae6f2c..0962253b988c 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -187,3 +187,7 @@ namespace rdar11948732 {
XCtorInit xc = { xi, xi };
}
}
+
+namespace PR14272 {
+ auto x { { 0, 0 } }; // expected-error {{cannot deduce actual type for variable 'x' with type 'auto' from initializer list}}
+}
diff --git a/test/SemaCXX/cxx11-crashes.cpp b/test/SemaCXX/cxx11-crashes.cpp
new file mode 100644
index 000000000000..bd51af1da2fa
--- /dev/null
+++ b/test/SemaCXX/cxx11-crashes.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// rdar://12240916 stack overflow.
+namespace rdar12240916 {
+
+struct S2 {
+ S2(const S2&);
+ S2();
+};
+
+struct S { // expected-note {{not complete}}
+ S x; // expected-error {{incomplete type}}
+ S2 y;
+};
+
+S foo() {
+ S s;
+ return s;
+}
+
+struct S3; // expected-note {{forward declaration}}
+
+struct S4 {
+ S3 x; // expected-error {{incomplete type}}
+ S2 y;
+};
+
+struct S3 {
+ S4 x;
+ S2 y;
+};
+
+S4 foo2() {
+ S4 s;
+ return s;
+}
+
+}
+
+// rdar://12542261 stack overflow.
+namespace rdar12542261 {
+
+template <class _Tp>
+struct check_complete
+{
+ static_assert(sizeof(_Tp) > 0, "Type must be complete.");
+};
+
+
+template<class _Rp>
+class function // expected-note 2 {{candidate}}
+{
+public:
+ template<class _Fp>
+ function(_Fp, typename check_complete<_Fp>::type* = 0); // expected-note {{candidate}}
+};
+
+void foobar()
+{
+ auto LeftCanvas = new Canvas(); // expected-error {{unknown type name}}
+ function<void()> m_OnChange = [&, LeftCanvas]() { }; // expected-error {{no viable conversion}}
+}
+
+}
+
+namespace b6981007 {
+ struct S {}; // expected-note 3{{candidate}}
+ void f() {
+ S s(1, 2, 3); // expected-error {{no matching}}
+ for (auto x : s) {
+ // We used to attempt to evaluate the initializer of this variable,
+ // and crash because it has an undeduced type.
+ const int &n(x);
+ }
+ }
+}
diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp
index c07f64e614d2..18fd1520ec4e 100644
--- a/test/SemaCXX/cxx98-compat-pedantic.cpp
+++ b/test/SemaCXX/cxx98-compat-pedantic.cpp
@@ -32,3 +32,9 @@ int *ArraySizeConversion = new int[ConvertToInt()]; // expected-warning {{implic
template<typename T> class ExternTemplate {};
extern template class ExternTemplate<int>; // expected-warning {{extern templates are incompatible with C++98}}
+
+long long ll1 = // expected-warning {{'long long' is incompatible with C++98}}
+ -42LL; // expected-warning {{'long long' is incompatible with C++98}}
+unsigned long long ull1 = // expected-warning {{'long long' is incompatible with C++98}}
+ 42ULL; // expected-warning {{'long long' is incompatible with C++98}}
+
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 37341f885619..d497d45c3e35 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -20,7 +20,7 @@ class Variadic2 {};
template<int ...I> // expected-warning {{variadic templates are incompatible with C++98}}
class Variadic3 {};
-int alignas(8) with_alignas; // expected-warning {{'alignas' is incompatible with C++98}}
+alignas(8) int with_alignas; // expected-warning {{'alignas' is incompatible with C++98}}
int with_attribute [[ ]]; // expected-warning {{attributes are incompatible with C++98}}
void Literals() {
@@ -362,3 +362,14 @@ namespace AssignOpUnion {
b y; // expected-warning {{union member 'y' with a non-trivial copy assignment operator is incompatible with C++98}}
};
}
+
+namespace rdar11736429 {
+ struct X {
+ X(const X&) = delete; // expected-warning{{deleted function definitions are incompatible with C++98}} \
+ // expected-note{{because type 'rdar11736429::X' has a user-declared constructor}}
+ };
+
+ union S {
+ X x; // expected-warning{{union member 'x' with a non-trivial constructor is incompatible with C++98}}
+ };
+}
diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp
index 08867c0ea2f5..97780e41f0c4 100644
--- a/test/SemaCXX/dcl_ambig_res.cpp
+++ b/test/SemaCXX/dcl_ambig_res.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// PR13819
+// REQUIRES: LP64
+
// [dcl.ambig.res]p1:
struct S {
S(int);
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 0980c40cbfd5..87fd2dad316c 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -Wno-int-to-pointer-cast -fsyntax-only -verify -pedantic-errors %s
void f() {
int a;
diff --git a/test/SemaCXX/decltype-98.cpp b/test/SemaCXX/decltype-98.cpp
index db52565e6c74..3202dfea71e2 100644
--- a/test/SemaCXX/decltype-98.cpp
+++ b/test/SemaCXX/decltype-98.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern int x;
__decltype(1) x = 3;
diff --git a/test/SemaCXX/decltype-overloaded-functions.cpp b/test/SemaCXX/decltype-overloaded-functions.cpp
index b0a43a999bb6..c1d01fc9af95 100644
--- a/test/SemaCXX/decltype-overloaded-functions.cpp
+++ b/test/SemaCXX/decltype-overloaded-functions.cpp
@@ -1,15 +1,30 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-void f(); // expected-note{{possible target for call}}
-void f(int); // expected-note{{possible target for call}}
+void f(); // expected-note{{possible target for call}}
+void f(int); // expected-note{{possible target for call}}
decltype(f) a; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{variable has incomplete type 'decltype(f())' (aka 'void')}}
template<typename T> struct S {
- decltype(T::f) * f; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{call to non-static member function without an object argument}}
+ decltype(T::f) * f; // expected-error {{call to non-static member function without an object argument}}
};
struct K {
- void f(); // expected-note{{possible target for call}}
- void f(int); // expected-note{{possible target for call}}
+ void f();
+ void f(int);
};
S<K> b; // expected-note{{in instantiation of template class 'S<K>' requested here}}
+
+namespace PR13978 {
+ template<typename T> struct S { decltype(1) f(); };
+ template<typename T> decltype(1) S<T>::f() { return 1; }
+
+ // This case is ill-formed (no diagnostic required) because the decltype
+ // expressions are functionally equivalent but not equivalent. It would
+ // be acceptable for us to reject this case.
+ template<typename T> struct U { struct A {}; decltype(A{}) f(); };
+ template<typename T> decltype(typename U<T>::A{}) U<T>::f() {}
+
+ // This case is valid.
+ template<typename T> struct V { struct A {}; decltype(typename V<T>::A{}) f(); };
+ template<typename T> decltype(typename V<T>::A{}) V<T>::f() {}
+}
diff --git a/test/SemaCXX/decltype-pr4444.cpp b/test/SemaCXX/decltype-pr4444.cpp
index 2f95075067a4..a5ac54bc37fe 100644
--- a/test/SemaCXX/decltype-pr4444.cpp
+++ b/test/SemaCXX/decltype-pr4444.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
template<typename T, T t>
struct TestStruct {
diff --git a/test/SemaCXX/decltype-pr4448.cpp b/test/SemaCXX/decltype-pr4448.cpp
index 9d33ce7341a2..b781b891ffb7 100644
--- a/test/SemaCXX/decltype-pr4448.cpp
+++ b/test/SemaCXX/decltype-pr4448.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
template< typename T, T t, decltype(t+2) v >
struct Convoluted {};
diff --git a/test/SemaCXX/decltype-this.cpp b/test/SemaCXX/decltype-this.cpp
index a13416f089dd..21b4b60ea3ce 100644
--- a/test/SemaCXX/decltype-this.cpp
+++ b/test/SemaCXX/decltype-this.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
template<typename T, typename U> struct is_same {
static const bool value = false;
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index a1200e08200d..ccde3dcfb312 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -28,3 +28,18 @@ template<typename T> auto f(T t) -> decltype(S<int>(t)) {
using U = S<int>;
return S<int>(t);
}
+
+struct B {
+ B(decltype(undeclared)); // expected-error {{undeclared identifier}}
+};
+struct C {
+ C(decltype(undeclared; // expected-error {{undeclared identifier}} \
+ // expected-error {{expected ')'}} expected-note {{to match this '('}}
+};
+
+template<typename>
+class conditional {
+};
+
+void foo(conditional<decltype((1),int>) { // expected-note 2 {{to match this '('}} expected-error {{expected ')'}}
+} // expected-error {{expected function body after function declarator}} expected-error 2 {{expected '>'}} expected-error {{expected ')'}}
diff --git a/test/SemaCXX/default-argument-temporaries.cpp b/test/SemaCXX/default-argument-temporaries.cpp
index 3ab7bf4eb13d..c0880d507e43 100644
--- a/test/SemaCXX/default-argument-temporaries.cpp
+++ b/test/SemaCXX/default-argument-temporaries.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct B { B(void* = 0); };
struct A {
diff --git a/test/SemaCXX/defaulted-ctor-loop.cpp b/test/SemaCXX/defaulted-ctor-loop.cpp
index 6416336c6eed..bc8dfdaa3cf2 100644
--- a/test/SemaCXX/defaulted-ctor-loop.cpp
+++ b/test/SemaCXX/defaulted-ctor-loop.cpp
@@ -9,6 +9,6 @@ struct bar {
struct foo {
bar b;
foo()
- : b(b) // expected-warning{{field is uninitialized}}
+ : b(b) // expected-warning{{field 'b' is uninitialized}}
{}
};
diff --git a/test/SemaCXX/do-while-scope.cpp b/test/SemaCXX/do-while-scope.cpp
index 2602ae12f243..67534db36d61 100644
--- a/test/SemaCXX/do-while-scope.cpp
+++ b/test/SemaCXX/do-while-scope.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
void test() {
int x;
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index c68f2bb6fb0e..951f16c1b0c5 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify
+// expected-no-diagnostics
#define SA(n, p) int a##n[(p) ? 1 : -1]
diff --git a/test/SemaCXX/exception-spec-no-exceptions.cpp b/test/SemaCXX/exception-spec-no-exceptions.cpp
index 2e180706d3b9..e26e864e3d8f 100644
--- a/test/SemaCXX/exception-spec-no-exceptions.cpp
+++ b/test/SemaCXX/exception-spec-no-exceptions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fobjc-exceptions %s
+// expected-no-diagnostics
// Note that we're specifically excluding -fcxx-exceptions in the command line above.
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
index 477463771e88..5ce2cf19132c 100644
--- a/test/SemaCXX/explicit.cpp
+++ b/test/SemaCXX/explicit.cpp
@@ -40,10 +40,10 @@ 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 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}}
+ 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}}
struct Z {
explicit operator Y() const;
@@ -52,7 +52,7 @@ namespace Conversion {
Z z;
// 13.3.1.4p1 & 8.5p16:
- Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
+ Y y2 = z; // expected-error {{no viable conversion from 'Z' to 'Y'}}
Y y3 = (Y)z;
Y y4 = Y(z);
Y y5 = static_cast<Y>(z);
@@ -62,7 +62,7 @@ namespace Conversion {
int i3 = static_cast<int>(z);
int i4(z);
// 13.3.1.6p1 & 8.5.3p5:
- const Y& y6 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'const Conversion::Y'}}
+ const Y& y6 = z; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
const int& y7(z);
}
@@ -78,7 +78,7 @@ namespace Conversion {
NotBool n;
(void) (1 + b);
- (void) (1 + n); // expected-error {{invalid operands to binary expression ('int' and 'Conversion::NotBool')}}
+ (void) (1 + n); // expected-error {{invalid operands to binary expression ('int' and 'NotBool')}}
// 5.3.1p9:
(void) (!b);
@@ -105,7 +105,7 @@ namespace Conversion {
// 6.4.2p2:
switch (b) {} // expected-warning {{switch condition has boolean value}}
- switch (n) {} // expected-error {{switch condition type 'Conversion::NotBool' requires explicit conversion to 'bool'}} \
+ switch (n) {} // expected-error {{switch condition type 'NotBool' requires explicit conversion to 'bool'}} \
expected-warning {{switch condition has boolean value}}
// 6.5.1:
@@ -135,7 +135,7 @@ namespace Conversion {
NotInt ni;
new int[i];
- new int[ni]; // expected-error {{array size expression of type 'Conversion::NotInt' requires explicit conversion to type 'int'}}
+ new int[ni]; // expected-error {{array size expression of type 'NotInt' requires explicit conversion to type 'int'}}
}
void testDelete()
@@ -152,7 +152,7 @@ namespace Conversion {
NotPtr np;
delete p;
- delete np; // expected-error {{cannot delete expression of type 'Conversion::NotPtr'}}
+ delete np; // expected-error {{cannot delete expression of type 'NotPtr'}}
}
void testFunctionPointer()
@@ -170,6 +170,6 @@ namespace Conversion {
FP fp;
NotFP nfp;
fp(1);
- nfp(1); // expected-error {{type 'Conversion::NotFP' does not provide a call operator}}
+ nfp(1); // expected-error {{type 'NotFP' does not provide a call operator}}
}
}
diff --git a/test/SemaCXX/for-range-dereference.cpp b/test/SemaCXX/for-range-dereference.cpp
new file mode 100644
index 000000000000..bf3187da30e2
--- /dev/null
+++ b/test/SemaCXX/for-range-dereference.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+struct Data { };
+struct T {
+ Data *begin();
+ Data *end();
+};
+
+struct NoBegin {
+ Data *end();
+};
+
+struct DeletedEnd : public T {
+ Data *begin();
+ Data *end() = delete; //expected-note {{function has been explicitly marked deleted here}}
+};
+
+struct DeletedADLBegin { };
+
+int* begin(DeletedADLBegin) = delete; //expected-note {{candidate function has been explicitly deleted}} \
+ expected-note 5 {{candidate function not viable: no known conversion}}
+
+struct PrivateEnd {
+ Data *begin();
+
+ private:
+ Data *end(); // expected-note 2 {{declared private here}}
+};
+
+struct ADLNoEnd { };
+Data * begin(ADLNoEnd); // expected-note 6 {{candidate function not viable: no known conversion}}
+
+struct OverloadedStar {
+ T operator*();
+};
+
+void f() {
+ T t;
+ for (auto i : t) { }
+ T *pt;
+ for (auto i : pt) { } // expected-error{{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}}
+
+ int arr[10];
+ for (auto i : arr) { }
+ int (*parr)[10];
+ for (auto i : parr) { }// expected-error{{invalid range expression of type 'int (*)[10]'; did you mean to dereference it with '*'?}}
+
+ NoBegin NB;
+ for (auto i : NB) { }// expected-error{{range type 'NoBegin' has 'end' member but no 'begin' member}}
+ NoBegin *pNB;
+ for (auto i : pNB) { }// expected-error{{invalid range expression of type 'NoBegin *'; no viable 'begin' function available}}
+ NoBegin **ppNB;
+ for (auto i : ppNB) { }// expected-error{{invalid range expression of type 'NoBegin **'; no viable 'begin' function available}}
+ NoBegin *****pppppNB;
+ for (auto i : pppppNB) { }// expected-error{{invalid range expression of type 'NoBegin *****'; no viable 'begin' function available}}
+
+ ADLNoEnd ANE;
+ for (auto i : ANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd'; no viable 'end' function available}}
+ ADLNoEnd *pANE;
+ for (auto i : pANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd *'; no viable 'begin' function available}}
+
+ DeletedEnd DE;
+ for (auto i : DE) { } // expected-error{{attempt to use a deleted function}} \
+expected-note {{when looking up 'end' function for range expression of type 'DeletedEnd'}}
+ DeletedEnd *pDE;
+
+ for (auto i : pDE) { } // expected-error {{invalid range expression of type 'DeletedEnd *'; no viable 'begin' function available}}
+
+ PrivateEnd PE;
+ // FIXME: This diagnostic should be improved, as it does not specify that
+ // the range is invalid.
+ for (auto i : PE) { } // expected-error{{'end' is a private member of 'PrivateEnd'}}
+
+ PrivateEnd *pPE;
+ for (auto i : pPE) { }// expected-error {{invalid range expression of type 'PrivateEnd *'}}
+ // expected-error@-1 {{'end' is a private member of 'PrivateEnd'}}
+
+ DeletedADLBegin DAB;
+ for (auto i : DAB) { } // expected-error {{call to deleted function 'begin'}}\
+ expected-note {{when looking up 'begin' function for range expression of type 'DeletedADLBegin'}}
+
+ OverloadedStar OS;
+ for (auto i : *OS) { }
+
+ for (auto i : OS) { } // expected-error {{invalid range expression of type 'OverloadedStar'; did you mean to dereference it with '*'?}}
+
+ for (Data *p : pt) { } // expected-error {{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}}
+ // expected-error@-1 {{no viable conversion from 'Data' to 'Data *'}}
+ // expected-note@4 {{selected 'begin' function with iterator type 'Data *'}}
+}
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 8bda51062a40..953c98b4c818 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -115,7 +115,7 @@ namespace map_range {
}
}
-#define assert(b) if (!b) { return 1; }
+#define assert(b) if (!(b)) { return 1; }
int main() {
int total = 0;
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
index fa42ca45a58f..66b445e4d83b 100644
--- a/test/SemaCXX/for-range-no-std.cpp
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -31,10 +31,10 @@ NS::iter end(NS::NoADL);
void f() {
int a[] = {1, 2, 3};
for (auto b : S()) {} // ok
- for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (auto b : T()) {} // expected-error {{invalid range expression of type 'T'}}
for (auto b : a) {} // ok
for (int b : NS::ADL()) {} // ok
- for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (int b : NS::NoADL()) {} // expected-error {{invalid range expression of type 'NS::NoADL'}}
}
void PR11601() {
diff --git a/test/SemaCXX/format-strings.cpp b/test/SemaCXX/format-strings.cpp
index 6b0df2935378..299aa81bb161 100644
--- a/test/SemaCXX/format-strings.cpp
+++ b/test/SemaCXX/format-strings.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic -fblocks %s
#include <stdarg.h>
@@ -75,3 +75,61 @@ int Foo::printf2(const char *fmt, ...) {
return 0;
}
+
+
+namespace Templates {
+ template<typename T>
+ void my_uninstantiated_print(const T &arg) {
+ printf("%d", arg); // no-warning
+ }
+
+ template<typename T>
+ void my_print(const T &arg) {
+ printf("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+
+ void use_my_print() {
+ my_print("abc"); // expected-note {{requested here}}
+ }
+
+
+ template<typename T>
+ class UninstantiatedPrinter {
+ public:
+ static void print(const T &arg) {
+ printf("%d", arg); // no-warning
+ }
+ };
+
+ template<typename T>
+ class Printer {
+ void format(const char *fmt, ...) __attribute__((format(printf,2,3)));
+ public:
+
+ void print(const T &arg) {
+ format("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+ };
+
+ void use_class(Printer<const char *> &p) {
+ p.print("abc"); // expected-note {{requested here}}
+ }
+
+
+ extern void (^block_print)(const char * format, ...) __attribute__((format(printf, 1, 2)));
+
+ template<typename T>
+ void uninstantiated_call_block_print(const T &arg) {
+ block_print("%d", arg); // no-warning
+ }
+
+ template<typename T>
+ void call_block_print(const T &arg) {
+ block_print("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+
+ void use_block_print() {
+ call_block_print("abc"); // expected-note {{requested here}}
+ }
+}
+
diff --git a/test/SemaCXX/friend-out-of-line.cpp b/test/SemaCXX/friend-out-of-line.cpp
index 56b2daab4c4f..ab75a4f8ca44 100644
--- a/test/SemaCXX/friend-out-of-line.cpp
+++ b/test/SemaCXX/friend-out-of-line.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/10204947>
namespace N {
diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp
index 73613aef8d01..ccb57472925d 100644
--- a/test/SemaCXX/function-type-qual.cpp
+++ b/test/SemaCXX/function-type-qual.cpp
@@ -26,3 +26,6 @@ class C {
void (C::*mpf)() const;
cfn C::*mpg;
+
+// Don't crash!
+void (PR14171)() const; // expected-error {{non-member function cannot have 'const' qualifier}}
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
index 61e4da3da9b8..f8e0c465875e 100644
--- a/test/SemaCXX/functional-cast.cpp
+++ b/test/SemaCXX/functional-cast.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// REQUIRES: LP64
// ------------ not interpreted as C-style cast ------------
diff --git a/test/SemaCXX/gnu-case-ranges.cpp b/test/SemaCXX/gnu-case-ranges.cpp
index b082e3a6c1c0..c613cecbc5a9 100644
--- a/test/SemaCXX/gnu-case-ranges.cpp
+++ b/test/SemaCXX/gnu-case-ranges.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -Wno-covered-switch-default %s
+// expected-no-diagnostics
enum E {
one,
diff --git a/test/SemaCXX/goto2.cpp b/test/SemaCXX/goto2.cpp
index 01ea031ac2c1..b42a61118241 100644
--- a/test/SemaCXX/goto2.cpp
+++ b/test/SemaCXX/goto2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
//PR9463
int subfun(const char *text) {
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index b29cff5c5d12..e26f985f0d0a 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -30,20 +30,17 @@ namespace InClassInitializers {
bool x = noexcept(TemplateArg());
// And within a nested class.
- // FIXME: The diagnostic location is terrible here.
- struct Nested {
+ struct Nested { // expected-error {{cannot be used by non-static data member initializer}}
struct Inner {
- int n = ExceptionIf<noexcept(Nested())>::f();
- } inner; // expected-error {{cannot be used by non-static data member initializer}}
+ int n = ExceptionIf<noexcept(Nested())>::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}}
+ } inner;
};
- bool y = noexcept(Nested());
- bool z = noexcept(Nested::Inner());
struct Nested2 {
struct Inner;
int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}}
struct Inner {
- int n = ExceptionIf<noexcept(Nested())>::f();
+ int n = ExceptionIf<noexcept(Nested2())>::f();
} inner;
};
}
diff --git a/test/SemaCXX/indirect-goto.cpp b/test/SemaCXX/indirect-goto.cpp
index 5b3fac4a658f..cb2213d78dd7 100644
--- a/test/SemaCXX/indirect-goto.cpp
+++ b/test/SemaCXX/indirect-goto.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace test1 {
// Make sure this doesn't crash.
diff --git a/test/SemaCXX/issue547.cpp b/test/SemaCXX/issue547.cpp
index ab03a155d366..bfec6e080ba5 100644
--- a/test/SemaCXX/issue547.cpp
+++ b/test/SemaCXX/issue547.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T>
struct classify_function {
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index 0fd634502bc9..6f92373a6954 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -77,18 +77,21 @@ namespace ImplicitCapture {
struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
G g;
[=]() { const G* gg = &g; return gg->a; };
- [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'ImplicitCapture::G'}}
- (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const ImplicitCapture::G'}}
+ [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'G'}}
+ (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const G'}}
const int h = a; // expected-note {{declared}}
[]() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
- // The exemption for variables which can appear in constant expressions
- // applies only to objects (and not to references).
- // FIXME: This might be a bug in the standard.
- static int i;
- constexpr int &ref_i = i; // expected-note {{declared}}
+ // References can appear in constant expressions if they are initialized by
+ // reference constant expressions.
+ int i;
+ int &ref_i = i; // expected-note {{declared}}
[] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+
+ static int j;
+ int &ref_j = j;
+ [] { return ref_j; }; // ok
}
}
@@ -221,3 +224,15 @@ namespace VariadicPackExpansion {
template void nested2(int); // ok
template void nested2(int, int); // expected-note {{in instantiation of}}
}
+
+namespace PR13860 {
+ void foo() {
+ auto x = PR13860UndeclaredIdentifier(); // expected-error {{use of undeclared identifier 'PR13860UndeclaredIdentifier'}}
+ auto y = [x]() { };
+ static_assert(sizeof(y), "");
+ }
+}
+
+namespace PR13854 {
+ auto l = [](void){};
+}
diff --git a/test/SemaCXX/libstdcxx_atomic_ns_hack.cpp b/test/SemaCXX/libstdcxx_atomic_ns_hack.cpp
new file mode 100644
index 000000000000..4e4523f85322
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_atomic_ns_hack.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+// libstdc++ 4.6.x contains a bug where it defines std::__atomic[0,1,2] as a
+// non-inline namespace, then selects one of those namespaces and reopens it
+// as inline, as a strange way of providing something like a using-directive.
+// Clang has an egregious hack to work around the problem, by allowing a
+// namespace to be converted from non-inline to inline in this one specific
+// case.
+
+#ifdef BE_THE_HEADER
+
+#pragma clang system_header
+
+namespace std {
+ namespace __atomic0 {
+ typedef int foobar;
+ }
+ namespace __atomic1 {
+ typedef void foobar;
+ }
+
+ inline namespace __atomic0 {}
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libstdcxx_atomic_ns_hack.cpp"
+
+std::foobar fb;
+
+using T = void; // expected-note {{here}}
+using T = std::foobar; // expected-error {{different types ('std::foobar' (aka 'int') vs 'void')}}
+
+#endif
diff --git a/test/SemaCXX/libstdcxx_common_type_hack.cpp b/test/SemaCXX/libstdcxx_common_type_hack.cpp
new file mode 100644
index 000000000000..e9cb22f9dabf
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_common_type_hack.cpp
@@ -0,0 +1,33 @@
+// 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 GCC's <type_traits> implementation. std::common_type
+// relies on pre-standard rules for decltype(), in which it doesn't
+// produce reference types so frequently.
+
+#ifdef BE_THE_HEADER
+
+#pragma GCC system_header
+namespace std {
+ template<typename T> T &&declval();
+
+ template<typename...Ts> struct common_type {};
+ template<typename A, typename B> struct common_type<A, B> {
+ // Under the rules in the standard, this always produces a
+ // reference type.
+ typedef decltype(true ? declval<A>() : declval<B>()) type;
+ };
+}
+
+#else
+
+#define BE_THE_HEADER
+#include "libstdcxx_common_type_hack.cpp"
+
+using T = int;
+using T = std::common_type<int, int>::type;
+
+using U = int; // expected-note {{here}}
+using U = decltype(true ? std::declval<int>() : std::declval<int>()); // expected-error {{different types}}
+
+#endif
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index 3ac233627ccb..1ba3721c8c2e 100644
--- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -8,6 +8,7 @@
template<typename T>
struct __is_pod {
+ __is_pod() {}
};
__is_pod<int> ipi;
@@ -28,6 +29,13 @@ struct test_is_signed {
bool check_signed = test_is_signed::__is_signed;
-#if __has_feature(is_pod)
-# error __is_pod won't work now anyway
+template<bool B> struct must_be_true {};
+template<> struct must_be_true<false>;
+
+void foo() {
+ bool b = __is_pod(int);
+ must_be_true<__is_pod(int)> mbt;
+}
+#if !__has_feature(is_pod)
+# error __is_pod should still be available.
#endif
diff --git a/test/SemaCXX/local-classes.cpp b/test/SemaCXX/local-classes.cpp
index 500b2197ef35..f4ca79159dc9 100644
--- a/test/SemaCXX/local-classes.cpp
+++ b/test/SemaCXX/local-classes.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace PR6382 {
int foo()
diff --git a/test/SemaCXX/lookup-member.cpp b/test/SemaCXX/lookup-member.cpp
index c75b185bcc42..39f5a15d0811 100644
--- a/test/SemaCXX/lookup-member.cpp
+++ b/test/SemaCXX/lookup-member.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace A {
class String;
diff --git a/test/SemaCXX/member-expr-anonymous-union.cpp b/test/SemaCXX/member-expr-anonymous-union.cpp
index 6e35eb2b14d7..246afee23990 100644
--- a/test/SemaCXX/member-expr-anonymous-union.cpp
+++ b/test/SemaCXX/member-expr-anonymous-union.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// PR5543
struct A { int x; union { int* y; float* z; }; }; struct B : A {int a;};
diff --git a/test/SemaCXX/member-expr-static.cpp b/test/SemaCXX/member-expr-static.cpp
index 7ed60f7a17b7..d4c6c0b6da2f 100644
--- a/test/SemaCXX/member-expr-static.cpp
+++ b/test/SemaCXX/member-expr-static.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef void (*thread_continue_t)();
extern "C" {
diff --git a/test/SemaCXX/member-pointer-size.cpp b/test/SemaCXX/member-pointer-size.cpp
index 3aa1eaf5f256..8b595237fcab 100644
--- a/test/SemaCXX/member-pointer-size.cpp
+++ b/test/SemaCXX/member-pointer-size.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify
// RUN: %clang_cc1 -triple i686-unknown-unknown %s -fsyntax-only -verify
+// expected-no-diagnostics
#include <stddef.h>
struct A;
diff --git a/test/SemaCXX/missing-header.cpp b/test/SemaCXX/missing-header.cpp
index 5b3915b865cd..a1048fee46eb 100644
--- a/test/SemaCXX/missing-header.cpp
+++ b/test/SemaCXX/missing-header.cpp
@@ -4,6 +4,6 @@
class AnalysisDeclContext {};
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {}
+ if (const GCCAsmStmt *AS = dyn_cast<GCCAsmStmt>(S)) {}
bool NoReturnEdge = false;
}
diff --git a/test/SemaCXX/ms-exception-spec.cpp b/test/SemaCXX/ms-exception-spec.cpp
index bda56f5468d4..1be8ec293690 100644
--- a/test/SemaCXX/ms-exception-spec.cpp
+++ b/test/SemaCXX/ms-exception-spec.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions
+// expected-no-diagnostics
void f() throw(...) { }
diff --git a/test/SemaCXX/ms-interface.cpp b/test/SemaCXX/ms-interface.cpp
new file mode 100644
index 000000000000..3625f7027aa4
--- /dev/null
+++ b/test/SemaCXX/ms-interface.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+
+__interface I1 {
+ // expected-error@+1 {{user-declared constructor is not permitted within an interface type}}
+ I1();
+ // expected-error@+1 {{user-declared destructor is not permitted within an interface type}}
+ ~I1();
+ virtual void fn1() const;
+ // expected-error@+1 {{operator 'operator!' is not permitted within an interface type}}
+ bool operator!();
+ // expected-error@+1 {{operator 'operator int' is not permitted within an interface type}}
+ operator int();
+ // expected-error@+1 {{nested class I1::<anonymous> is not permitted within an interface type}}
+ struct { int a; };
+ void fn2() {
+ struct A { }; // should be ignored: not a nested class
+ }
+protected: // expected-error {{interface types cannot specify 'protected' access}}
+ typedef void void_t;
+ using int_t = int;
+private: // expected-error {{interface types cannot specify 'private' access}}
+ static_assert(true, "oops");
+};
+
+__interface I2 {
+ // expected-error@+1 {{data member 'i' is not permitted within an interface type}}
+ int i;
+ // expected-error@+1 {{static member function 'fn1' is not permitted within an interface type}}
+ static int fn1();
+private: // expected-error {{interface types cannot specify 'private' access}}
+ // expected-error@+1 {{non-public member function 'fn2' is not permitted within an interface type}}
+ void fn2();
+protected: // expected-error {{interface types cannot specify 'protected' access}}
+ // expected-error@+1 {{non-public member function 'fn3' is not permitted within an interface type}}
+ void fn3();
+public:
+ void fn4();
+};
+
+// expected-error@+1 {{'final' keyword not permitted with interface types}}
+__interface I3 final {
+};
+
+__interface I4 : I1, I2 {
+ void fn1() const override;
+ // expected-error@+1 {{'final' keyword not permitted with interface types}}
+ void fn2() final;
+};
+
+// expected-error@+1 {{interface type cannot inherit from non-public 'interface I1'}}
+__interface I5 : private I1 {
+};
+
+template <typename X>
+__interface I6 : X {
+};
+
+struct S { };
+class C { };
+__interface I { };
+
+static_assert(!__is_interface_class(S), "oops");
+static_assert(!__is_interface_class(C), "oops");
+static_assert(__is_interface_class(I), "oops");
+
+// expected-error@55 {{interface type cannot inherit from 'struct S'}}
+// expected-note@+1 {{in instantiation of template class 'I6<S>' requested here}}
+struct S1 : I6<S> {
+};
+
+// expected-error@55 {{interface type cannot inherit from 'class C'}}
+// expected-note@+1 {{in instantiation of template class 'I6<C>' requested here}}
+class C1 : I6<C> {
+};
+
+class C2 : I6<I> {
+};
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 4e1abc5e5bc8..7239646d8d7e 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -93,8 +93,7 @@ void f3() {
}
// make sure the following doesn't hit any asserts
-void f4(undef::C); // expected-error {{use of undeclared identifier 'undef'}} \
- expected-error {{variable has incomplete type 'void'}}
+void f4(undef::C); // expected-error {{use of undeclared identifier 'undef'}}
typedef void C2::f5(int); // expected-error{{typedef declarator cannot be qualified}}
@@ -160,7 +159,7 @@ namespace N {
void f();
// FIXME: if we move this to a separate definition of N, things break!
}
-void ::global_func2(int) { } // expected-warning{{extra qualification on member 'global_func2'}}
+void ::global_func2(int) { } // expected-error{{extra qualification on member 'global_func2'}}
void N::f() { } // okay
@@ -246,15 +245,15 @@ namespace PR7133 {
}
class CLASS {
- void CLASS::foo2(); // expected-warning {{extra qualification on member 'foo2'}}
+ void CLASS::foo2(); // expected-error {{extra qualification on member 'foo2'}}
};
namespace PR8159 {
class B { };
class A {
- int A::a; // expected-warning{{extra qualification on member 'a'}}
- static int A::b; // expected-warning{{extra qualification on member 'b'}}
+ int A::a; // expected-error{{extra qualification on member 'a'}}
+ static int A::b; // expected-error{{extra qualification on member 'b'}}
int ::c; // expected-error{{non-friend class member 'c' cannot have a qualified name}}
};
}
diff --git a/test/SemaCXX/new-delete-0x.cpp b/test/SemaCXX/new-delete-0x.cpp
index dcc2e9b8b12a..9e3b4928b141 100644
--- a/test/SemaCXX/new-delete-0x.cpp
+++ b/test/SemaCXX/new-delete-0x.cpp
@@ -27,6 +27,11 @@ void bad_news(int *ip)
void good_deletes()
{
delete [&]{ return (int*)0; }();
- // FIXME: This appears to be legal.
- delete []{ return (int*)0; }(); // unexpected-error {{expected expression}}
+}
+
+void bad_deletes()
+{
+ // 'delete []' is always array delete, per [expr.delete]p1.
+ // FIXME: Give a better diagnostic.
+ delete []{ return (int*)0; }(); // expected-error {{expected expression}}
}
diff --git a/test/SemaCXX/new-delete-predefined-decl-2.cpp b/test/SemaCXX/new-delete-predefined-decl-2.cpp
index 981476d4fd21..c2dfc77d01fb 100644
--- a/test/SemaCXX/new-delete-predefined-decl-2.cpp
+++ b/test/SemaCXX/new-delete-predefined-decl-2.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -DQUALIFIED -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5904
void f0(int *ptr) {
diff --git a/test/SemaCXX/new-delete-predefined-decl.cpp b/test/SemaCXX/new-delete-predefined-decl.cpp
index 20b15b729cd0..ae1006536112 100644
--- a/test/SemaCXX/new-delete-predefined-decl.cpp
+++ b/test/SemaCXX/new-delete-predefined-decl.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -DTEMPLATE_OVERLOAD -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <stddef.h>
diff --git a/test/SemaCXX/no-warn-composite-pointer-type.cpp b/test/SemaCXX/no-warn-composite-pointer-type.cpp
new file mode 100644
index 000000000000..f33f60de9fdd
--- /dev/null
+++ b/test/SemaCXX/no-warn-composite-pointer-type.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-compare-distinct-pointer-types -verify %s
+// expected-no-diagnostics
+// rdar://12501960
+
+void Foo(int **thing, const int **thingMax)
+{
+ if ((thing + 3) > thingMax)
+ return;
+}
diff --git a/test/SemaCXX/no-wchar.cpp b/test/SemaCXX/no-wchar.cpp
new file mode 100644
index 000000000000..291b657f51ab
--- /dev/null
+++ b/test/SemaCXX/no-wchar.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -fno-wchar -verify %s
+wchar_t x; // expected-error {{unknown type name 'wchar_t'}}
+
+typedef unsigned short wchar_t;
+void foo(const wchar_t* x);
+
+void bar() {
+ foo(L"wide string literal");
+}
diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp
index a6c0dbfc6560..a919213fb208 100644
--- a/test/SemaCXX/null_in_arithmetic_ops.cpp
+++ b/test/SemaCXX/null_in_arithmetic_ops.cpp
@@ -90,4 +90,6 @@ void f() {
b = e == NULL || NULL == e || e != NULL || NULL != e;
b = f == NULL || NULL == f || f != NULL || NULL != f;
b = "f" == NULL || NULL == "f" || "f" != NULL || NULL != "f";
+
+ return NULL; // expected-error{{void function 'f' should not return a value}}
}
diff --git a/test/SemaCXX/nullptr-98.cpp b/test/SemaCXX/nullptr-98.cpp
index 0d624c26de70..306b2033e456 100644
--- a/test/SemaCXX/nullptr-98.cpp
+++ b/test/SemaCXX/nullptr-98.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
+// expected-no-diagnostics
void f(void *);
void g() { f(__nullptr); }
diff --git a/test/SemaCXX/overload-value-dep-arg.cpp b/test/SemaCXX/overload-value-dep-arg.cpp
index c1834a722577..763daadc252a 100644
--- a/test/SemaCXX/overload-value-dep-arg.cpp
+++ b/test/SemaCXX/overload-value-dep-arg.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
class C {
C(void*);
diff --git a/test/SemaCXX/overloaded-builtin-operators-0x.cpp b/test/SemaCXX/overloaded-builtin-operators-0x.cpp
index 6a5a162af679..bf543892e43d 100644
--- a/test/SemaCXX/overloaded-builtin-operators-0x.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -std=c++11 -verify %s
+// expected-no-diagnostics
template <class T>
struct X
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index ac110a3c0561..19dc33871630 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify %s
+// REQUIRES: LP64
+
struct yes;
struct no;
diff --git a/test/SemaCXX/overloaded-operator-decl.cpp b/test/SemaCXX/overloaded-operator-decl.cpp
index 4519a2d1f9ad..972e2deac29e 100644
--- a/test/SemaCXX/overloaded-operator-decl.cpp
+++ b/test/SemaCXX/overloaded-operator-decl.cpp
@@ -48,3 +48,13 @@ struct PR10839 {
operator int; // expected-error{{'operator int' cannot be the name of a variable or data member}}
int operator+; // expected-error{{'operator+' cannot be the name of a variable or data member}}
};
+
+namespace PR14120 {
+ struct A {
+ static void operator()(int& i) { ++i; } // expected-error{{overloaded 'operator()' cannot be a static member function}}
+ };
+ void f() {
+ int i = 0;
+ A()(i);
+ }
+}
diff --git a/test/SemaCXX/pragma-pack.cpp b/test/SemaCXX/pragma-pack.cpp
index 5c1d5c6c82af..e468cce7f070 100644
--- a/test/SemaCXX/pragma-pack.cpp
+++ b/test/SemaCXX/pragma-pack.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace rdar8745206 {
diff --git a/test/SemaCXX/pragma-unused.cpp b/test/SemaCXX/pragma-unused.cpp
index c9ddffafafa9..c9eaab6d3f50 100644
--- a/test/SemaCXX/pragma-unused.cpp
+++ b/test/SemaCXX/pragma-unused.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -Wunused -verify %s
+// expected-no-diagnostics
struct S {
void m(int x, int y) {
diff --git a/test/SemaCXX/pragma-visibility.cpp b/test/SemaCXX/pragma-visibility.cpp
index e3ef97a74447..18c59c8c10ff 100644
--- a/test/SemaCXX/pragma-visibility.cpp
+++ b/test/SemaCXX/pragma-visibility.cpp
@@ -21,3 +21,10 @@ void f() {
#pragma GCC visibility push(protected)
#pragma GCC visibility pop
}
+
+namespace pr13662 {
+#pragma GCC visibility push(hidden)
+ template<class T> class __attribute__((__visibility__("default"))) foo;
+ class bar { template<class T> friend class foo; };
+#pragma GCC visibility pop
+}
diff --git a/test/SemaCXX/prefetch-enum.cpp b/test/SemaCXX/prefetch-enum.cpp
index 3c77dae70ff5..5457bbe498ff 100644
--- a/test/SemaCXX/prefetch-enum.cpp
+++ b/test/SemaCXX/prefetch-enum.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify
+// expected-no-diagnostics
// PR5679
enum X { A = 3 };
diff --git a/test/SemaCXX/primary-base.cpp b/test/SemaCXX/primary-base.cpp
index a6cbbad2427a..0b6aaef493cb 100644
--- a/test/SemaCXX/primary-base.cpp
+++ b/test/SemaCXX/primary-base.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
class A { virtual void f(); };
class B : virtual A { };
diff --git a/test/SemaCXX/ptrtomember-overload-resolution.cpp b/test/SemaCXX/ptrtomember-overload-resolution.cpp
index 787e33022aa3..85ed0aaa4f9e 100644
--- a/test/SemaCXX/ptrtomember-overload-resolution.cpp
+++ b/test/SemaCXX/ptrtomember-overload-resolution.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
// 13.3.3.2 Ranking implicit conversion sequences
// conversion of A::* to B::* is better than conversion of A::* to C::*,
diff --git a/test/SemaCXX/qualified-member-enum.cpp b/test/SemaCXX/qualified-member-enum.cpp
index 83b0a5911d43..750821bfd81c 100644
--- a/test/SemaCXX/qualified-member-enum.cpp
+++ b/test/SemaCXX/qualified-member-enum.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Check that this doesn't crash.
struct A {
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index 028c6909210e..4f3dab0514b9 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -136,4 +136,4 @@ namespace PR8608 {
}
// The following crashed trying to recursively evaluate the LValue.
-const int &do_not_crash = do_not_crash; // expected-warning{{variable 'do_not_crash' is uninitialized when used within its own initialization}}
+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}}
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index b659de001c0f..8fd23f4efe91 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu++11 %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fcxx-exceptions -std=gnu++11 %s -Wno-unreachable-code
namespace test0 {
struct D { ~D(); };
@@ -174,14 +174,14 @@ namespace test9 {
// http://llvm.org/PR10462
namespace PR10462 {
-enum MyEnum {
- something_valid,
- something_invalid
-};
-
-bool recurse() {
- MyEnum K;
- switch (K) { // expected-warning {{enumeration value 'something_invalid' not handled in switch}}
+ enum MyEnum {
+ something_valid,
+ something_invalid
+ };
+
+ bool recurse() {
+ MyEnum K;
+ switch (K) { // expected-warning {{enumeration value 'something_invalid' not handled in switch}}
case something_valid:
case what_am_i_thinking: // expected-error {{use of undeclared identifier}}
int *X = 0;
@@ -189,21 +189,88 @@ bool recurse() {
}
break;
+ }
}
}
-
namespace test10 {
-
-int test() {
- static void *ps[] = { &&a0 };
- goto *&&a0; // expected-error {{goto into protected scope}}
- int a = 3; // expected-note {{jump bypasses variable initialization}}
- a0:
- return 0;
+ int test() {
+ static void *ps[] = { &&a0 };
+ goto *&&a0; // expected-error {{goto into protected scope}}
+ int a = 3; // expected-note {{jump bypasses variable initialization}}
+ a0:
+ return 0;
+ }
+}
+
+// pr13812
+namespace test11 {
+ struct C {
+ C(int x);
+ ~C();
+ };
+ void f(void **ip) {
+ static void *ips[] = { &&l0 };
+ l0: // expected-note {{possible target of indirect goto}}
+ C c0 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+ goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ }
+}
+
+namespace test12 {
+ struct C {
+ C(int x);
+ ~C();
+ };
+ void f(void **ip) {
+ static void *ips[] = { &&l0 };
+ const C c0 = 17;
+ l0: // expected-note {{possible target of indirect goto}}
+ const C &c1 = 42; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+ const C &c2 = c0;
+ goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ }
}
+namespace test13 {
+ struct C {
+ C(int x);
+ ~C();
+ int i;
+ };
+ void f(void **ip) {
+ static void *ips[] = { &&l0 };
+ l0: // expected-note {{possible target of indirect goto}}
+ const int &c1 = C(1).i; // expected-note {{jump exits scope of variable with non-trivial destructor}}
+ goto *ip; // expected-error {{indirect goto might cross protected scopes}}
+ }
}
+namespace test14 {
+ struct C {
+ C(int x);
+ ~C();
+ operator int&() const;
+ };
+ void f(void **ip) {
+ static void *ips[] = { &&l0 };
+ l0:
+ // no warning since the C temporary is destructed before the goto.
+ const int &c1 = C(1);
+ goto *ip;
+ }
}
+// PR14225
+namespace test15 {
+ void f1() try {
+ goto x; // expected-error {{goto into protected scope}}
+ } catch(...) { // expected-note {{jump bypasses initialization of catch block}}
+ x: ;
+ }
+ void f2() try { // expected-note {{jump bypasses initialization of try block}}
+ x: ;
+ } catch(...) {
+ goto x; // expected-error {{goto into protected scope}}
+ }
+}
diff --git a/test/SemaCXX/short-wchar-sign.cpp b/test/SemaCXX/short-wchar-sign.cpp
index 9a177c04b104..7ce21c523cd7 100644
--- a/test/SemaCXX/short-wchar-sign.cpp
+++ b/test/SemaCXX/short-wchar-sign.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -pedantic -verify %s
// RUN: %clang_cc1 -fshort-wchar -fsyntax-only -pedantic -verify %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -pedantic -verify %s
+// expected-no-diagnostics
// Check that short wchar_t is unsigned, and that regular wchar_t is not.
int test[(wchar_t(-1)<wchar_t(0)) == (sizeof(wchar_t) == 4) ?1:-1];
diff --git a/test/SemaCXX/static-initializers.cpp b/test/SemaCXX/static-initializers.cpp
index ca49fce052e3..0620f484d9cb 100644
--- a/test/SemaCXX/static-initializers.cpp
+++ b/test/SemaCXX/static-initializers.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
int f() {
return 10;
}
diff --git a/test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp b/test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp
index 14ffcef704d9..8b24c4a3b130 100644
--- a/test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp
+++ b/test/SemaCXX/switch-implicit-fallthrough-cxx98.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -Wimplicit-fallthrough %s
+// XFAIL: *
+// NOTE: This test is marked XFAIL until we come up with a good language design
+// for a worfklow to use this warning outside of C++11.
int fallthrough(int n) {
switch (n / 10) {
diff --git a/test/SemaCXX/switch-implicit-fallthrough-macro.cpp b/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
new file mode 100644
index 000000000000..add212fcf5d8
--- /dev/null
+++ b/test/SemaCXX/switch-implicit-fallthrough-macro.cpp
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wimplicit-fallthrough -DCOMMAND_LINE_FALLTHROUGH=[[clang::fallthrough]] %s
+
+int fallthrough_compatibility_macro_from_command_line(int n) {
+ switch (n) {
+ case 0:
+ n = n * 10;
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'COMMAND_LINE_FALLTHROUGH;' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+ }
+ return n;
+}
+
+#ifdef __clang__
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define COMPATIBILITY_FALLTHROUGH [ [ /* test */ clang /* test */ \
+ :: fallthrough ] ] // testing whitespace and comments in macro definition
+#endif
+#endif
+
+#ifndef COMPATIBILITY_FALLTHROUGH
+#define COMPATIBILITY_FALLTHROUGH do { } while (0)
+#endif
+
+int fallthrough_compatibility_macro_from_source(int n) {
+ switch (n) {
+ case 0:
+ n = n * 20;
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'COMPATIBILITY_FALLTHROUGH;' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+ }
+ return n;
+}
+
+// Deeper macro substitution
+#define M1 [[clang::fallthrough]]
+#ifdef __clang__
+#define M2 M1
+#else
+#define M2
+#endif
+
+#define WRONG_MACRO1 clang::fallthrough
+#define WRONG_MACRO2 [[clang::fallthrough]
+#define WRONG_MACRO3 [[clang::fall through]]
+#define WRONG_MACRO4 [[clang::fallthrough]]]
+
+int fallthrough_compatibility_macro_in_macro(int n) {
+ switch (n) {
+ case 0:
+ n = n * 20;
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'M1;' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ // there was an idea that this ^ should be M2
+ ;
+ }
+ return n;
+}
+
+#undef M1
+#undef M2
+#undef COMPATIBILITY_FALLTHROUGH
+#undef COMMAND_LINE_FALLTHROUGH
+
+int fallthrough_compatibility_macro_undefined(int n) {
+ switch (n) {
+ case 0:
+ n = n * 20;
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+ }
+#define TOO_LATE [[clang::fallthrough]]
+ return n;
+}
+#undef TOO_LATE
+
+#define MACRO_WITH_HISTORY 11111111
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY [[clang::fallthrough]]
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 2222222
+
+int fallthrough_compatibility_macro_history(int n) {
+ switch (n) {
+ case 0:
+ n = n * 20;
+#undef MACRO_WITH_HISTORY
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+#define MACRO_WITH_HISTORY [[clang::fallthrough]]
+ }
+ return n;
+}
+
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 11111111
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY [[clang::fallthrough]]
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 2222222
+#undef MACRO_WITH_HISTORY
+
+int fallthrough_compatibility_macro_history2(int n) {
+ switch (n) {
+ case 0:
+ n = n * 20;
+#define MACRO_WITH_HISTORY [[clang::fallthrough]]
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'MACRO_WITH_HISTORY;' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 3333333
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 4444444
+#undef MACRO_WITH_HISTORY
+#define MACRO_WITH_HISTORY 5555555
+ }
+ return n;
+}
+
+template<const int N>
+int fallthrough_compatibility_macro_history_template(int n) {
+ switch (N * n) {
+ case 0:
+ n = n * 20;
+#define MACRO_WITH_HISTORY2 [[clang::fallthrough]]
+ case 1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'MACRO_WITH_HISTORY2;' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ ;
+#undef MACRO_WITH_HISTORY2
+#define MACRO_WITH_HISTORY2 3333333
+ }
+ return n;
+}
+
+#undef MACRO_WITH_HISTORY2
+#define MACRO_WITH_HISTORY2 4444444
+#undef MACRO_WITH_HISTORY2
+#define MACRO_WITH_HISTORY2 5555555
+
+void f() {
+ fallthrough_compatibility_macro_history_template<1>(0); // expected-note{{in instantiation of function template specialization 'fallthrough_compatibility_macro_history_template<1>' requested here}}
+}
diff --git a/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
index 7c52e5138b71..009c8180b1bb 100644
--- a/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
+++ b/test/SemaCXX/switch-implicit-fallthrough-per-method.cpp
@@ -42,7 +42,7 @@ void unscoped(int n) {
switch (n % 2) {
case 0:
// FIXME: This should be typo-corrected, probably.
- [[fallthrough]];
+ [[fallthrough]]; // expected-warning{{unknown attribute 'fallthrough' ignored}}
case 2: // expected-warning{{unannotated fall-through}} expected-note{{clang::fallthrough}} expected-note{{break;}}
[[clang::fallthrough]];
case 1:
diff --git a/test/SemaCXX/tag-ambig.cpp b/test/SemaCXX/tag-ambig.cpp
index 6403cf30597d..bbd17e7fe9b5 100644
--- a/test/SemaCXX/tag-ambig.cpp
+++ b/test/SemaCXX/tag-ambig.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/9168556>
typedef struct Point Point;
diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp
index c219b77d9e4d..462b4fa3da09 100644
--- a/test/SemaCXX/trailing-return-0x.cpp
+++ b/test/SemaCXX/trailing-return-0x.cpp
@@ -69,3 +69,19 @@ X<int> xx;
only<int> p2 = xx.f(0L);
only<double> p3 = xx.g(0L, 1.0);
only<double> p4 = xx.get_nested<double>().h(0L, 1.0, 3.14f);
+
+namespace PR12053 {
+ template <typename T>
+ auto f1(T t) -> decltype(f1(t)) {} // expected-note{{candidate template ignored}}
+
+ void test_f1() {
+ f1(0); // expected-error{{no matching function for call to 'f1'}}
+ }
+
+ template <typename T>
+ auto f2(T t) -> decltype(f2(&t)) {} // expected-note{{candidate template ignored}}
+
+ void test_f2() {
+ f2(0); // expected-error{{no matching function for call to 'f2'}}
+ }
+}
diff --git a/test/SemaCXX/trivial-constructor.cpp b/test/SemaCXX/trivial-constructor.cpp
index bda206b61f9a..ed5b526a124d 100644
--- a/test/SemaCXX/trivial-constructor.cpp
+++ b/test/SemaCXX/trivial-constructor.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
struct T1 {
};
static_assert(__has_trivial_constructor(T1), "T1 has trivial constructor!");
diff --git a/test/SemaCXX/trivial-destructor.cpp b/test/SemaCXX/trivial-destructor.cpp
index db415cf9050a..d3acec6284f5 100644
--- a/test/SemaCXX/trivial-destructor.cpp
+++ b/test/SemaCXX/trivial-destructor.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
struct T1 {
};
static_assert(__has_trivial_destructor(T1), "T1 has trivial destructor!");
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 893f08a422ca..c21ef51a7da5 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -116,14 +116,14 @@ void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of '
// Test the improved typo correction for the Parser::ParseCastExpr =>
// Sema::ActOnIdExpression => Sema::DiagnoseEmptyLookup call path.
-class SomeNetMessage;
+class SomeNetMessage; // expected-note 2{{'SomeNetMessage'}}
class Message {};
void foo(Message&);
void foo(SomeNetMessage&);
void doit(void *data) {
Message somenetmsg; // expected-note{{'somenetmsg' declared here}}
foo(somenetmessage); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'somenetmsg'?}}
- foo((somenetmessage)data); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'SomeNetMessage'?}}
+ foo((somenetmessage)data); // expected-error{{unknown type name 'somenetmessage'; did you mean 'SomeNetMessage'?}} expected-error{{incomplete type}}
}
// Test the typo-correction callback in BuildRecoveryCallExpr.
@@ -155,7 +155,7 @@ void Test3() {
struct R {};
bool begun(R);
void RangeTest() {
- for (auto b : R()) {} // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type}}
+ for (auto b : R()) {} // expected-error {{invalid range expression of type 'R'}}
}
// PR 12019 - Avoid infinite mutual recursion in DiagnoseInvalidRedeclaration
@@ -172,7 +172,7 @@ void Child::add_types(int value) {} // expected-error{{out-of-line definition of
// Sema::ActOnIdExpression by Parser::ParseCastExpression to allow type names as
// potential corrections for template arguments.
namespace clash {
-class ConstructExpr {}; // expected-note{{'clash::ConstructExpr' declared here}}
+class ConstructExpr {}; // expected-note 2{{'clash::ConstructExpr' declared here}}
}
class ClashTool {
bool HaveConstructExpr();
@@ -180,7 +180,7 @@ class ClashTool {
void test() {
ConstructExpr *expr = // expected-error{{unknown type name 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}}
- getExprAs<ConstructExpr>(); // expected-error{{use of undeclared identifier 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}}
+ getExprAs<ConstructExpr>(); // expected-error{{unknown type name 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}}
}
};
@@ -220,6 +220,8 @@ namespace PR13051 {
}
}
+inf f(doulbe); // expected-error{{'int'}} expected-error{{'double'}}
+
namespace PR6325 {
class foo { }; // expected-note{{'foo' declared here}}
// Note that for this example (pulled from the PR), if keywords are not excluded
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 385548b51cca..f55f10f7edaa 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -114,6 +114,19 @@ void setupA(bool x) {
A a17(a17.get2()); // expected-warning {{variable 'a17' is uninitialized when used within its own initialization}}
A a18 = x ? a18 : a17; // expected-warning {{variable 'a18' is uninitialized when used within its own initialization}}
A a19 = getA(x ? a19 : a17); // expected-warning {{variable 'a19' is uninitialized when used within its own initialization}}
+ A a20{a20}; // expected-warning {{variable 'a20' is uninitialized when used within its own initialization}}
+ A a21 = {a21}; // expected-warning {{variable 'a21' is uninitialized when used within its own initialization}}
+
+ // FIXME: Make the local uninitialized warning consistant with the global
+ // uninitialized checking.
+ A *a22 = new A(a22->count); // expected-warning {{variable 'a22' is uninitialized when used within its own initialization}}
+ A *a23 = new A(a23->ONE); // expected-warning {{variable 'a23' is uninitialized when used within its own initialization}}
+ A *a24 = new A(a24->TWO); // expected-warning {{variable 'a24' is uninitialized when used within its own initialization}}
+ A *a25 = new A(a25->zero()); // expected-warning {{variable 'a25' is uninitialized when used within its own initialization}}
+
+ A *a26 = new A(a26->get()); // expected-warning {{variable 'a26' is uninitialized when used within its own initialization}}
+ A *a27 = new A(a27->get2()); // expected-warning {{variable 'a27' is uninitialized when used within its own initialization}}
+ A *a28 = new A(a28->num); // expected-warning {{variable 'a28' is uninitialized when used within its own initialization}}
}
bool x;
@@ -138,6 +151,17 @@ A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when use
A a17(a17.get2()); // expected-warning {{variable 'a17' is uninitialized when used within its own initialization}}
A a18 = x ? a18 : a17; // expected-warning {{variable 'a18' is uninitialized when used within its own initialization}}
A a19 = getA(x ? a19 : a17); // expected-warning {{variable 'a19' is uninitialized when used within its own initialization}}
+A a20{a20}; // expected-warning {{variable 'a20' is uninitialized when used within its own initialization}}
+A a21 = {a21}; // expected-warning {{variable 'a21' is uninitialized when used within its own initialization}}
+
+A *a22 = new A(a22->count);
+A *a23 = new A(a23->ONE);
+A *a24 = new A(a24->TWO);
+A *a25 = new A(a25->zero());
+
+A *a26 = new A(a26->get()); // expected-warning {{variable 'a26' is uninitialized when used within its own initialization}}
+A *a27 = new A(a27->get2()); // expected-warning {{variable 'a27' is uninitialized when used within its own initialization}}
+A *a28 = new A(a28->num); // expected-warning {{variable 'a28' is uninitialized when used within its own initialization}}
struct B {
// POD struct.
@@ -150,6 +174,11 @@ B getB(int x) { return B(); };
B getB(int *x) { return B(); };
B getB(B *b) { return B(); };
+B* getPtrB() { return 0; };
+B* getPtrB(int x) { return 0; };
+B* getPtrB(int *x) { return 0; };
+B* getPtrB(B **b) { return 0; };
+
void setupB() {
B b1;
B b2(b1);
@@ -166,18 +195,56 @@ void setupB() {
B b8 = getB(b8.x); // expected-warning {{variable 'b8' is uninitialized when used within its own initialization}}
B b9 = getB(b9.y); // expected-warning {{variable 'b9' is uninitialized when used within its own initialization}}
B b10 = getB(-b10.x); // expected-warning {{variable 'b10' is uninitialized when used within its own initialization}}
+
+ B* b11 = 0;
+ B* b12(b11);
+ B* b13 = getPtrB();
+ B* b14 = getPtrB(&b14);
+
+ (void) b12;
+ (void) b13;
+
+ B* b15 = getPtrB(b15->x); // expected-warning {{variable 'b15' is uninitialized when used within its own initialization}}
+ B* b16 = getPtrB(b16->y); // expected-warning {{variable 'b16' is uninitialized when used within its own initialization}}
+
+ B b17 = { b17.x = 5, b17.y = 0 };
+ B b18 = { b18.x + 1, b18.y }; // expected-warning 2{{variable 'b18' is uninitialized when used within its own initialization}}
}
+B b1;
+B b2(b1);
+B b3 = { 5, &b3.x };
+B b4 = getB();
+B b5 = getB(&b5);
+B b6 = getB(&b6.x);
+
+B b7(b7); // expected-warning {{variable 'b7' is uninitialized when used within its own initialization}}
+B b8 = getB(b8.x); // expected-warning {{variable 'b8' is uninitialized when used within its own initialization}}
+B b9 = getB(b9.y); // expected-warning {{variable 'b9' is uninitialized when used within its own initialization}}
+B b10 = getB(-b10.x); // expected-warning {{variable 'b10' is uninitialized when used within its own initialization}}
+
+B* b11 = 0;
+B* b12(b11);
+B* b13 = getPtrB();
+B* b14 = getPtrB(&b14);
+
+B* b15 = getPtrB(b15->x); // expected-warning {{variable 'b15' is uninitialized when used within its own initialization}}
+B* b16 = getPtrB(b16->y); // expected-warning {{variable 'b16' is uninitialized when used within its own initialization}}
+
+B b17 = { b17.x = 5, b17.y = 0 };
+B b18 = { b18.x + 1, b18.y }; // expected-warning 2{{variable 'b18' is uninitialized when used within its own initialization}}
+
+
// Also test similar constructs in a field's initializer.
struct S {
int x;
void *ptr;
- S(bool (*)[1]) : x(x) {} // expected-warning {{field is uninitialized when used here}}
- S(bool (*)[2]) : x(x + 1) {} // expected-warning {{field is uninitialized when used here}}
- S(bool (*)[3]) : x(x + x) {} // expected-warning 2{{field is uninitialized when used here}}
- S(bool (*)[4]) : x(static_cast<long>(x) + 1) {} // expected-warning {{field is uninitialized when used here}}
- S(bool (*)[5]) : x(foo(x)) {} // expected-warning {{field is uninitialized when used here}}
+ S(bool (*)[1]) : x(x) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[2]) : x(x + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[3]) : x(x + x) {} // expected-warning 2{{field 'x' is uninitialized when used here}}
+ S(bool (*)[4]) : x(static_cast<long>(x) + 1) {} // expected-warning {{field 'x' is uninitialized when used here}}
+ S(bool (*)[5]) : x(foo(x)) {} // expected-warning {{field 'x' is uninitialized when used here}}
// These don't actually require the value of x and so shouldn't warn.
S(char (*)[1]) : x(sizeof(x)) {} // rdar://8610363
@@ -262,8 +329,8 @@ namespace {
C c;
D(char (*)[1]) : c(c.b.a.A1) {}
D(char (*)[2]) : c(c.b.a.A2()) {}
- D(char (*)[3]) : c(c.b.a.A3) {} // expected-warning {{field is uninitialized when used here}}
- D(char (*)[4]) : c(c.b.a.A4()) {} // expected-warning {{field is uninitialized when used here}}
+ D(char (*)[3]) : c(c.b.a.A3) {} // expected-warning {{field 'c' is uninitialized when used here}}
+ D(char (*)[4]) : c(c.b.a.A4()) {} // expected-warning {{field 'c' is uninitialized when used here}}
// c::a is static, so it is already initialized
D(char (*)[5]) : c(c.a.A1) {}
@@ -274,21 +341,21 @@ namespace {
struct E {
int a, b, c;
- E(char (*)[1]) : a(a ? b : c) {} // expected-warning {{field is uninitialized when used here}}
- E(char (*)[2]) : a(b ? a : a) {} // expected-warning 2{{field is uninitialized when used here}}
- E(char (*)[3]) : a(b ? (a) : c) {} // expected-warning {{field is uninitialized when used here}}
- E(char (*)[4]) : a(b ? c : (a+c)) {} // expected-warning {{field is uninitialized when used here}}
+ 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}}
+ E(char (*)[4]) : a(b ? c : (a+c)) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[5]) : a(b ? c : b) {}
- E(char (*)[6]) : a(a ?: a) {} // expected-warning 2{{field is uninitialized when used here}}
- E(char (*)[7]) : a(b ?: a) {} // expected-warning {{field is uninitialized when used here}}
- E(char (*)[8]) : a(a ?: c) {} // expected-warning {{field is uninitialized when used here}}
+ E(char (*)[6]) : a(a ?: a) {} // expected-warning 2{{field 'a' is uninitialized when used here}}
+ E(char (*)[7]) : a(b ?: a) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ E(char (*)[8]) : a(a ?: c) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[9]) : a(b ?: c) {}
E(char (*)[10]) : a((a, a, b)) {}
- E(char (*)[11]) : a((c + a, a + 1, b)) {} // expected-warning 2{{field is uninitialized when used here}}
- E(char (*)[12]) : a((b + c, c, a)) {} // expected-warning {{field is uninitialized when used here}}
- E(char (*)[13]) : a((a, a, a, a)) {} // expected-warning {{field is uninitialized when used here}}
+ E(char (*)[11]) : a((c + a, a + 1, b)) {} // expected-warning 2{{field 'a' is uninitialized when used here}}
+ E(char (*)[12]) : a((b + c, c, a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
+ E(char (*)[13]) : a((a, a, a, a)) {} // expected-warning {{field 'a' is uninitialized when used here}}
E(char (*)[14]) : a((b, c, c)) {}
};
@@ -304,16 +371,16 @@ namespace {
struct G {
F f1, f2;
F *f3, *f4;
- G(char (*)[1]) : f1(f1) {} // expected-warning {{field is uninitialized when used here}}
+ G(char (*)[1]) : f1(f1) {} // expected-warning {{field 'f1' is uninitialized when used here}}
G(char (*)[2]) : f2(f1) {}
G(char (*)[3]) : f2(F()) {}
- G(char (*)[4]) : f1(f1.*ptr) {} // expected-warning {{field is uninitialized when used here}}
+ G(char (*)[4]) : f1(f1.*ptr) {} // expected-warning {{field 'f1' is uninitialized when used here}}
G(char (*)[5]) : f2(f1.*ptr) {}
- G(char (*)[6]) : f3(f3) {} // expected-warning {{field is uninitialized when used here}}
- G(char (*)[7]) : f3(f3->*f_ptr) {} // expected-warning {{field is uninitialized when used here}}
- G(char (*)[8]) : f3(new F(f3->*ptr)) {} // expected-warning {{field is uninitialized when used here}}
+ G(char (*)[6]) : f3(f3) {} // expected-warning {{field 'f3' is uninitialized when used here}}
+ G(char (*)[7]) : f3(f3->*f_ptr) {} // expected-warning {{field 'f3' is uninitialized when used here}}
+ G(char (*)[8]) : f3(new F(f3->*ptr)) {} // expected-warning {{field 'f3' is uninitialized when used here}}
};
}
@@ -379,21 +446,53 @@ namespace statics {
}
}
+namespace in_class_initializers {
+ struct S {
+ S() : a(a + 1) {} // expected-warning{{field 'a' is uninitialized when used here}}
+ int a = 42; // Note: because a is in a member initializer list, this initialization is ignored.
+ };
+
+ struct T {
+ T() : b(a + 1) {} // No-warning.
+ int a = 42;
+ int b;
+ };
+
+ struct U {
+ U() : a(b + 1), b(a + 1) {} // FIXME: Warn here.
+ int a = 42; // Note: because a and b are in the member initializer list, these initializers are ignored.
+ int b = 1;
+ };
+}
+
namespace references {
- int &a = a; // expected-warning{{variable 'a' is uninitialized when used within its own initialization}}
+ int &a = a; // expected-warning{{reference 'a' is not yet bound to a value when used within its own initialization}}
+ int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}}
+ int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}}
+ int &d{d}; // expected-warning{{reference 'd' is not yet bound to a value when used within its own initialization}}
struct S {
- S() : a(a) {} // expected-warning{{field is uninitialized when used here}}
+ S() : a(a) {} // expected-warning{{reference 'a' is not yet bound to a value when used here}}
int &a;
};
void f() {
- int &a = a; // expected-warning{{variable 'a' is uninitialized when used within its own initialization}}
+ int &a = a; // expected-warning{{reference 'a' is not yet bound to a value when used within its own initialization}}
+ int &b(b); // expected-warning{{reference 'b' is not yet bound to a value when used within its own initialization}}
+ int &c = a ? b : c; // expected-warning{{reference 'c' is not yet bound to a value when used within its own initialization}}
+ int &d{d}; // expected-warning{{reference 'd' is not yet bound to a value when used within its own initialization}}
}
struct T {
T() : a(b), b(a) {} // FIXME: Warn here.
int &a, &b;
- int &c = c; // FIXME: Warn here.
+ int &c = c; // expected-warning{{reference 'c' is not yet bound to a value when used here}}
+ };
+
+ int x;
+ struct U {
+ U() : b(a) {} // No-warning.
+ int &a = x;
+ int &b;
};
}
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
index 893e0cc5dc86..ce5972bf2dc5 100644
--- a/test/SemaCXX/unknown-type-name.cpp
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -6,6 +6,8 @@ namespace N {
};
typedef Wibble foo;
+
+ int zeppelin; // expected-note{{declared here}}
}
using namespace N;
@@ -15,6 +17,13 @@ void f() {
foo::bar = 4; // expected-error{{no member named 'bar' in 'N::Wibble'}}
}
+int f(foo::bar); // expected-error{{no type named 'bar' in 'N::Wibble'}}
+
+int f(doulbe); // expected-error{{did you mean 'double'?}}
+
+int fun(zapotron); // expected-error{{unknown type name 'zapotron'}}
+int var(zepelin); // expected-error{{did you mean 'zeppelin'?}}
+
template<typename T>
struct A {
typedef T type;
@@ -59,6 +68,20 @@ void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
template<typename T>
void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+int *p;
+
+// FIXME: We should assume that 'undeclared' is a type, not a parameter name
+// here, and produce an 'unknown type name' diagnostic instead.
+int f1(undeclared, int); // expected-error{{requires a type specifier}}
+
+int f2(undeclared, 0); // expected-error{{undeclared identifier}}
+
+int f3(undeclared *p, int); // expected-error{{unknown type name 'undeclared'}}
+
+int f4(undeclared *p, 0); // expected-error{{undeclared identifier}}
+
+int *test(UnknownType *fool) { return 0; } // expected-error{{unknown type name 'UnknownType'}}
+
template<typename T> int A<T>::n(T::value); // ok
template<typename T>
A<T>::type // expected-error{{missing 'typename'}}
diff --git a/test/SemaCXX/unused-functions.cpp b/test/SemaCXX/unused-functions.cpp
index 359808203892..d05ff4db6055 100644
--- a/test/SemaCXX/unused-functions.cpp
+++ b/test/SemaCXX/unused-functions.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wunused -verify %s
+// expected-no-diagnostics
static int foo(int x) { return x; }
diff --git a/test/SemaCXX/unused.cpp b/test/SemaCXX/unused.cpp
index 54898c828ec6..fbaf8c8bf3c1 100644
--- a/test/SemaCXX/unused.cpp
+++ b/test/SemaCXX/unused.cpp
@@ -34,3 +34,30 @@ namespace derefvolatile {
(void)y; // don't warn here, because it's a common pattern.
}
}
+
+// <rdar://problem/12359208>
+namespace AnonObject {
+ struct Foo {
+ Foo(const char* const message);
+ ~Foo();
+ };
+ void f() {
+ Foo("Hello World!"); // don't warn
+ int(1); // expected-warning {{expression result unused}}
+ }
+}
+
+// Test that constructing an object (which may have side effects) with
+// constructor arguments which are dependent doesn't produce an unused value
+// warning.
+namespace UnresolvedLookup {
+ struct Foo {
+ Foo(int i, int j);
+ };
+ template <typename T>
+ struct Bar {
+ void f(T t) {
+ Foo(t, 0); // no warning
+ }
+ };
+}
diff --git a/test/SemaCXX/using-decl-pr4441.cpp b/test/SemaCXX/using-decl-pr4441.cpp
index 39a446fed9ac..da21db311bb6 100644
--- a/test/SemaCXX/using-decl-pr4441.cpp
+++ b/test/SemaCXX/using-decl-pr4441.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace A {
struct B { };
diff --git a/test/SemaCXX/using-decl-pr4450.cpp b/test/SemaCXX/using-decl-pr4450.cpp
index 4f929ad15f5f..ba81e93e0b07 100644
--- a/test/SemaCXX/using-decl-pr4450.cpp
+++ b/test/SemaCXX/using-decl-pr4450.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
namespace A {
void g();
diff --git a/test/SemaCXX/value-dependent-exprs.cpp b/test/SemaCXX/value-dependent-exprs.cpp
index 2017ffa67c90..b26ca253b7c0 100644
--- a/test/SemaCXX/value-dependent-exprs.cpp
+++ b/test/SemaCXX/value-dependent-exprs.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
template <unsigned I>
class C0 {
diff --git a/test/SemaCXX/vararg-default-arg.cpp b/test/SemaCXX/vararg-default-arg.cpp
index 3c8e41cb3e35..27c2bbbf5b8e 100644
--- a/test/SemaCXX/vararg-default-arg.cpp
+++ b/test/SemaCXX/vararg-default-arg.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// expected-no-diagnostics
// PR5462
void f1(void);
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 86b560e814c2..da06d957180e 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -123,3 +123,21 @@ int t9(int n) {
// Make sure the error works in potentially-evaluated sizeof
return (int)sizeof(*(Helper(Foo()), (int (*)[n])0)); // expected-warning{{cannot pass object of non-POD type}}
}
+
+// PR14057
+namespace t10 {
+ struct F {
+ F();
+ };
+
+ struct S {
+ void operator()(F, ...);
+ };
+
+ void foo() {
+ S s;
+ F f;
+ s.operator()(f);
+ s(f);
+ }
+}
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index 82245ac29bbd..4d2d064b32f1 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -267,3 +267,14 @@ void test_mixed_vector_types(fltx4 f, intx4 n, flte4 g, flte4 m) {
(void)(n *= m);
(void)(n /= m);
}
+
+template<typename T> void test_pseudo_dtor_tmpl(T *ptr) {
+ ptr->~T();
+ (*ptr).~T();
+}
+
+void test_pseudo_dtor(fltx4 *f) {
+ f->~fltx4();
+ (*f).~fltx4();
+ test_pseudo_dtor_tmpl(f);
+}
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
index 04f2e7952547..09084e36bb49 100644
--- a/test/SemaCXX/warn-assignment-condition.cpp
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -133,14 +133,14 @@ void test2() {
namespace rdar9027658 {
template <typename T>
-void f() {
- if ((T::g == 3)) { } // expected-warning {{equality comparison with extraneous parentheses}} \
+void f(T t) {
+ if ((t.g == 3)) { } // expected-warning {{equality comparison with extraneous parentheses}} \
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
// expected-note {{remove extraneous parentheses around the comparison to silence this warning}}
}
struct S { int g; };
void test() {
- f<S>(); // expected-note {{in instantiation}}
+ f(S()); // expected-note {{in instantiation}}
}
}
diff --git a/test/SemaCXX/warn-c++11-extensions.cpp b/test/SemaCXX/warn-c++11-extensions.cpp
new file mode 100644
index 000000000000..8f351711195e
--- /dev/null
+++ b/test/SemaCXX/warn-c++11-extensions.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-extensions -verify %s
+
+long long ll1 = // expected-warning {{'long long' is a C++11 extension}}
+ -42LL; // expected-warning {{'long long' is a C++11 extension}}
+unsigned long long ull1 = // expected-warning {{'long long' is a C++11 extension}}
+ 42ULL; // expected-warning {{'long long' is a C++11 extension}}
+
diff --git a/test/SemaCXX/warn-enum-compare.cpp b/test/SemaCXX/warn-enum-compare.cpp
index 52639e70a804..c68275e1a73e 100644
--- a/test/SemaCXX/warn-enum-compare.cpp
+++ b/test/SemaCXX/warn-enum-compare.cpp
@@ -39,8 +39,8 @@ void test () {
while (b == c);
while (B1 == name1::B2);
while (B2 == name2::B1);
- while (x == AnonAA);
- while (AnonBB == y);
+ while (x == AnonAA); // expected-warning {{comparison of constant 42 with expression of type 'Foo' is always false}}
+ while (AnonBB == y); // expected-warning {{comparison of constant 45 with expression of type 'Bar' is always false}}
while (AnonAA == AnonAB);
while (AnonAB == AnonBA);
while (AnonBB == AnonAA);
diff --git a/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp b/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp
new file mode 100644
index 000000000000..1d8037aceb73
--- /dev/null
+++ b/test/SemaCXX/warn-implicit-conversion-floating-point-to-bool.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+float foof(float x);
+double food(double x);
+void foo(bool b, float f);
+
+void bar() {
+
+ float c = 1.7;
+ bool b = c;
+
+ double e = 1.7;
+ b = e;
+
+ b = foof(4.0);
+
+ b = foof(c < 1); // expected-warning {{implicit conversion turns floating-point number into bool: 'float' to 'bool'}}
+
+ b = food(e < 2); // expected-warning {{implicit conversion turns floating-point number into bool: 'double' to 'bool'}}
+
+ foo(c, b); // expected-warning {{implicit conversion turns floating-point number into bool: 'float' to 'bool'}}
+ foo(c, c);
+
+}
diff --git a/test/SemaCXX/warn-missing-variable-declarations.cpp b/test/SemaCXX/warn-missing-variable-declarations.cpp
new file mode 100644
index 000000000000..12af9735d1a9
--- /dev/null
+++ b/test/SemaCXX/warn-missing-variable-declarations.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang -Wmissing-variable-declarations -fsyntax-only -Xclang -verify %s
+
+// Variable declarations that should trigger a warning.
+int vbad1; // expected-warning{{no previous extern declaration for non-static variable 'vbad1'}}
+int vbad2 = 10; // expected-warning{{no previous extern declaration for non-static variable 'vbad2'}}
+
+namespace x {
+ int vbad3; // expected-warning{{no previous extern declaration for non-static variable 'vbad3'}}
+}
+
+// Variable declarations that should not trigger a warning.
+static int vgood1;
+extern int vgood2;
+int vgood2;
+static struct {
+ int mgood1;
+} vgood3;
+
+// Functions should never trigger a warning.
+void fgood1(void);
+void fgood2(void) {
+ int lgood1;
+ static int lgood2;
+}
+static void fgood3(void) {
+ int lgood3;
+ static int lgood4;
+}
+
+// Structures, namespaces and classes should be unaffected.
+struct sgood1 {
+ int mgood2;
+};
+struct {
+ int mgood3;
+} sgood2;
+class CGood1 {
+ static int MGood1;
+};
+int CGood1::MGood1;
+namespace {
+ int mgood4;
+}
diff --git a/test/SemaCXX/warn-new-overaligned-2.cpp b/test/SemaCXX/warn-new-overaligned-2.cpp
index 550500906892..e643015f31b8 100644
--- a/test/SemaCXX/warn-new-overaligned-2.cpp
+++ b/test/SemaCXX/warn-new-overaligned-2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -Wover-aligned -verify %s
+// expected-no-diagnostics
// This test verifies that we don't warn when the global operator new is
// overridden. That's why we can't merge this with the other test file.
diff --git a/test/SemaCXX/warn-overloaded-virtual.cpp b/test/SemaCXX/warn-overloaded-virtual.cpp
index 8e2b671bf493..9b0f5aa9f339 100644
--- a/test/SemaCXX/warn-overloaded-virtual.cpp
+++ b/test/SemaCXX/warn-overloaded-virtual.cpp
@@ -64,3 +64,59 @@ public:
static void f() {}
};
}
+
+namespace ThreeLayer {
+struct A {
+ virtual void f();
+};
+
+struct B: A {
+ void f();
+ void f(int);
+};
+
+struct C: B {
+ void f(int);
+ using A::f;
+};
+}
+
+namespace UnbalancedVirtual {
+struct Base {
+ virtual void func();
+};
+
+struct Derived1: virtual Base {
+ virtual void func();
+};
+
+struct Derived2: virtual Base {
+};
+
+struct MostDerived: Derived1, Derived2 {
+ void func(int);
+ void func();
+};
+}
+
+namespace UnbalancedVirtual2 {
+struct Base {
+ virtual void func();
+};
+
+struct Derived1: virtual Base {
+ virtual void func();
+};
+
+struct Derived2: virtual Base {
+};
+
+struct Derived3: Derived1 {
+ virtual void func();
+};
+
+struct MostDerived: Derived3, Derived2 {
+ void func(int);
+ void func();
+};
+}
diff --git a/test/SemaCXX/warn-self-comparisons.cpp b/test/SemaCXX/warn-self-comparisons.cpp
index 620be195c1de..2e8d130bcd5a 100644
--- a/test/SemaCXX/warn-self-comparisons.cpp
+++ b/test/SemaCXX/warn-self-comparisons.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
void f(int (&array1)[2], int (&array2)[2]) {
if (array1 == array2) { } // no warning
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 17a1931c1594..bd555ac56c36 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -24,10 +24,6 @@
__attribute__ ((shared_locks_required(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
-//-----------------------------------------//
-// Helper fields
-//-----------------------------------------//
-
class __attribute__((lockable)) Mutex {
public:
@@ -60,6 +56,15 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
};
+// The universal lock, written "*", allows checking to be selectively turned
+// off for a particular piece of code.
+void beginNoWarnOnReads() SHARED_LOCK_FUNCTION("*");
+void endNoWarnOnReads() UNLOCK_FUNCTION("*");
+void beginNoWarnOnWrites() EXCLUSIVE_LOCK_FUNCTION("*");
+void endNoWarnOnWrites() UNLOCK_FUNCTION("*");
+
+
+// For testing handling of smart pointers.
template<class T>
class SmartPtr {
public:
@@ -76,6 +81,15 @@ private:
};
+// For testing destructor calls and cleanup.
+class MyString {
+public:
+ MyString(const char* s);
+ ~MyString();
+};
+
+
+
Mutex sls_mu;
Mutex sls_mu2 __attribute__((acquired_after(sls_mu)));
@@ -529,7 +543,8 @@ void late_bad_0() {
LateFoo fooB;
fooA.mu.Lock();
fooB.a = 5; // \
- // expected-warning{{writing variable 'a' requires locking 'fooB.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'fooB.mu' exclusively}} \
+ // expected-note{{found near match 'fooA.mu'}}
fooA.mu.Unlock();
}
@@ -549,7 +564,8 @@ void late_bad_2() {
LateBar BarA;
BarA.FooPointer->mu.Lock();
BarA.Foo.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.Foo.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo.mu' exclusively}} \
+ // expected-note{{found near match 'BarA.FooPointer->mu'}}
BarA.FooPointer->mu.Unlock();
}
@@ -557,7 +573,8 @@ void late_bad_3() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.FooPointer->a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.FooPointer->mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.FooPointer->mu' exclusively}} \
+ // expected-note{{found near match 'BarA.Foo.mu'}}
BarA.Foo.mu.Unlock();
}
@@ -565,7 +582,8 @@ void late_bad_4() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.Foo2.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.Foo2.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo2.mu' exclusively}} \
+ // expected-note{{found near match 'BarA.Foo.mu'}}
BarA.Foo.mu.Unlock();
}
@@ -1233,7 +1251,9 @@ void func()
{
b1->MyLock();
b1->a_ = 5;
- b2->a_ = 3; // expected-warning {{writing variable 'a_' requires locking 'b2->mu1_' exclusively}}
+ b2->a_ = 3; // \
+ // expected-warning {{writing variable 'a_' requires locking 'b2->mu1_' exclusively}} \
+ // expected-note {{found near match 'b1->mu1_'}}
b2->MyLock();
b2->MyUnlock();
b1->MyUnlock();
@@ -1263,11 +1283,13 @@ int func(int i)
int x;
b3->mu1_.Lock();
res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires locking 'b1.mu1_'}} \
- // expected-warning {{writing variable 'res' requires locking 'mu' exclusively}}
+ // expected-warning {{writing variable 'res' requires locking 'mu' exclusively}} \
+ // expected-note {{found near match 'b3->mu1_'}}
*p = i; // expected-warning {{reading variable 'p' requires locking 'mu'}} \
// expected-warning {{writing the value pointed to by 'p' requires locking 'mu' exclusively}}
b1.a_ = res + b3->b_; // expected-warning {{reading variable 'res' requires locking 'mu'}} \
- // expected-warning {{writing variable 'a_' requires locking 'b1.mu1_' exclusively}}
+ // expected-warning {{writing variable 'a_' requires locking 'b1.mu1_' exclusively}} \
+ // expected-note {{found near match 'b3->mu1_'}}
b3->b_ = *b1.q; // expected-warning {{reading the value pointed to by 'q' requires locking 'mu'}}
b3->mu1_.Unlock();
b1.b_ = res; // expected-warning {{reading variable 'res' requires locking 'mu'}}
@@ -1292,8 +1314,12 @@ class Foo {
child->Func(new_foo); // There shouldn't be any warning here as the
// acquired lock is not in child.
- child->bar(7); // expected-warning {{calling function 'bar' requires exclusive lock on 'child->lock_'}}
- child->a_ = 5; // expected-warning {{writing variable 'a_' requires locking 'child->lock_' exclusively}}
+ child->bar(7); // \
+ // expected-warning {{calling function 'bar' requires exclusive lock on 'child->lock_'}} \
+ // expected-note {{found near match 'lock_'}}
+ child->a_ = 5; // \
+ // expected-warning {{writing variable 'a_' requires locking 'child->lock_' exclusively}} \
+ // expected-note {{found near match 'lock_'}}
lock_.Unlock();
}
@@ -1491,7 +1517,8 @@ namespace substitution_test {
DataLocker dlr;
dlr.lockData(d1);
foo(d2); // \
- // expected-warning {{calling function 'foo' requires exclusive lock on 'd2->mu'}}
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'd2->mu'}} \
+ // expected-note {{found near match 'd1->mu'}}
dlr.unlockData(d1);
}
};
@@ -1516,22 +1543,6 @@ namespace constructor_destructor_tests {
}
-namespace invalid_lock_expression_test {
-
-class LOCKABLE MyLockable {
-public:
- MyLockable() __attribute__((exclusive_lock_function)) { }
- ~MyLockable() { }
-};
-
-// create an empty lock expression
-void foo() {
- MyLockable lock; // \
- // expected-warning {{cannot resolve lock expression}}
-}
-
-} // end namespace invalid_lock_expression_test
-
namespace template_member_test {
struct S { int n; };
@@ -1638,6 +1649,8 @@ void bar() {
}; // end namespace FunctionAttrTest
+namespace TryLockTest {
+
struct TestTryLock {
Mutex mu;
int a GUARDED_BY(mu);
@@ -1734,8 +1747,36 @@ struct TestTryLock {
b = !b;
}
}
+
+ // Test merge of exclusive trylock
+ void foo11() {
+ if (cond) {
+ if (!mu.TryLock())
+ return;
+ }
+ else {
+ mu.Lock();
+ }
+ a = 10;
+ mu.Unlock();
+ }
+
+ // Test merge of shared trylock
+ void foo12() {
+ if (cond) {
+ if (!mu.ReaderTryLock())
+ return;
+ }
+ else {
+ mu.ReaderLock();
+ }
+ int i = a;
+ mu.Unlock();
+ }
}; // end TestTrylock
+} // end namespace TrylockTest
+
namespace TestTemplateAttributeInstantiation {
@@ -1829,7 +1870,8 @@ void test() {
f1.mu_.Unlock();
bt.barTD(&f1); // \
- // expected-warning {{calling function 'barTD' requires exclusive lock on 'f1.mu_'}}
+ // expected-warning {{calling function 'barTD' requires exclusive lock on 'f1.mu_'}} \
+ // expected-note {{found near match 'bt.fooBase.mu_'}}
bt.fooBase.mu_.Unlock();
bt.fooBaseT.mu_.Unlock();
@@ -2235,27 +2277,32 @@ void test() {
bar.getFoo().mu_.Lock();
bar.getFooey().a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFooey().mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFooey().mu_' exclusively}} \
+ // expected-note {{found near match 'bar.getFoo().mu_'}}
bar.getFoo().mu_.Unlock();
bar.getFoo2(a).mu_.Lock();
bar.getFoo2(b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFoo2(b).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo2(b).mu_' exclusively}} \
+ // expected-note {{found near match 'bar.getFoo2(a).mu_'}}
bar.getFoo2(a).mu_.Unlock();
bar.getFoo3(a, b).mu_.Lock();
bar.getFoo3(a, c).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFoo3(a,c).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo3(a,c).mu_' exclusively}} \
+ // expected-note {{'bar.getFoo3(a,b).mu_'}}
bar.getFoo3(a, b).mu_.Unlock();
getBarFoo(bar, a).mu_.Lock();
getBarFoo(bar, b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'getBarFoo(bar,b).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'getBarFoo(bar,b).mu_' exclusively}} \
+ // expected-note {{'getBarFoo(bar,a).mu_'}}
getBarFoo(bar, a).mu_.Unlock();
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
(a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking '((a#_)#_#fooArray[b]).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking '((a#_)#_#fooArray[b]).mu_' exclusively}} \
+ // expected-note {{'((a#_)#_#fooArray[_]).mu_'}}
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
}
@@ -2314,7 +2361,9 @@ void test1(Foo* f1, Foo* f2) {
f1->a = 0;
f1->foo();
- f1->foo2(f2); // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}}
+ f1->foo2(f2); // \
+ // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}} \
+ // expected-note {{found near match 'f1->mu_'}}
Foo::getMu(f2)->Lock();
f1->foo2(f2);
@@ -2354,7 +2403,9 @@ void test2(Bar* b1, Bar* b2) {
b1->b = 0;
b1->bar();
- b1->bar2(b2); // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}}
+ b1->bar2(b2); // \
+ // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}} \
+ // // expected-note {{found near match 'b1->mu_'}}
b2->getMu()->Lock();
b1->bar2(b2);
@@ -3119,3 +3170,545 @@ void test() {
} // end namespace ExistentialPatternMatching
+
+namespace StringIgnoreTest {
+
+class Foo {
+public:
+ Mutex mu_;
+ void lock() EXCLUSIVE_LOCK_FUNCTION("");
+ void unlock() UNLOCK_FUNCTION("");
+ void goober() EXCLUSIVE_LOCKS_REQUIRED("");
+ void roober() SHARED_LOCKS_REQUIRED("");
+};
+
+
+class Bar : public Foo {
+public:
+ void bar(Foo* f) {
+ f->unlock();
+ f->goober();
+ f->roober();
+ f->lock();
+ };
+};
+
+} // end namespace StringIgnoreTest
+
+
+namespace LockReturnedScopeFix {
+
+class Base {
+protected:
+ struct Inner;
+ bool c;
+
+ const Mutex& getLock(const Inner* i);
+
+ void lockInner (Inner* i) EXCLUSIVE_LOCK_FUNCTION(getLock(i));
+ void unlockInner(Inner* i) UNLOCK_FUNCTION(getLock(i));
+ void foo(Inner* i) EXCLUSIVE_LOCKS_REQUIRED(getLock(i));
+
+ void bar(Inner* i);
+};
+
+
+struct Base::Inner {
+ Mutex lock_;
+ void doSomething() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+};
+
+
+const Mutex& Base::getLock(const Inner* i) LOCK_RETURNED(i->lock_) {
+ return i->lock_;
+}
+
+
+void Base::foo(Inner* i) {
+ i->doSomething();
+}
+
+void Base::bar(Inner* i) {
+ if (c) {
+ i->lock_.Lock();
+ unlockInner(i);
+ }
+ else {
+ lockInner(i);
+ i->lock_.Unlock();
+ }
+}
+
+} // end namespace LockReturnedScopeFix
+
+
+namespace TrylockWithCleanups {
+
+struct Foo {
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+Foo* GetAndLockFoo(const MyString& s)
+ EXCLUSIVE_TRYLOCK_FUNCTION(true, &Foo::mu_);
+
+static void test() {
+ Foo* lt = GetAndLockFoo("foo");
+ if (!lt) return;
+ int a = lt->a;
+ lt->mu_.Unlock();
+}
+
+} // end namespace TrylockWithCleanups
+
+
+namespace UniversalLock {
+
+class Foo {
+ Mutex mu_;
+ bool c;
+
+ int a GUARDED_BY(mu_);
+ void r_foo() SHARED_LOCKS_REQUIRED(mu_);
+ void w_foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+ void test1() {
+ int b;
+
+ beginNoWarnOnReads();
+ b = a;
+ r_foo();
+ endNoWarnOnReads();
+
+ beginNoWarnOnWrites();
+ a = 0;
+ w_foo();
+ endNoWarnOnWrites();
+ }
+
+ // don't warn on joins with universal lock
+ void test2() {
+ if (c) {
+ beginNoWarnOnWrites();
+ }
+ a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ endNoWarnOnWrites(); // \
+ // expected-warning {{unlocking '*' that was not locked}}
+ }
+
+
+ // make sure the universal lock joins properly
+ void test3() {
+ if (c) {
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ }
+ else {
+ beginNoWarnOnWrites();
+ mu_.Lock();
+ }
+ a = 0;
+ endNoWarnOnWrites();
+ mu_.Unlock();
+ }
+
+
+ // combine universal lock with other locks
+ void test4() {
+ beginNoWarnOnWrites();
+ mu_.Lock();
+ mu_.Unlock();
+ endNoWarnOnWrites();
+
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ endNoWarnOnWrites();
+ mu_.Unlock();
+
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ mu_.Unlock();
+ endNoWarnOnWrites();
+ }
+};
+
+} // end namespace UniversalLock
+
+
+namespace TemplateLockReturned {
+
+template<class T>
+class BaseT {
+public:
+ virtual void baseMethod() = 0;
+ Mutex* get_mutex() LOCK_RETURNED(mutex_) { return &mutex_; }
+
+ Mutex mutex_;
+ int a GUARDED_BY(mutex_);
+};
+
+
+class Derived : public BaseT<int> {
+public:
+ void baseMethod() EXCLUSIVE_LOCKS_REQUIRED(get_mutex()) {
+ a = 0;
+ }
+};
+
+} // end namespace TemplateLockReturned
+
+
+namespace ExprMatchingBugFix {
+
+class Foo {
+public:
+ Mutex mu_;
+};
+
+
+class Bar {
+public:
+ bool c;
+ Foo* foo;
+ Bar(Foo* f) : foo(f) { }
+
+ struct Nested {
+ Foo* foo;
+ Nested(Foo* f) : foo(f) { }
+
+ void unlockFoo() UNLOCK_FUNCTION(&Foo::mu_);
+ };
+
+ void test();
+};
+
+
+void Bar::test() {
+ foo->mu_.Lock();
+ if (c) {
+ Nested *n = new Nested(foo);
+ n->unlockFoo();
+ }
+ else {
+ foo->mu_.Unlock();
+ }
+}
+
+}; // end namespace ExprMatchingBugfix
+
+
+namespace ComplexNameTest {
+
+class Foo {
+public:
+ static Mutex mu_;
+
+ Foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) { }
+ ~Foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) { }
+
+ int operator[](int i) EXCLUSIVE_LOCKS_REQUIRED(mu_) { return 0; }
+};
+
+class Bar {
+public:
+ static Mutex mu_;
+
+ Bar() LOCKS_EXCLUDED(mu_) { }
+ ~Bar() LOCKS_EXCLUDED(mu_) { }
+
+ int operator[](int i) LOCKS_EXCLUDED(mu_) { return 0; }
+};
+
+
+void test1() {
+ Foo f; // expected-warning {{calling function 'Foo' requires exclusive lock on 'mu_'}}
+ int a = f[0]; // expected-warning {{calling function 'operator[]' requires exclusive lock on 'mu_'}}
+} // expected-warning {{calling function '~Foo' requires exclusive lock on 'mu_'}}
+
+
+void test2() {
+ Bar::mu_.Lock();
+ {
+ Bar b; // expected-warning {{cannot call function 'Bar' while mutex 'mu_' is locked}}
+ int a = b[0]; // expected-warning {{cannot call function 'operator[]' while mutex 'mu_' is locked}}
+ } // expected-warning {{cannot call function '~Bar' while mutex 'mu_' is locked}}
+ Bar::mu_.Unlock();
+}
+
+}; // end namespace ComplexNameTest
+
+
+namespace UnreachableExitTest {
+
+class FemmeFatale {
+public:
+ FemmeFatale();
+ ~FemmeFatale() __attribute__((noreturn));
+};
+
+void exitNow() __attribute__((noreturn));
+void exitDestruct(const MyString& ms) __attribute__((noreturn));
+
+Mutex fatalmu_;
+
+void test1() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ exitNow();
+}
+
+void test2() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ FemmeFatale femme;
+}
+
+bool c;
+
+void test3() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ if (c) {
+ exitNow();
+ }
+ else {
+ FemmeFatale femme;
+ }
+}
+
+void test4() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ exitDestruct("foo");
+}
+
+} // end namespace UnreachableExitTest
+
+
+namespace VirtualMethodCanonicalizationTest {
+
+class Base {
+public:
+ virtual Mutex* getMutex() = 0;
+};
+
+class Base2 : public Base {
+public:
+ Mutex* getMutex();
+};
+
+class Base3 : public Base2 {
+public:
+ Mutex* getMutex();
+};
+
+class Derived : public Base3 {
+public:
+ Mutex* getMutex(); // overrides Base::getMutex()
+};
+
+void baseFun(Base *b) EXCLUSIVE_LOCKS_REQUIRED(b->getMutex()) { }
+
+void derivedFun(Derived *d) EXCLUSIVE_LOCKS_REQUIRED(d->getMutex()) {
+ baseFun(d);
+}
+
+} // end namespace VirtualMethodCanonicalizationTest
+
+
+namespace TemplateFunctionParamRemapTest {
+
+template <class T>
+struct Cell {
+ T dummy_;
+ Mutex* mu_;
+};
+
+class Foo {
+public:
+ template <class T>
+ void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+ void test();
+};
+
+template<class T>
+void Foo::elr(Cell<T>* c1) { }
+
+void Foo::test() {
+ Cell<int> cell;
+ elr(&cell); // \
+ // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+void globalELR(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+template<class T>
+void globalELR(Cell<T>* c1) { }
+
+void globalTest() {
+ Cell<int> cell;
+ globalELR(&cell); // \
+ // expected-warning {{calling function 'globalELR' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+void globalELR2(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+// second declaration
+template<class T>
+void globalELR2(Cell<T>* c2);
+
+template<class T>
+void globalELR2(Cell<T>* c3) { }
+
+// re-declaration after definition
+template<class T>
+void globalELR2(Cell<T>* c4);
+
+void globalTest2() {
+ Cell<int> cell;
+ globalELR2(&cell); // \
+ // expected-warning {{calling function 'globalELR2' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+class FooT {
+public:
+ void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+};
+
+template<class T>
+void FooT<T>::elr(Cell<T>* c1) { }
+
+void testFooT() {
+ Cell<int> cell;
+ FooT<int> foo;
+ foo.elr(&cell); // \
+ // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}}
+}
+
+} // end namespace TemplateFunctionParamRemapTest
+
+
+namespace SelfConstructorTest {
+
+class SelfLock {
+public:
+ SelfLock() EXCLUSIVE_LOCK_FUNCTION(mu_);
+ ~SelfLock() UNLOCK_FUNCTION(mu_);
+
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+ Mutex mu_;
+};
+
+class LOCKABLE SelfLock2 {
+public:
+ SelfLock2() EXCLUSIVE_LOCK_FUNCTION();
+ ~SelfLock2() UNLOCK_FUNCTION();
+
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(this);
+};
+
+
+void test() {
+ SelfLock s;
+ s.foo();
+}
+
+void test2() {
+ SelfLock2 s2;
+ s2.foo();
+}
+
+} // end namespace SelfConstructorTest
+
+
+namespace MultipleAttributeTest {
+
+class Foo {
+ Mutex mu1_;
+ Mutex mu2_;
+ int a GUARDED_BY(mu1_);
+ int b GUARDED_BY(mu2_);
+ int c GUARDED_BY(mu1_) GUARDED_BY(mu2_);
+ int* d PT_GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
+
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu1_)
+ EXCLUSIVE_LOCKS_REQUIRED(mu2_);
+ void foo2() SHARED_LOCKS_REQUIRED(mu1_)
+ SHARED_LOCKS_REQUIRED(mu2_);
+ void foo3() LOCKS_EXCLUDED(mu1_)
+ LOCKS_EXCLUDED(mu2_);
+ void lock() EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_);
+ void readerlock() EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_);
+ void unlock() UNLOCK_FUNCTION(mu1_)
+ UNLOCK_FUNCTION(mu2_);
+ bool trylock() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu1_)
+ EXCLUSIVE_TRYLOCK_FUNCTION(true, mu2_);
+ bool readertrylock() SHARED_TRYLOCK_FUNCTION(true, mu1_)
+ SHARED_TRYLOCK_FUNCTION(true, mu2_);
+
+ void test();
+};
+
+
+void Foo::foo1() {
+ a = 1;
+ b = 2;
+}
+
+void Foo::foo2() {
+ int result = a + b;
+}
+
+void Foo::foo3() { }
+void Foo::lock() { }
+void Foo::readerlock() { }
+void Foo::unlock() { }
+bool Foo::trylock() { return true; }
+bool Foo::readertrylock() { return true; }
+
+
+void Foo::test() {
+ mu1_.Lock();
+ foo1(); // expected-warning {{}}
+ c = 0; // expected-warning {{}}
+ *d = 0; // expected-warning {{}}
+ mu1_.Unlock();
+
+ mu1_.ReaderLock();
+ foo2(); // expected-warning {{}}
+ int x = c; // expected-warning {{}}
+ int y = *d; // expected-warning {{}}
+ mu1_.Unlock();
+
+ mu2_.Lock();
+ foo3(); // expected-warning {{}}
+ mu2_.Unlock();
+
+ lock();
+ a = 0;
+ b = 0;
+ unlock();
+
+ readerlock();
+ int z = a + b;
+ unlock();
+
+ if (trylock()) {
+ a = 0;
+ b = 0;
+ unlock();
+ }
+
+ if (readertrylock()) {
+ int zz = a + b;
+ unlock();
+ }
+}
+
+
+} // end namespace MultipleAttributeTest
+
+
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index 8aa6a91a9d2d..df9415cf8601 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1255,7 +1255,7 @@ public:
void foo4(FooLate *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu);
static void foo5() EXCLUSIVE_LOCKS_REQUIRED(mu); // \
- // expected-error {{'this' cannot be implicitly used in a static member function declaration}}
+ // expected-error {{invalid use of member 'mu' in static member function}}
template <class T>
void foo6() EXCLUSIVE_LOCKS_REQUIRED(T::statmu) { }
@@ -1440,3 +1440,50 @@ void Foo::bar(Mutex* mu) LOCKS_EXCLUDED(mu) { } // \
} // end namespace InvalidDeclTest
+
+namespace StaticScopeTest {
+
+class FooStream;
+
+class Foo {
+ mutable Mutex mu;
+ int a GUARDED_BY(mu);
+
+ static int si GUARDED_BY(mu); // \
+ // expected-error {{invalid use of non-static data member 'mu'}}
+
+ static void foo() EXCLUSIVE_LOCKS_REQUIRED(mu); // \
+ // expected-error {{invalid use of member 'mu' in static member function}}
+
+ friend FooStream& operator<<(FooStream& s, const Foo& f)
+ EXCLUSIVE_LOCKS_REQUIRED(mu); // \
+ // expected-error {{invalid use of non-static data member 'mu'}}
+};
+
+
+} // end namespace StaticScopeTest
+
+
+namespace FunctionAttributesInsideClass_ICE_Test {
+
+class Foo {
+public:
+ /* Originally found when parsing foo() as an ordinary method after the
+ * the following:
+
+ template <class T>
+ void syntaxErrorMethod(int i) {
+ if (i) {
+ foo(
+ }
+ }
+ */
+
+ void method() {
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(mu); // \
+ // expected-error {{use of undeclared identifier 'mu'}}
+ }
+};
+
+} // end namespace FunctionAttributesInsideClass_ICE_Test
+
diff --git a/test/SemaCXX/warn-unique-enum.cpp b/test/SemaCXX/warn-unique-enum.cpp
deleted file mode 100644
index 59a127807172..000000000000
--- a/test/SemaCXX/warn-unique-enum.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -Wunique-enum
-enum A { A1 = 1, A2 = 1, A3 = 1 }; // expected-warning {{all elements of 'A' are initialized with literals to value 1}} \
-// expected-note {{initialize the last element with the previous element to silence this warning}}
-enum { B1 = 1, B2 = 1, B3 = 1 }; // no warning
-enum C { // expected-warning {{all elements of 'C' are initialized with literals to value 1}}
- C1 = true,
- C2 = true // expected-note {{initialize the last element with the previous element to silence this warning}}
-};
-enum D { D1 = 5, D2 = 5L, D3 = 5UL, D4 = 5LL, D5 = 5ULL }; // expected-warning {{all elements of 'D' are initialized with literals to value 5}} \
-// expected-note {{initialize the last element with the previous element to silence this warning}}
-
-// Don't warn on enums with less than 2 elements.
-enum E { E1 = 4 };
-enum F { F1 };
-enum G {};
-
-// Don't warn when integer literals do not initialize the elements.
-enum H { H1 = 4, H_MAX = H1, H_MIN = H1 };
-enum I { I1 = H1, I2 = 4 };
-enum J { J1 = 4, J2 = I2 };
-enum K { K1, K2, K3, K4 };
-
-// Don't crash or warn on this one.
-// rdar://11875995
-enum L {
- L1 = 0x8000000000000000ULL, L2 = 0x0000000000000001ULL
-};
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index dbff4b0e68c1..ad896b521204 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++11 %s
static void f1(); // expected-warning{{unused}}
@@ -87,3 +88,16 @@ namespace rdar8733476 {
foo();
}
}
+
+namespace test5 {
+ static int n = 0;
+ static int &r = n;
+ int f(int &);
+ int k = f(r);
+
+ // FIXME: We should produce warnings for both of these.
+ static const int m = n;
+ int x = sizeof(m);
+ static const double d = 0.0;
+ int y = sizeof(d);
+}
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 582701957e59..4e8d51d319e9 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -42,10 +42,11 @@ void test_dependent_init(T *p) {
}
namespace PR6948 {
- template<typename T> class X;
+ template<typename T> class X; // expected-note{{template is declared here}}
void f() {
- X<char> str (read_from_file()); // expected-error{{use of undeclared identifier 'read_from_file'}}
+ X<char> str (read_from_file()); // expected-error{{use of undeclared identifier 'read_from_file'}} \
+ expected-error{{implicit instantiation of undefined template 'PR6948::X<char>'}}
}
}
@@ -122,3 +123,15 @@ namespace PR11550 {
S3 z = a; // expected-warning {{unused variable 'z'}}
}
}
+
+namespace ctor_with_cleanups {
+ struct S1 {
+ ~S1();
+ };
+ struct S2 {
+ S2(const S1&);
+ };
+ void func() {
+ S2 s((S1()));
+ }
+}
diff --git a/test/SemaCXX/warn-using-namespace-in-header.cpp b/test/SemaCXX/warn-using-namespace-in-header.cpp
index 72c25529b40f..f68b99893aae 100644
--- a/test/SemaCXX/warn-using-namespace-in-header.cpp
+++ b/test/SemaCXX/warn-using-namespace-in-header.cpp
@@ -1,54 +1,60 @@
// RUN: %clang_cc1 -fsyntax-only -Wheader-hygiene -verify %s
-#include "warn-using-namespace-in-header.h"
+#ifdef BE_THE_HEADER
+namespace warn_in_header_in_global_context {}
+using namespace warn_in_header_in_global_context; // expected-warning {{using namespace directive in global context in header}}
+
+// While we want to error on the previous using directive, we don't when we are
+// inside a namespace
+namespace dont_warn_here {
+using namespace warn_in_header_in_global_context;
+}
+
+// We should warn in toplevel extern contexts.
+namespace warn_inside_linkage {}
+extern "C++" {
+using namespace warn_inside_linkage; // expected-warning {{using namespace directive in global context in header}}
+}
+
+// This is really silly, but we should warn on it:
+extern "C++" {
+extern "C" {
+extern "C++" {
+using namespace warn_inside_linkage; // expected-warning {{using namespace directive in global context in header}}
+}
+}
+}
+
+// But we shouldn't warn in extern contexts inside namespaces.
+namespace dont_warn_here {
+extern "C++" {
+using namespace warn_in_header_in_global_context;
+}
+}
+
+// We also shouldn't warn in case of functions.
+inline void foo() {
+ using namespace warn_in_header_in_global_context;
+}
+
+
+namespace macronamespace {}
+#define USING_MACRO using namespace macronamespace;
+
+// |using namespace| through a macro should warn if the instantiation is in a
+// header.
+USING_MACRO // expected-warning {{using namespace directive in global context in header}}
+
+#else
+
+#define BE_THE_HEADER
+#include __FILE__
namespace dont_warn {}
using namespace dont_warn;
-// Warning is actually in the header but only the cpp file gets scanned.
-// expected-warning {{using namespace directive in global context in header}}
-
-
-
-
-
-
-
-
-
-// Warn inside linkage specs too.
-// expected-warning {{using namespace directive in global context in header}}
-
-
-
-
-
-
-// expected-warning {{using namespace directive in global context in header}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// expected-warning {{using namespace directive in global context in header}}
-
// |using namespace| through a macro shouldn't warn if the instantiation is in a
// cc file.
USING_MACRO
+
+#endif
diff --git a/test/SemaCXX/warn-using-namespace-in-header.h b/test/SemaCXX/warn-using-namespace-in-header.h
deleted file mode 100644
index b544c548ae9b..000000000000
--- a/test/SemaCXX/warn-using-namespace-in-header.h
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-// Lots of vertical space to make the error line match up with the line of the
-// expected line in the source file.
-namespace warn_in_header_in_global_context {}
-using namespace warn_in_header_in_global_context;
-
-// While we want to error on the previous using directive, we don't when we are
-// inside a namespace
-namespace dont_warn_here {
-using namespace warn_in_header_in_global_context;
-}
-
-// We should warn in toplevel extern contexts.
-namespace warn_inside_linkage {}
-extern "C++" {
-using namespace warn_inside_linkage;
-}
-
-// This is really silly, but we should warn on it:
-extern "C++" {
-extern "C" {
-extern "C++" {
-using namespace warn_inside_linkage;
-}
-}
-}
-
-// But we shouldn't warn in extern contexts inside namespaces.
-namespace dont_warn_here {
-extern "C++" {
-using namespace warn_in_header_in_global_context;
-}
-}
-
-// We also shouldn't warn in case of functions.
-inline void foo() {
- using namespace warn_in_header_in_global_context;
-}
-
-
-namespace macronamespace {}
-#define USING_MACRO using namespace macronamespace;
-
-// |using namespace| through a macro should warn if the instantiation is in a
-// header.
-USING_MACRO
diff --git a/test/SemaCXX/zero-length-arrays.cpp b/test/SemaCXX/zero-length-arrays.cpp
index 05ded4ad9b3c..d86ab8666d53 100644
--- a/test/SemaCXX/zero-length-arrays.cpp
+++ b/test/SemaCXX/zero-length-arrays.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/10228639>
class Foo {
diff --git a/test/SemaObjC/ClassPropertyNotObject.m b/test/SemaObjC/ClassPropertyNotObject.m
index 02ed40ae338b..67d76b85e7ab 100644
--- a/test/SemaObjC/ClassPropertyNotObject.m
+++ b/test/SemaObjC/ClassPropertyNotObject.m
@@ -1,5 +1,6 @@
// 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
+// expected-no-diagnostics
// rdar://10565506
@protocol P @end
diff --git a/test/SemaObjC/ContClassPropertyLookup.m b/test/SemaObjC/ContClassPropertyLookup.m
index 06a0ffae588c..bf4f6430bae0 100644
--- a/test/SemaObjC/ContClassPropertyLookup.m
+++ b/test/SemaObjC/ContClassPropertyLookup.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface MyObject {
int _foo;
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
index 8d5cca26a74c..a53b52acd862 100644
--- a/test/SemaObjC/arc-decls.m
+++ b/test/SemaObjC/arc-decls.m
@@ -85,6 +85,8 @@ void func()
- (id)ns_non __attribute((ns_returns_not_retained)); // expected-error {{overriding method has mismatched ns_returns_not_retained attributes}}
- (id)not_ret:(id) b __attribute((ns_returns_retained)); // expected-error {{overriding method has mismatched ns_returns_retained attributes}}
- (id)both__returns_not_retained:(id) b __attribute((ns_returns_not_retained));
+// rdar://12173491
+@property (copy, nonatomic) __attribute__((ns_returns_retained)) id (^fblock)(void);
@end
// Test that we give a good diagnostic here that mentions the missing
diff --git a/test/SemaObjC/arc-objc-lifetime.m b/test/SemaObjC/arc-objc-lifetime.m
index 03260e8cdd4a..08d2dbe16c87 100644
--- a/test/SemaObjC/arc-objc-lifetime.m
+++ b/test/SemaObjC/arc-objc-lifetime.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
// rdar://10244607
typedef const struct __CFString * CFStringRef;
@@ -40,3 +40,30 @@ __strong I *(__strong (test3)); // expected-error {{the type 'I *__strong' is al
__unsafe_unretained __typeof__(test3) test4;
typedef __strong I *strong_I;
__unsafe_unretained strong_I test5;
+
+// rdar://10907090
+typedef void (^T) ();
+@interface NSObject @end
+@protocol P;
+@interface Radar10907090 @end
+
+@implementation Radar10907090
+- (void) MMM : (NSObject*) arg0 : (NSObject<P>**)arg : (id) arg1 : (id<P>*) arg2 {} // expected-warning {{method parameter of type 'NSObject<P> *__autoreleasing *' with no explicit ownership}} \
+ // expected-warning {{method parameter of type '__autoreleasing id<P> *' with no explicit ownership}}
+- (void) MM : (NSObject*) arg0 : (__strong NSObject**)arg : (id) arg1 : (__strong id*) arg2 {}
+- (void) M : (NSObject**)arg0 : (id*)arg {} // expected-warning {{method parameter of type 'NSObject *__autoreleasing *' with no explicit ownership}} \
+ // expected-warning {{method parameter of type '__autoreleasing id *' with no explicit ownership}}
+- (void) N : (__strong NSObject***) arg0 : (__strong NSObject<P>***)arg : (float**) arg1 : (double) arg2 {}
+- (void) BLOCK : (T*) arg0 : (T)arg : (__strong T*) arg1 {} // expected-warning {{method parameter of type '__autoreleasing T *' (aka 'void (^__autoreleasing *)()') with no explicit ownership}}
+@end
+
+// rdar://12280826
+@class NSMutableDictionary, NSError;
+@interface Radar12280826
+- (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError**)error;
+@end
+
+@implementation Radar12280826
+- (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError**)error {}
+@end
+
diff --git a/test/SemaObjC/arc-property-decl-attrs.m b/test/SemaObjC/arc-property-decl-attrs.m
index 1386241dd73c..283772c2279c 100644
--- a/test/SemaObjC/arc-property-decl-attrs.m
+++ b/test/SemaObjC/arc-property-decl-attrs.m
@@ -5,7 +5,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(strong) id x;
@property(strong) id y;
@@ -16,7 +16,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(retain) id x;
@property(retain) id y;
@@ -27,7 +27,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(copy) id x;
@property(copy) id y;
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
index bd393e0bf51f..19570815f611 100644
--- a/test/SemaObjC/arc-property-lifetime.m
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -5,7 +5,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(strong) id x; // expected-note {{property declared here}}
@property(strong) id y; // expected-note {{property declared here}}
@@ -13,8 +13,8 @@
@end
@implementation Foo
-@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
-@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
@synthesize z; // suppressed
@end
@@ -22,7 +22,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(retain) id x; // expected-note {{property declared here}}
@property(retain) id y; // expected-note {{property declared here}}
@@ -30,8 +30,8 @@
@end
@implementation Bar
-@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
-@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
@synthesize z; // suppressed
@end
@@ -39,7 +39,7 @@
@public
id __unsafe_unretained x;
id __weak y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(copy) id x; // expected-note {{property declared here}}
@property(copy) id y; // expected-note {{property declared here}}
@@ -47,8 +47,8 @@
@end
@implementation Bas
-@synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
-@synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+@synthesize x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
@synthesize z; // suppressed
@end
@@ -79,7 +79,7 @@
@implementation Gorf
@synthesize x;
-@synthesize y; // expected-error {{existing ivar 'y' for property 'y' with assign attribute must be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing instance variable 'y' for property 'y' with assign attribute must be __unsafe_unretained}}
@synthesize z;
@end
@@ -94,7 +94,7 @@
@implementation Gorf2
@synthesize x;
-@synthesize y; // expected-error {{existing ivar 'y' for property 'y' with unsafe_unretained attribute must be __unsafe_unretained}}
+@synthesize y; // expected-error {{existing instance variable 'y' for property 'y' with unsafe_unretained attribute must be __unsafe_unretained}}
@synthesize z;
@end
diff --git a/test/SemaObjC/arc-property.m b/test/SemaObjC/arc-property.m
index 41d8e8723961..2925459620eb 100644
--- a/test/SemaObjC/arc-property.m
+++ b/test/SemaObjC/arc-property.m
@@ -18,13 +18,13 @@
@end
@implementation MyClass
-@synthesize myString; // expected-error {{existing ivar 'myString' for strong property 'myString' may not be __weak}}
+@synthesize myString; // expected-error {{existing instance variable 'myString' for strong property 'myString' may not be __weak}}
@synthesize myString1 = StrongIvar; // OK
-@synthesize myString2 = myString2; // expected-error {{existing ivar 'myString2' for strong property 'myString2' may not be __weak}}
+@synthesize myString2 = myString2; // expected-error {{existing instance variable 'myString2' for strong property 'myString2' may not be __weak}}
//
@synthesize myString3; // OK
@synthesize myString4; // OK
-@synthesize myString5 = StrongIvar5; // expected-error {{existing ivar 'StrongIvar5' for __weak property 'myString5' must be __weak}}
+@synthesize myString5 = StrongIvar5; // expected-error {{existing instance variable 'StrongIvar5' for __weak property 'myString5' must be __weak}}
@end
@@ -33,7 +33,7 @@
@public
id __unsafe_unretained x; // should be __weak
id __strong y;
- id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing ownership}}
+ id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(weak) id x; // expected-note {{property declared here}}
@property(weak) id y; // expected-note {{property declared here}}
@@ -41,8 +41,8 @@
@end
@implementation Foo
-@synthesize x; // expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
-@synthesize y; // expected-error {{existing ivar 'y' for __weak property 'y' must be __weak}}
+@synthesize x; // expected-error {{existing instance variable 'x' for __weak property 'x' must be __weak}}
+@synthesize y; // expected-error {{existing instance variable 'y' for __weak property 'y' must be __weak}}
@synthesize z; // suppressed
@end
diff --git a/test/SemaObjC/arc-readonly-property-ivar-1.m b/test/SemaObjC/arc-readonly-property-ivar-1.m
index c773f26cc113..418f90d38a8b 100644
--- a/test/SemaObjC/arc-readonly-property-ivar-1.m
+++ b/test/SemaObjC/arc-readonly-property-ivar-1.m
@@ -1,5 +1,6 @@
// 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
+// expected-no-diagnostics
// rdar:// 10558871
@interface PP
diff --git a/test/SemaObjC/arc-readonly-property-ivar.m b/test/SemaObjC/arc-readonly-property-ivar.m
index 635b9fec71d1..bcc1f4b45b23 100644
--- a/test/SemaObjC/arc-readonly-property-ivar.m
+++ b/test/SemaObjC/arc-readonly-property-ivar.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar:// 10558871
@interface PP
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
new file mode 100644
index 000000000000..e652bee82d53
--- /dev/null
+++ b/test/SemaObjC/arc-repeated-weak.mm
@@ -0,0 +1,386 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
+
+@interface Test {
+@public
+ Test *ivar;
+ __weak id weakIvar;
+}
+@property(weak) Test *weakProp;
+@property(strong) Test *strongProp;
+
+- (__weak id)implicitProp;
+
++ (__weak id)weakProp;
+@end
+
+extern void use(id);
+extern id get();
+extern bool condition();
+#define nil ((id)0)
+
+void sanity(Test *a) {
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
+ use(a.weakProp); // expected-note{{also accessed here}}
+
+ use(a.strongProp);
+ use(a.strongProp); // no-warning
+
+ use(a.weakProp); // expected-note{{also accessed here}}
+}
+
+void singleUse(Test *a) {
+ use(a.weakProp); // no-warning
+ use(a.strongProp); // no-warning
+}
+
+void assignsOnly(Test *a) {
+ a.weakProp = get(); // no-warning
+
+ id next = get();
+ if (next)
+ a.weakProp = next; // no-warning
+
+ a->weakIvar = get(); // no-warning
+ next = get();
+ if (next)
+ a->weakIvar = next; // no-warning
+
+ extern __weak id x;
+ x = get(); // no-warning
+ next = get();
+ if (next)
+ x = next; // no-warning
+}
+
+void assignThenRead(Test *a) {
+ a.weakProp = get(); // expected-note{{also accessed here}}
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+}
+
+void twoVariables(Test *a, Test *b) {
+ use(a.weakProp); // no-warning
+ use(b.weakProp); // no-warning
+}
+
+void doubleLevelAccess(Test *a) {
+ use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times in this function and may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
+ use(a.strongProp.weakProp); // expected-note{{also accessed here}}
+}
+
+void doubleLevelAccessIvar(Test *a) {
+ use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
+ use(a.strongProp.weakProp); // expected-note{{also accessed here}}
+}
+
+void implicitProperties(Test *a) {
+ use(a.implicitProp); // expected-warning{{weak implicit property 'implicitProp' is accessed multiple times}}
+ use(a.implicitProp); // expected-note{{also accessed here}}
+}
+
+void classProperties() {
+ use(Test.weakProp); // expected-warning{{weak implicit property 'weakProp' is accessed multiple times}}
+ use(Test.weakProp); // expected-note{{also accessed here}}
+}
+
+void classPropertiesAreDifferent(Test *a) {
+ use(Test.weakProp); // no-warning
+ use(a.weakProp); // no-warning
+ use(a.strongProp.weakProp); // no-warning
+}
+
+void ivars(Test *a) {
+ use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
+ use(a->weakIvar); // expected-note{{also accessed here}}
+}
+
+void globals() {
+ extern __weak id a;
+ use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
+ use(a); // expected-note{{also accessed here}}
+}
+
+void messageGetter(Test *a) {
+ use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ use([a weakProp]); // expected-note{{also accessed here}}
+}
+
+void messageSetter(Test *a) {
+ [a setWeakProp:get()]; // no-warning
+ [a setWeakProp:get()]; // no-warning
+}
+
+void messageSetterAndGetter(Test *a) {
+ [a setWeakProp:get()]; // expected-note{{also accessed here}}
+ use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+}
+
+void mixDotAndMessageSend(Test *a, Test *b) {
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ use([a weakProp]); // expected-note{{also accessed here}}
+
+ use([b weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ use(b.weakProp); // expected-note{{also accessed here}}
+}
+
+
+void assignToStrongWrongInit(Test *a) {
+ id val = a.weakProp; // expected-note{{also accessed here}}
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+}
+
+void assignToStrongWrong(Test *a) {
+ id val;
+ val = a.weakProp; // expected-note{{also accessed here}}
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+}
+
+void assignToIvarWrong(Test *a) {
+ a->weakIvar = get(); // expected-note{{also accessed here}}
+ use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
+}
+
+void assignToGlobalWrong() {
+ extern __weak id a;
+ a = get(); // expected-note{{also accessed here}}
+ use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
+}
+
+void assignToStrongOK(Test *a) {
+ if (condition()) {
+ id val = a.weakProp; // no-warning
+ (void)val;
+ } else {
+ id val;
+ val = a.weakProp; // no-warning
+ (void)val;
+ }
+}
+
+void assignToStrongConditional(Test *a) {
+ id val = (condition() ? a.weakProp : a.weakProp); // no-warning
+ id val2 = a.implicitProp ?: a.implicitProp; // no-warning
+}
+
+void testBlock(Test *a) {
+ use(a.weakProp); // no-warning
+
+ use(^{
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this block}}
+ use(a.weakProp); // expected-note{{also accessed here}}
+ });
+}
+
+void assignToStrongWithCasts(Test *a) {
+ if (condition()) {
+ Test *val = (Test *)a.weakProp; // no-warning
+ (void)val;
+ } else {
+ id val;
+ val = (Test *)a.weakProp; // no-warning
+ (void)val;
+ }
+}
+
+void assignToStrongWithMessages(Test *a) {
+ if (condition()) {
+ id val = [a weakProp]; // no-warning
+ (void)val;
+ } else {
+ id val;
+ val = [a weakProp]; // no-warning
+ (void)val;
+ }
+}
+
+
+void assignAfterRead(Test *a) {
+ // Special exception for a single read before any writes.
+ if (!a.weakProp) // no-warning
+ a.weakProp = get(); // no-warning
+}
+
+void readOnceWriteMany(Test *a) {
+ if (!a.weakProp) { // no-warning
+ a.weakProp = get(); // no-warning
+ a.weakProp = get(); // no-warning
+ }
+}
+
+void readOnceAfterWrite(Test *a) {
+ a.weakProp = get(); // expected-note{{also accessed here}}
+ if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ a.weakProp = get(); // expected-note{{also accessed here}}
+ }
+}
+
+void readOnceWriteManyLoops(Test *a, Test *b, Test *c, Test *d, Test *e) {
+ while (condition()) {
+ if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ a.weakProp = get(); // expected-note{{also accessed here}}
+ a.weakProp = get(); // expected-note{{also accessed here}}
+ }
+ }
+
+ do {
+ if (!b.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ b.weakProp = get(); // expected-note{{also accessed here}}
+ b.weakProp = get(); // expected-note{{also accessed here}}
+ }
+ } while (condition());
+
+ for (id x = get(); x; x = get()) {
+ if (!c.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ c.weakProp = get(); // expected-note{{also accessed here}}
+ c.weakProp = get(); // expected-note{{also accessed here}}
+ }
+ }
+
+ for (id x in get()) {
+ if (!d.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ d.weakProp = get(); // expected-note{{also accessed here}}
+ d.weakProp = get(); // expected-note{{also accessed here}}
+ }
+ }
+
+ int array[] = { 1, 2, 3 };
+ for (int i : array) {
+ if (!e.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ e.weakProp = get(); // expected-note{{also accessed here}}
+ e.weakProp = get(); // expected-note{{also accessed here}}
+ }
+ }
+}
+
+void readOnlyLoop(Test *a) {
+ while (condition()) {
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ }
+}
+
+void readInIterationLoop() {
+ for (Test *a in get())
+ use(a.weakProp); // no-warning
+}
+
+void readDoubleLevelAccessInLoop() {
+ for (Test *a in get()) {
+ use(a.strongProp.weakProp); // no-warning
+ }
+}
+
+void readParameterInLoop(Test *a) {
+ for (id unused in get()) {
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
+ (void)unused;
+ }
+}
+
+void readGlobalInLoop() {
+ static __weak id a;
+ for (id unused in get()) {
+ use(a); // expected-warning{{weak variable 'a' is accessed multiple times in this function}}
+ (void)unused;
+ }
+}
+
+void doWhileLoop(Test *a) {
+ do {
+ use(a.weakProp); // no-warning
+ } while(0);
+}
+
+
+@interface Test (Methods)
+@end
+
+@implementation Test (Methods)
+- (void)sanity {
+ use(self.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
+ use(self.weakProp); // expected-note{{also accessed here}}
+}
+
+- (void)ivars {
+ use(weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
+ use(weakIvar); // expected-note{{also accessed here}}
+}
+
+- (void)doubleLevelAccessForSelf {
+ use(self.strongProp.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ use(self.strongProp.weakProp); // expected-note{{also accessed here}}
+
+ use(self->ivar.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ use(self->ivar.weakProp); // expected-note{{also accessed here}}
+
+ use(self->ivar->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
+ use(self->ivar->weakIvar); // expected-note{{also accessed here}}
+}
+
+- (void)distinctFromOther:(Test *)other {
+ use(self.strongProp.weakProp); // no-warning
+ use(other.strongProp.weakProp); // no-warning
+
+ use(self->ivar.weakProp); // no-warning
+ use(other->ivar.weakProp); // no-warning
+
+ use(self.strongProp->weakIvar); // no-warning
+ use(other.strongProp->weakIvar); // no-warning
+}
+@end
+
+
+class Wrapper {
+ Test *a;
+
+public:
+ void fields() {
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
+ use(a.weakProp); // expected-note{{also accessed here}}
+ }
+
+ void distinctFromOther(Test *b, const Wrapper &w) {
+ use(a.weakProp); // no-warning
+ use(b.weakProp); // no-warning
+ use(w.a.weakProp); // no-warning
+ }
+
+ static void doubleLevelAccessField(const Wrapper &x, const Wrapper &y) {
+ use(x.a.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
+ use(y.a.weakProp); // expected-note{{also accessed here}}
+ }
+};
+
+
+// -----------------------
+// False positives
+// -----------------------
+
+// Most of these would require flow-sensitive analysis to silence correctly.
+
+void assignNil(Test *a) {
+ if (condition())
+ a.weakProp = nil; // expected-note{{also accessed here}}
+
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+}
+
+void branch(Test *a) {
+ if (condition())
+ use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
+ else
+ use(a.weakProp); // expected-note{{also accessed here}}
+}
+
+void doubleLevelAccess(Test *a, Test *b) {
+ use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
+ use(b.strongProp.weakProp); // expected-note{{also accessed here}}
+
+ use(a.weakProp.weakProp); // no-warning
+}
+
+void doubleLevelAccessIvar(Test *a, Test *b) {
+ use(a->ivar.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
+ use(b->ivar.weakProp); // expected-note{{also accessed here}}
+
+ use(a.strongProp.weakProp); // no-warning
+}
+
diff --git a/test/SemaObjC/arc-setter-property-match.m b/test/SemaObjC/arc-setter-property-match.m
index 9158b09a47e7..83a07e94f2b9 100644
--- a/test/SemaObjC/arc-setter-property-match.m
+++ b/test/SemaObjC/arc-setter-property-match.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10156674
@class NSArray;
diff --git a/test/SemaObjC/arc-system-header.m b/test/SemaObjC/arc-system-header.m
index 1a7c39d4e1cd..3443bda99bb3 100644
--- a/test/SemaObjC/arc-system-header.m
+++ b/test/SemaObjC/arc-system-header.m
@@ -38,7 +38,7 @@ id test6() {
x = (id) (test6_helper(), kMagicConstant);
}
-// workaround expected-note 4 {{marked unavailable here}}
+// workaround expected-note 4 {{marked unavailable here}} expected-note 2 {{property 'prop' is declared unavailable here}}
void test7(Test7 *p) {
*p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
index 8498de6d9a11..b140c64da71f 100644
--- a/test/SemaObjC/arc-unavailable-for-weakref.m
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -60,5 +60,5 @@ __attribute__((objc_arc_weak_reference_unavailable))
@end
@implementation I
-@synthesize font = _font; // expected-error {{synthesis of a weak-unavailable property is disallowed because it requires synthesis of an ivar of the __weak object}}
+@synthesize font = _font; // expected-error {{synthesis of a weak-unavailable property is disallowed because it requires synthesis of an instance variable of the __weak object}}
@end
diff --git a/test/SemaObjC/arc-unsafe_unretained.m b/test/SemaObjC/arc-unsafe_unretained.m
index a6c5f985df8f..99e870f643a8 100644
--- a/test/SemaObjC/arc-unsafe_unretained.m
+++ b/test/SemaObjC/arc-unsafe_unretained.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks %s
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-arc %s
+// expected-no-diagnostics
struct X {
__unsafe_unretained id object;
diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m
index 7c9ff0f13d90..ed6b7608b9a4 100644
--- a/test/SemaObjC/attr-availability.m
+++ b/test/SemaObjC/attr-availability.m
@@ -14,8 +14,8 @@
@end
void f(A *a, B *b) {
- [a method]; // expected-warning{{'method' is deprecated: first deprecated in Mac OS X 10.2}}
- [b method]; // expected-warning {{'method' is deprecated: first deprecated in Mac OS X 10.2}}
- [a proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in Mac OS X 10.2}}
- [b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in Mac OS X 10.2}}
+ [a method]; // expected-warning{{'method' is deprecated: first deprecated in OS X 10.2}}
+ [b method]; // expected-warning {{'method' is deprecated: first deprecated in OS X 10.2}}
+ [a proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}}
+ [b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}}
}
diff --git a/test/SemaObjC/attr-cleanup.m b/test/SemaObjC/attr-cleanup.m
index 8415c698f348..978498ca64b5 100644
--- a/test/SemaObjC/attr-cleanup.m
+++ b/test/SemaObjC/attr-cleanup.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// expected-no-diagnostics
@class NSString;
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index 260462abc0b8..c0aa9fc07071 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -107,7 +107,8 @@ __attribute ((deprecated))
@interface Test2
-@property int test2 __attribute__((deprecated)); // expected-note 4 {{declared here}}
+@property int test2 __attribute__((deprecated)); // expected-note 4 {{declared here}} \
+ // expected-note 2 {{property 'test2' is declared deprecated here}}
@end
void test(Test2 *foo) {
diff --git a/test/SemaObjC/block-as-object.m b/test/SemaObjC/block-as-object.m
index a85b6067571e..945d6f68d6ea 100644
--- a/test/SemaObjC/block-as-object.m
+++ b/test/SemaObjC/block-as-object.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+// expected-no-diagnostics
@interface Whatever
- copy;
diff --git a/test/SemaObjC/block-ivar.m b/test/SemaObjC/block-ivar.m
index c7ea1d96a05b..5864b6350120 100644
--- a/test/SemaObjC/block-ivar.m
+++ b/test/SemaObjC/block-ivar.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+// expected-no-diagnostics
@interface NSObject {
struct objc_object *isa;
diff --git a/test/SemaObjC/block-return.m b/test/SemaObjC/block-return.m
index 15c3fb64d778..e0bac996d80a 100644
--- a/test/SemaObjC/block-return.m
+++ b/test/SemaObjC/block-return.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -fobjc-gc-only %s
+// expected-no-diagnostics
// rdar://8979379
@interface NSString
diff --git a/test/SemaObjC/builtin_objc_assign_ivar.m b/test/SemaObjC/builtin_objc_assign_ivar.m
index 5839bf444419..6c28178de0ec 100644
--- a/test/SemaObjC/builtin_objc_assign_ivar.m
+++ b/test/SemaObjC/builtin_objc_assign_ivar.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://9362887
typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
diff --git a/test/SemaObjC/builtin_objc_msgSend.m b/test/SemaObjC/builtin_objc_msgSend.m
index bf17225a0417..bfa09d9f6cfc 100644
--- a/test/SemaObjC/builtin_objc_msgSend.m
+++ b/test/SemaObjC/builtin_objc_msgSend.m
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://8632525
extern id objc_msgSend(id self, SEL op, ...);
diff --git a/test/SemaObjC/category-method-lookup-2.m b/test/SemaObjC/category-method-lookup-2.m
index a31d824d1d45..ed347c7cde0c 100644
--- a/test/SemaObjC/category-method-lookup-2.m
+++ b/test/SemaObjC/category-method-lookup-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef struct objc_class *Class;
@interface NSObject
diff --git a/test/SemaObjC/category-method-lookup.m b/test/SemaObjC/category-method-lookup.m
index 4223a747947c..6239e948dce4 100644
--- a/test/SemaObjC/category-method-lookup.m
+++ b/test/SemaObjC/category-method-lookup.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface Foo
@end
diff --git a/test/SemaObjC/class-getter-using-dotsyntax.m b/test/SemaObjC/class-getter-using-dotsyntax.m
index 4ff9428e9637..dd384b510833 100644
--- a/test/SemaObjC/class-getter-using-dotsyntax.m
+++ b/test/SemaObjC/class-getter-using-dotsyntax.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
typedef struct objc_class *Class;
diff --git a/test/SemaObjC/class-property-access.m b/test/SemaObjC/class-property-access.m
index c46d3fb397ce..735b51a3c432 100644
--- a/test/SemaObjC/class-property-access.m
+++ b/test/SemaObjC/class-property-access.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface Test {}
+ (Test*)one;
diff --git a/test/SemaObjC/class-protocol.m b/test/SemaObjC/class-protocol.m
index 91cd1389f1e6..021047e12052 100644
--- a/test/SemaObjC/class-protocol.m
+++ b/test/SemaObjC/class-protocol.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// pr5552
@interface Protocol
diff --git a/test/SemaObjC/comptypes-2.m b/test/SemaObjC/comptypes-2.m
index 74e42c96137d..8e90455de664 100644
--- a/test/SemaObjC/comptypes-2.m
+++ b/test/SemaObjC/comptypes-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#define nil (void *)0;
#define Nil (void *)0;
diff --git a/test/SemaObjC/comptypes-8.m b/test/SemaObjC/comptypes-8.m
index 750b0a6a5a97..e65103068911 100644
--- a/test/SemaObjC/comptypes-8.m
+++ b/test/SemaObjC/comptypes-8.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol MyProtocol
@end
diff --git a/test/SemaObjC/conditional-expr-5.m b/test/SemaObjC/conditional-expr-5.m
index 47aed3e6a579..b1f7e5996947 100644
--- a/test/SemaObjC/conditional-expr-5.m
+++ b/test/SemaObjC/conditional-expr-5.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface PBXBuildSettingsDictionary
{
diff --git a/test/SemaObjC/conditional-expr-6.m b/test/SemaObjC/conditional-expr-6.m
index 098688a8a90a..e944e540b2fc 100644
--- a/test/SemaObjC/conditional-expr-6.m
+++ b/test/SemaObjC/conditional-expr-6.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol MyProtocol @end
diff --git a/test/SemaObjC/conditional-expr-7.m b/test/SemaObjC/conditional-expr-7.m
index 3ddf3d73566a..5b4a8632b27f 100644
--- a/test/SemaObjC/conditional-expr-7.m
+++ b/test/SemaObjC/conditional-expr-7.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// radar 7682116
@interface Super @end
diff --git a/test/SemaObjC/conditional-expr-8.m b/test/SemaObjC/conditional-expr-8.m
index 6799983e3b16..beddd205a907 100644
--- a/test/SemaObjC/conditional-expr-8.m
+++ b/test/SemaObjC/conditional-expr-8.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://9296866
@interface NSResponder
diff --git a/test/SemaObjC/conflict-nonfragile-abi2.m b/test/SemaObjC/conflict-nonfragile-abi2.m
index 819732758d27..d0d6be84a65e 100644
--- a/test/SemaObjC/conflict-nonfragile-abi2.m
+++ b/test/SemaObjC/conflict-nonfragile-abi2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://8225011
int glob;
diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m
index ceb8ee90c9f5..8378c3f9f8bf 100644
--- a/test/SemaObjC/continuation-class-err.m
+++ b/test/SemaObjC/continuation-class-err.m
@@ -5,13 +5,13 @@
id _object;
id _object1;
}
-@property(readonly) id object; // expected-note {{property declared here}}
+@property(readonly) id object;
@property(readwrite, assign) id object1; // expected-note {{property declared here}}
@property (readonly) int indentLevel;
@end
@interface ReadOnly ()
-@property(readwrite, copy) id object; // expected-warning {{property attribute in class extension does not match the primary class}}
+@property(readwrite, copy) id object; // Ok. declaring memory model in class extension - primary has none.
@property(readonly) id object1; // expected-error {{illegal redeclaration of property in class extension 'ReadOnly' (attribute must be 'readwrite', while its primary must be 'readonly')}}
@property (readwrite, assign) int indentLevel; // OK. assign the default in any case.
@end
diff --git a/test/SemaObjC/crash-on-objc-bool-literal.m b/test/SemaObjC/crash-on-objc-bool-literal.m
new file mode 100644
index 000000000000..2c003a534b5a
--- /dev/null
+++ b/test/SemaObjC/crash-on-objc-bool-literal.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// rdar://12456743
+
+typedef signed char BOOL; // expected-note 2 {{candidate found by name lookup is 'BOOL'}}
+
+EXPORT BOOL FUNC(BOOL enabled); // expected-error {{unknown type name 'EXPORT'}} // expected-error {{expected ';' after top level declarator}} \
+ // expected-note 2 {{candidate found by name lookup is 'BOOL'}}
+
+static inline BOOL MFIsPrivateVersion(void) { // expected-error {{reference to 'BOOL' is ambiguous}}
+ return __objc_yes; // expected-error {{reference to 'BOOL' is ambiguous}}
+}
diff --git a/test/SemaObjC/default-synthesize-2.m b/test/SemaObjC/default-synthesize-2.m
index 3756413bd83f..20c045e60e06 100644
--- a/test/SemaObjC/default-synthesize-2.m
+++ b/test/SemaObjC/default-synthesize-2.m
@@ -41,7 +41,7 @@
// Test3
@interface Test3
{
- id uid; // expected-note {{ivar is declared here}}
+ id uid; // expected-note {{instance variable is declared here}}
}
@property (readwrite, assign) id uid; // expected-note {{property declared here}}
@end
@@ -119,7 +119,7 @@ int* _object;
@interface Test8
{
id _y;
- id y; // expected-note {{ivar is declared here}}
+ id y; // expected-note {{instance variable is declared here}}
}
@property(copy) id y; // expected-note {{property declared here}}
@end
diff --git a/test/SemaObjC/delay-parsing-cfunctions.m b/test/SemaObjC/delay-parsing-cfunctions.m
index a6f66fe1bd38..c74b054f74d4 100644
--- a/test/SemaObjC/delay-parsing-cfunctions.m
+++ b/test/SemaObjC/delay-parsing-cfunctions.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Werror -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10387088
@interface MyClass
diff --git a/test/SemaObjC/direct-synthesized-ivar-access.m b/test/SemaObjC/direct-synthesized-ivar-access.m
index dc1491173aae..a276a64913b3 100644
--- a/test/SemaObjC/direct-synthesized-ivar-access.m
+++ b/test/SemaObjC/direct-synthesized-ivar-access.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://8673791
// rdar://9943851
diff --git a/test/SemaObjC/enhanced-proto-2.m b/test/SemaObjC/enhanced-proto-2.m
index 28b03d93e2d2..352f29160e53 100644
--- a/test/SemaObjC/enhanced-proto-2.m
+++ b/test/SemaObjC/enhanced-proto-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@protocol MyProto1
@optional
diff --git a/test/SemaObjC/enum-fixed-type.m b/test/SemaObjC/enum-fixed-type.m
index 95153bedb3db..4fe643faef2f 100644
--- a/test/SemaObjC/enum-fixed-type.m
+++ b/test/SemaObjC/enum-fixed-type.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#if !__has_feature(objc_fixed_enum)
# error Enumerations with a fixed underlying type are not supported
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
index 56802960c6b2..dfac0d4286ea 100644
--- a/test/SemaObjC/error-property-gc-attr.m
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -3,7 +3,7 @@
@interface INTF
{
- id IVAR; // expected-note {{ivar is declared here}}
+ id IVAR; // expected-note {{instance variable is declared here}}
__weak id II;
__weak id WID;
id ID;
@@ -19,10 +19,10 @@
@end
@implementation INTF
-@synthesize pweak=IVAR; // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}}
-@synthesize NOT=II; // expected-error {{existing ivar 'II' for strong property 'NOT' may not be __weak}}
+@synthesize pweak=IVAR; // expected-error {{existing instance variable 'IVAR' for __weak property 'pweak' must be __weak}}
+@synthesize NOT=II; // expected-error {{existing instance variable 'II' for strong property 'NOT' may not be __weak}}
@synthesize WID;
@synthesize ID;
-@synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for strong property 'AWEAK' may not be __weak}}
+@synthesize AWEAK; // expected-error {{existing instance variable 'AWEAK' for strong property 'AWEAK' may not be __weak}}
@synthesize WI;
@end
diff --git a/test/SemaObjC/getter-setter-defined-in-category-of-parent.m b/test/SemaObjC/getter-setter-defined-in-category-of-parent.m
index 71c3237425bd..ff5c17446680 100644
--- a/test/SemaObjC/getter-setter-defined-in-category-of-parent.m
+++ b/test/SemaObjC/getter-setter-defined-in-category-of-parent.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface MyParent {
int X;
diff --git a/test/SemaObjC/iboutletcollection-attr.m b/test/SemaObjC/iboutletcollection-attr.m
index 22c21a764bdc..82cb96fbede7 100644
--- a/test/SemaObjC/iboutletcollection-attr.m
+++ b/test/SemaObjC/iboutletcollection-attr.m
@@ -21,9 +21,9 @@ typedef void *PV;
__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(PV))) void *ivar4; // expected-warning {{ivar with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
+ __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 {{ivar with 'iboutlet' attribute must be an object 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}}
diff --git a/test/SemaObjC/id_builtin.m b/test/SemaObjC/id_builtin.m
index a1431d60abe3..be42e7d7c564 100644
--- a/test/SemaObjC/id_builtin.m
+++ b/test/SemaObjC/id_builtin.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// id is now builtin. There should be no errors.
id obj;
diff --git a/test/SemaObjC/idiomatic-parentheses.m b/test/SemaObjC/idiomatic-parentheses.m
index 417b948b8fab..801db5944f10 100644
--- a/test/SemaObjC/idiomatic-parentheses.m
+++ b/test/SemaObjC/idiomatic-parentheses.m
@@ -4,13 +4,18 @@
// <rdar://problem/7382435>
@interface Object
+{
+ unsigned uid;
+}
- (id) init;
- (id) initWithInt: (int) i;
- (void) iterate: (id) coll;
- (id) nextObject;
+@property unsigned uid;
@end
@implementation Object
+@synthesize uid;
- (id) init {
if (self = [self init]) {
}
@@ -20,6 +25,12 @@
- (id) initWithInt: (int) i {
if (self = [self initWithInt: i]) {
}
+ // rdar://11066598
+ if (self.uid = 100) { // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note {{place parentheses around the assignment to silence this warning}} \
+ // expected-note {{use '==' to turn this assignment into an equality comparison}}
+ // ...
+ }
return self;
}
diff --git a/test/SemaObjC/ignore-qualifier-on-qualified-id.m b/test/SemaObjC/ignore-qualifier-on-qualified-id.m
index 36a2c1ad873d..996664f6a9e0 100644
--- a/test/SemaObjC/ignore-qualifier-on-qualified-id.m
+++ b/test/SemaObjC/ignore-qualifier-on-qualified-id.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://10667659
@protocol NSCopying @end
diff --git a/test/SemaObjC/ignore-weakimport-method.m b/test/SemaObjC/ignore-weakimport-method.m
index d71cebf2c79a..c68c57830a9a 100644
--- a/test/SemaObjC/ignore-weakimport-method.m
+++ b/test/SemaObjC/ignore-weakimport-method.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface foo
+ (void) cx __attribute__((weak_import));
- (void) x __attribute__((weak_import));
diff --git a/test/SemaObjC/interface-layout-2.m b/test/SemaObjC/interface-layout-2.m
index 02b14035a223..17e34d4681bd 100644
--- a/test/SemaObjC/interface-layout-2.m
+++ b/test/SemaObjC/interface-layout-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
@interface A
{
int ivar;
diff --git a/test/SemaObjC/interface-layout.m b/test/SemaObjC/interface-layout.m
index 336605a7812e..9b083b0154e1 100644
--- a/test/SemaObjC/interface-layout.m
+++ b/test/SemaObjC/interface-layout.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5
+// expected-no-diagnostics
typedef struct objc_object {} *id;
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m
index 60fd900285d0..ffd740f7fc44 100644
--- a/test/SemaObjC/interface-scope-2.m
+++ b/test/SemaObjC/interface-scope-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin9 -Wno-objc-root-class %s
+// expected-no-diagnostics
// FIXME: must also compile as Objective-C++
// <rdar://problem/6487662>
diff --git a/test/SemaObjC/interface-scope.m b/test/SemaObjC/interface-scope.m
index 0671dae61e82..9875eca5bf16 100644
--- a/test/SemaObjC/interface-scope.m
+++ b/test/SemaObjC/interface-scope.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface I1 {
@private
diff --git a/test/SemaObjC/ivar-access-package.m b/test/SemaObjC/ivar-access-package.m
index abc3420f1bd2..ff5ff4e68aec 100644
--- a/test/SemaObjC/ivar-access-package.m
+++ b/test/SemaObjC/ivar-access-package.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef unsigned char BOOL;
diff --git a/test/SemaObjC/ivar-in-class-extension-error.m b/test/SemaObjC/ivar-in-class-extension-error.m
index b22b7984cc2d..c90e4780688d 100644
--- a/test/SemaObjC/ivar-in-class-extension-error.m
+++ b/test/SemaObjC/ivar-in-class-extension-error.m
@@ -4,12 +4,12 @@
@interface A @end
@interface A () {
- int _p0; // expected-error {{ivars may not be placed in class extension}}
+ int _p0; // expected-error {{instance variables may not be placed in class extension}}
}
@property int p0;
@end
@interface A(CAT) {
- int _p1; // expected-error {{ivars may not be placed in categories}}
+ int _p1; // expected-error {{instance variables may not be placed in categories}}
}
@end
diff --git a/test/SemaObjC/ivar-in-class-extension.m b/test/SemaObjC/ivar-in-class-extension.m
index cf02d26e7219..dc5cf6abf677 100644
--- a/test/SemaObjC/ivar-in-class-extension.m
+++ b/test/SemaObjC/ivar-in-class-extension.m
@@ -32,7 +32,7 @@ int fn3(SomeClass *obj) {
@interface SomeClass (Category)
{
- int categoryIvar; // expected-error {{ivars may not be placed in categories}}
+ int categoryIvar; // expected-error {{instance variables may not be placed in categories}}
}
@end
diff --git a/test/SemaObjC/ivar-sem-check-2.m b/test/SemaObjC/ivar-sem-check-2.m
index bf884b3d9d27..b1e1f2c2efad 100644
--- a/test/SemaObjC/ivar-sem-check-2.m
+++ b/test/SemaObjC/ivar-sem-check-2.m
@@ -16,8 +16,8 @@
@implementation Sub
@synthesize value; // expected-note {{previous use is here}}
-@synthesize value1=value; // expected-error {{synthesized properties 'value1' and 'value' both claim ivar 'value'}}
-@synthesize prop=value2; // expected-error {{property 'prop' attempting to use ivar 'value2' declared in super class 'Super'}}
+@synthesize value1=value; // expected-error {{synthesized properties 'value1' and 'value' both claim instance variable 'value'}}
+@synthesize prop=value2; // expected-error {{property 'prop' attempting to use instance variable 'value2' declared in super class 'Super'}}
@end
diff --git a/test/SemaObjC/method-attributes.m b/test/SemaObjC/method-attributes.m
index f7252af1f1b7..b402d52a42a1 100644
--- a/test/SemaObjC/method-attributes.m
+++ b/test/SemaObjC/method-attributes.m
@@ -55,3 +55,32 @@
- (IBAction)doSomething2:(id)sender {} // expected-warning {{attributes on method implementation and its declaration must match}}
- (IBAction)doSomething3:(id)sender {}
@end
+
+// rdar://11593375
+@interface NSObject @end
+
+@interface Test : NSObject
+-(id)method __attribute__((deprecated));
+-(id)method1;
+-(id)method2 __attribute__((aligned(16)));
+- (id) method3: (int)arg1 __attribute__((aligned(16))) __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{method 'method3:' declared here}}
+- (id) method4: (int)arg1 __attribute__((aligned(16))) __attribute__((deprecated)) __attribute__((unavailable));
+@end
+
+@implementation Test
+-(id)method __attribute__((aligned(16))) __attribute__((aligned(16))) __attribute__((deprecated)) {
+ return self;
+}
+-(id)method1 __attribute__((aligned(16))) {
+ return self;
+}
+-(id)method2 {
+ return self;
+}
+- (id) method3: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable)) { // expected-warning {{attributes on method implementation and its declaration must match}}
+ return self;
+}
+- (id) method4: (int)arg1 __attribute__((aligned(16))) __attribute__((deprecated)) __attribute__((unavailable)) {
+ return self;
+}
+@end
diff --git a/test/SemaObjC/method-conflict-1.m b/test/SemaObjC/method-conflict-1.m
index ca91ebdef237..654cd0166fb5 100644
--- a/test/SemaObjC/method-conflict-1.m
+++ b/test/SemaObjC/method-conflict-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// This test case tests the default behavior.
diff --git a/test/SemaObjC/method-in-class-extension-impl.m b/test/SemaObjC/method-in-class-extension-impl.m
index c205322dec9d..d74ae8f154fd 100644
--- a/test/SemaObjC/method-in-class-extension-impl.m
+++ b/test/SemaObjC/method-in-class-extension-impl.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://8530080
@protocol ViewDelegate @end
diff --git a/test/SemaObjC/method-lookup-2.m b/test/SemaObjC/method-lookup-2.m
index 53cae8371252..25963048f749 100644
--- a/test/SemaObjC/method-lookup-2.m
+++ b/test/SemaObjC/method-lookup-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
@protocol NSObject
diff --git a/test/SemaObjC/method-lookup-4.m b/test/SemaObjC/method-lookup-4.m
index 700565e78329..807d4dae36b5 100644
--- a/test/SemaObjC/method-lookup-4.m
+++ b/test/SemaObjC/method-lookup-4.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface NSObject {}
diff --git a/test/SemaObjC/method-typecheck-1.m b/test/SemaObjC/method-typecheck-1.m
index ee068d0bfccf..2d4e868cdf82 100644
--- a/test/SemaObjC/method-typecheck-1.m
+++ b/test/SemaObjC/method-typecheck-1.m
@@ -34,3 +34,18 @@
(float) x { return 0; } // expected-warning {{conflicting parameter types in implementation of 'setCat:': 'int' vs 'float'}}
+ (int) cCat: (int) x { return 0; } // expected-warning {{conflicting return type in implementation of 'cCat:': 'void' vs 'int'}}
@end
+
+// rdar://12519216
+// test that when implementation implements method in a category, types match.
+@interface testObject {}
+@end
+
+@interface testObject(Category)
+- (float)returnCGFloat; // expected-note {{previous definition is here}}
+@end
+
+@implementation testObject
+- (double)returnCGFloat { // expected-warning {{conflicting return type in implementation of 'returnCGFloat': 'float' vs 'double'}}
+ return 0.0;
+}
+@end
diff --git a/test/SemaObjC/nested-typedef-decl.m b/test/SemaObjC/nested-typedef-decl.m
index bb01eadba94b..7051ac689cc0 100644
--- a/test/SemaObjC/nested-typedef-decl.m
+++ b/test/SemaObjC/nested-typedef-decl.m
@@ -1,5 +1,6 @@
// 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
+// expected-no-diagnostics
// rdar://10041908
@interface Bar {
diff --git a/test/SemaObjC/no-gc-weak-test.m b/test/SemaObjC/no-gc-weak-test.m
index dd9b73cc0de3..6539a9b7f149 100644
--- a/test/SemaObjC/no-gc-weak-test.m
+++ b/test/SemaObjC/no-gc-weak-test.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface Subtask
{
diff --git a/test/SemaObjC/no-ivar-access-control.m b/test/SemaObjC/no-ivar-access-control.m
index 6f00b1a367c7..9bbff24be990 100644
--- a/test/SemaObjC/no-ivar-access-control.m
+++ b/test/SemaObjC/no-ivar-access-control.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -fdebugger-support -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -x objective-c++ -fdebugger-support -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10997647
@interface I
diff --git a/test/SemaObjC/no-ivar-in-interface-block.m b/test/SemaObjC/no-ivar-in-interface-block.m
index 215db6150e53..af4797f1b64e 100644
--- a/test/SemaObjC/no-ivar-in-interface-block.m
+++ b/test/SemaObjC/no-ivar-in-interface-block.m
@@ -3,11 +3,11 @@
@interface I
{
- @protected int P_IVAR; // expected-warning {{declaration of ivars in the interface is deprecated}}
+ @protected int P_IVAR; // expected-warning {{declaration of instance variables in the interface is deprecated}}
- @public int PU_IVAR; // expected-warning {{declaration of ivars in the interface is deprecated}}
+ @public int PU_IVAR; // expected-warning {{declaration of instance variables in the interface is deprecated}}
- @private int PRV_IVAR; // expected-warning {{declaration of ivars in the interface is deprecated}}
+ @private int PRV_IVAR; // expected-warning {{declaration of instance variables in the interface is deprecated}}
}
@end
diff --git a/test/SemaObjC/no-warn-qual-mismatch.m b/test/SemaObjC/no-warn-qual-mismatch.m
index 1e3c18636674..9638da46c18f 100644
--- a/test/SemaObjC/no-warn-qual-mismatch.m
+++ b/test/SemaObjC/no-warn-qual-mismatch.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// radar 7211563
@interface X
diff --git a/test/SemaObjC/no-warn-synth-protocol-meth.m b/test/SemaObjC/no-warn-synth-protocol-meth.m
index 103f6bbd02ed..cdb855e15473 100644
--- a/test/SemaObjC/no-warn-synth-protocol-meth.m
+++ b/test/SemaObjC/no-warn-synth-protocol-meth.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@protocol CYCdef
- (int)name;
diff --git a/test/SemaObjC/no-warn-unimpl-method.m b/test/SemaObjC/no-warn-unimpl-method.m
index dd6e3ad4aa32..174f70a4ee5c 100644
--- a/test/SemaObjC/no-warn-unimpl-method.m
+++ b/test/SemaObjC/no-warn-unimpl-method.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// expected-no-diagnostics
// This program tests that if class implements the forwardInvocation method, then
// every method possible is implemented in the class and should not issue
// warning of the "Method definition not found" kind. */
diff --git a/test/SemaObjC/no-warning-unavail-unimp.m b/test/SemaObjC/no-warning-unavail-unimp.m
index 88d519d115c4..d5a4eac99067 100644
--- a/test/SemaObjC/no-warning-unavail-unimp.m
+++ b/test/SemaObjC/no-warning-unavail-unimp.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://9651605
@interface Foo
diff --git a/test/SemaObjC/nonarc-weak.m b/test/SemaObjC/nonarc-weak.m
new file mode 100644
index 000000000000..ab51875de1cf
--- /dev/null
+++ b/test/SemaObjC/nonarc-weak.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -fobjc-runtime=macosx-10.8.0 -fsyntax-only -Wunused-function %s > %t.nonarc 2>&1
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -fobjc-runtime=macosx-10.8.0 -fsyntax-only -Wunused-function -fobjc-arc %s > %t.arc 2>&1
+// RUN: FileCheck -input-file=%t.nonarc %s
+// RUN: FileCheck -input-file=%t.arc -check-prefix=ARC %s
+
+static void bar() {} // Intentionally unused.
+
+void foo(id self) {
+ __weak id weakSelf = self;
+}
+
+// CHECK: 9:13: warning: __weak attribute cannot be specified on an automatic variable when ARC is not enabled
+// CHECK: 6:13: warning: unused function 'bar'
+// CHECK: 2 warnings generated
+// ARC: 6:13: warning: unused function 'bar'
+// ARC: 1 warning generated
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index a38c0acb84f1..902105b924dd 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -1,6 +1,7 @@
#include "nonnull.h"
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wno-objc-root-class %s
+// REQUIRES: LP64
@class NSObject;
diff --git a/test/SemaObjC/nowarn-superclass-method-mismatch.m b/test/SemaObjC/nowarn-superclass-method-mismatch.m
index b211cdea37b0..d522e899eb0b 100644
--- a/test/SemaObjC/nowarn-superclass-method-mismatch.m
+++ b/test/SemaObjC/nowarn-superclass-method-mismatch.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -Wsuper-class-method-mismatch -verify %s
+// expected-no-diagnostics
// rdar://11793793
@class NSString;
diff --git a/test/SemaObjC/nsobject-attribute-1.m b/test/SemaObjC/nsobject-attribute-1.m
index 72d8fa693a9b..4a75f5ce8efa 100644
--- a/test/SemaObjC/nsobject-attribute-1.m
+++ b/test/SemaObjC/nsobject-attribute-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface NSObject
- (id)self;
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
index e3f28740dc8f..b794eafc9ed7 100644
--- a/test/SemaObjC/nsobject-attribute.m
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -5,8 +5,8 @@ static int count;
static CGColorRef tmp = 0;
typedef struct S1 __attribute__ ((NSObject)) CGColorRef1; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
-typedef void * __attribute__ ((NSObject)) CGColorRef2; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
-
+typedef void * __attribute__ ((NSObject)) CGColorRef2; // no-warning
+typedef void * CFTypeRef;
@interface HandTested {
@public
@@ -14,9 +14,11 @@ typedef void * __attribute__ ((NSObject)) CGColorRef2; // expected-error {{__at
}
@property(copy) CGColorRef x;
-// rdar: // 7809460
-typedef struct CGColor * __attribute__((NSObject)) CGColorRefNoNSObject;
+// rdar://problem/7809460
+typedef struct CGColor * __attribute__((NSObject)) CGColorRefNoNSObject; // no-warning
@property (nonatomic, retain) CGColorRefNoNSObject color;
+// rdar://problem/12197822
+@property (strong) __attribute__((NSObject)) CFTypeRef myObj; // no-warning
@end
void setProperty(id self, id value) {
@@ -29,6 +31,7 @@ id getProperty(id self) {
@implementation HandTested
@synthesize x=x;
+@synthesize myObj;
@dynamic color;
@end
diff --git a/test/SemaObjC/objc-buffered-methods.m b/test/SemaObjC/objc-buffered-methods.m
index a4b83be0cd70..55e489798d77 100644
--- a/test/SemaObjC/objc-buffered-methods.m
+++ b/test/SemaObjC/objc-buffered-methods.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://8843851
int* global;
diff --git a/test/SemaObjC/objc-literal-comparison.m b/test/SemaObjC/objc-literal-comparison.m
index f1aa8ecd91e2..0a1058291e4e 100644
--- a/test/SemaObjC/objc-literal-comparison.m
+++ b/test/SemaObjC/objc-literal-comparison.m
@@ -2,6 +2,10 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare "-Dnil=(id)0" -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare "-Dnil=0" -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare -fobjc-arc "-Dnil=((id)0)" -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare -fobjc-arc "-Dnil=(id)0" -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare -fobjc-arc "-Dnil=0" -verify %s
+
// (test the warning flag as well)
typedef signed char BOOL;
diff --git a/test/SemaObjC/objc-qualified-property-lookup.m b/test/SemaObjC/objc-qualified-property-lookup.m
index 48b28cb05ca5..b5cadbd6037f 100644
--- a/test/SemaObjC/objc-qualified-property-lookup.m
+++ b/test/SemaObjC/objc-qualified-property-lookup.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://9078584
@interface NSObject @end
diff --git a/test/SemaObjC/overriding-property-in-class-extension.m b/test/SemaObjC/overriding-property-in-class-extension.m
new file mode 100644
index 000000000000..77efd556928c
--- /dev/null
+++ b/test/SemaObjC/overriding-property-in-class-extension.m
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Weverything %s
+// expected-no-diagnostics
+// rdar://12103434
+
+@class NSString;
+
+@interface NSObject @end
+
+@interface MyClass : NSObject
+
+@property (nonatomic, copy, readonly) NSString* name;
+
+@end
+
+@interface MyClass () {
+ NSString* _name;
+}
+
+@property (nonatomic, copy) NSString* name;
+
+@end
+
+@implementation MyClass
+
+@synthesize name = _name;
+
+@end
diff --git a/test/SemaObjC/pedantic-dynamic-test.m b/test/SemaObjC/pedantic-dynamic-test.m
index 61f36b333826..1fc5ef66b88a 100644
--- a/test/SemaObjC/pedantic-dynamic-test.m
+++ b/test/SemaObjC/pedantic-dynamic-test.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar: // 7860960
@interface I
diff --git a/test/SemaObjC/pragma-pack.m b/test/SemaObjC/pragma-pack.m
index ba39257fcd50..6869bca90d0a 100644
--- a/test/SemaObjC/pragma-pack.m
+++ b/test/SemaObjC/pragma-pack.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// Make sure pragma pack works inside ObjC methods. <rdar://problem/10893316>
@interface X
diff --git a/test/SemaObjC/property-11.m b/test/SemaObjC/property-11.m
index 297611574eae..e41a840c9224 100644
--- a/test/SemaObjC/property-11.m
+++ b/test/SemaObjC/property-11.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface NSSound
@end
diff --git a/test/SemaObjC/property-13.m b/test/SemaObjC/property-13.m
index 2ca341652686..362d6d3b15d1 100644
--- a/test/SemaObjC/property-13.m
+++ b/test/SemaObjC/property-13.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
+// expected-no-diagnostics
@interface NSObject
+ alloc;
diff --git a/test/SemaObjC/property-2.m b/test/SemaObjC/property-2.m
index f95af5990275..3298ee5766e2 100644
--- a/test/SemaObjC/property-2.m
+++ b/test/SemaObjC/property-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface Tester
@property char PropertyAtomic_char;
diff --git a/test/SemaObjC/property-6.m b/test/SemaObjC/property-6.m
index 933a4f0673f8..f2a293ec5ea4 100644
--- a/test/SemaObjC/property-6.m
+++ b/test/SemaObjC/property-6.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-exceptions %s
+// expected-no-diagnostics
# 1 "<command line>"
# 1 "/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 1 3
typedef signed char BOOL;
diff --git a/test/SemaObjC/property-7.m b/test/SemaObjC/property-7.m
index e6cba50f7a61..3d03b8f680d3 100644
--- a/test/SemaObjC/property-7.m
+++ b/test/SemaObjC/property-7.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
typedef struct _NSZone NSZone;
diff --git a/test/SemaObjC/property-8.m b/test/SemaObjC/property-8.m
index 8647aba8c3e7..da97ffcb7ed0 100644
--- a/test/SemaObjC/property-8.m
+++ b/test/SemaObjC/property-8.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
diff --git a/test/SemaObjC/property-9-impl-method.m b/test/SemaObjC/property-9-impl-method.m
index 84eb3635e2ac..d6220f66fa9a 100644
--- a/test/SemaObjC/property-9-impl-method.m
+++ b/test/SemaObjC/property-9-impl-method.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
// rdar://5967199
typedef signed char BOOL;
diff --git a/test/SemaObjC/property-and-class-extension.m b/test/SemaObjC/property-and-class-extension.m
index 7040078416cd..80cedc372dd2 100644
--- a/test/SemaObjC/property-and-class-extension.m
+++ b/test/SemaObjC/property-and-class-extension.m
@@ -31,6 +31,6 @@ extension but ignore any ivars in superclass class extensions.
@end
@implementation SomeClass
-@synthesize Property; // expected-error {{property 'Property' attempting to use ivar 'Property' declared in super class 'Super'}}
+@synthesize Property; // expected-error {{property 'Property' attempting to use instance variable 'Property' declared in super class 'Super'}}
@synthesize Property1; // OK
@end
diff --git a/test/SemaObjC/property-and-ivar-use.m b/test/SemaObjC/property-and-ivar-use.m
index 5b40d854898e..a9974945b2c0 100644
--- a/test/SemaObjC/property-and-ivar-use.m
+++ b/test/SemaObjC/property-and-ivar-use.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// Do not issue error if 'ivar' used previously belongs to the inherited class
// and has same name as @dynalic property in current class.
diff --git a/test/SemaObjC/property-deprecated-warning.m b/test/SemaObjC/property-deprecated-warning.m
new file mode 100644
index 000000000000..aa7b764fab19
--- /dev/null
+++ b/test/SemaObjC/property-deprecated-warning.m
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s
+// rdar://12324295
+
+typedef signed char BOOL;
+
+@protocol P
+@property(nonatomic,assign) id ptarget __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note 2 {{property 'ptarget' is declared deprecated here}}
+@end
+
+@protocol P1<P>
+- (void)setPtarget:(id)arg; // expected-note {{method 'setPtarget:' declared here}}
+@end
+
+
+@interface UITableViewCell<P1>
+@property(nonatomic,assign) id target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'target' is declared deprecated here}}
+@end
+
+@interface PSTableCell : UITableViewCell
+ - (void)setTarget:(id)target; // expected-note {{method 'setTarget:' declared here}}
+@end
+
+@interface UITableViewCell(UIDeprecated)
+@property(nonatomic,assign) id dep_target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'dep_target' declared here}} \
+ // expected-note 2 {{property 'dep_target' is declared deprecated here}} \
+ // expected-note {{method 'setDep_target:' declared here}}
+@end
+
+@implementation PSTableCell
+- (void)setTarget:(id)target {};
+- (void)setPtarget:(id)val {};
+- (void) Meth {
+ [self setTarget: (id)0]; // expected-warning {{'setTarget:' is deprecated: first deprecated in iOS 3.0}}
+ [self setDep_target: [self dep_target]]; // expected-warning {{'dep_target' is deprecated: first deprecated in iOS 3.0}} \
+ // expected-warning {{'setDep_target:' is deprecated: first deprecated in iOS 3.0}}
+
+ [self setPtarget: (id)0]; // expected-warning {{setPtarget:' is deprecated: first deprecated in iOS 3.0}}
+}
+@end
+
+
+@interface CustomAccessorNames
+@property(getter=isEnabled,assign) BOOL enabled __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'isEnabled' declared here}} expected-note {{property 'enabled' is declared deprecated here}}
+
+@property(setter=setNewDelegate:,assign) id delegate __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{method 'setNewDelegate:' declared here}} expected-note {{property 'delegate' is declared deprecated here}}
+@end
+
+void testCustomAccessorNames(CustomAccessorNames *obj) {
+ if ([obj isEnabled]) // expected-warning {{'isEnabled' is deprecated: first deprecated in iOS 3.0}}
+ [obj setNewDelegate:0]; // expected-warning {{'setNewDelegate:' is deprecated: first deprecated in iOS 3.0}}
+}
+
+
+@interface ProtocolInCategory
+@end
+
+@interface ProtocolInCategory (TheCategory) <P1>
+- (id)ptarget; // expected-note {{method 'ptarget' declared here}}
+@end
+
+id useDeprecatedProperty(ProtocolInCategory *obj) {
+ return [obj ptarget]; // expected-warning {{'ptarget' is deprecated: first deprecated in iOS 3.0}}
+}
diff --git a/test/SemaObjC/property-dot-receiver.m b/test/SemaObjC/property-dot-receiver.m
index c5a928b4e892..4a5f1959dc0e 100644
--- a/test/SemaObjC/property-dot-receiver.m
+++ b/test/SemaObjC/property-dot-receiver.m
@@ -1,5 +1,6 @@
// 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
+// expected-no-diagnostics
// rdar://8962253
@interface Singleton {
diff --git a/test/SemaObjC/property-impl-misuse.m b/test/SemaObjC/property-impl-misuse.m
index 939909e9b279..c49916e10d90 100644
--- a/test/SemaObjC/property-impl-misuse.m
+++ b/test/SemaObjC/property-impl-misuse.m
@@ -12,7 +12,7 @@
@dynamic X; // expected-note {{previous declaration is here}}
@dynamic X; // expected-error {{property 'X' is already implemented}}
@synthesize Y; // expected-note {{previous use is here}}
-@synthesize Z=Y; // expected-error {{synthesized properties 'Z' and 'Y' both claim ivar 'Y'}}
+@synthesize Z=Y; // expected-error {{synthesized properties 'Z' and 'Y' both claim instance variable 'Y'}}
@end
// rdar://8703553
diff --git a/test/SemaObjC/property-in-class-extension-1.m b/test/SemaObjC/property-in-class-extension-1.m
new file mode 100644
index 000000000000..ab461ef6c191
--- /dev/null
+++ b/test/SemaObjC/property-in-class-extension-1.m
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -verify -Weverything %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -verify -Weverything %s
+// rdar://12103400
+
+@class NSString;
+
+@interface MyClass
+
+@property (nonatomic, readonly) NSString* addingMemoryModel;
+
+@property (nonatomic, copy, readonly) NSString* matchingMemoryModel;
+
+@property (nonatomic, retain, readonly) NSString* addingNoNewMemoryModel;
+
+@property (readonly) NSString* none;
+@property (readonly) NSString* none1;
+
+@property (assign, readonly) NSString* changeMemoryModel; // expected-note {{property declared here}}
+
+@property (readonly) __weak id weak_prop;
+@property (readonly) __weak id weak_prop1;
+
+@property (assign, readonly) NSString* assignProperty;
+
+@property (readonly) NSString* readonlyProp;
+
+
+
+@end
+
+@interface MyClass ()
+{
+ NSString* _name;
+}
+
+@property (nonatomic, copy) NSString* addingMemoryModel;
+@property (nonatomic, copy) NSString* matchingMemoryModel;
+@property () NSString* addingNoNewMemoryModel;
+@property () NSString* none;
+@property (readwrite, retain) NSString* none1;
+
+@property (retain) NSString* changeMemoryModel; // expected-warning {{property attribute in class extension does not match the primary class}}
+@property () __weak id weak_prop;
+@property (readwrite) __weak id weak_prop1;
+
+@property (assign, readwrite) NSString* assignProperty;
+@property (assign) NSString* readonlyProp;
+@end
+
+// rdar://12214070
+@interface radar12214070
+@property (nonatomic, atomic, readonly) float propertyName; // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+@end
+
+@interface radar12214070 ()
+@property (atomic, nonatomic, readonly, readwrite) float propertyName; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}} \
+ // expected-error {{property attributes 'atomic' and 'nonatomic' are mutually exclusive}}
+@end
+
diff --git a/test/SemaObjC/property-ivar-mismatch.m b/test/SemaObjC/property-ivar-mismatch.m
index a0d1c9da7b80..148fa8ebb27f 100644
--- a/test/SemaObjC/property-ivar-mismatch.m
+++ b/test/SemaObjC/property-ivar-mismatch.m
@@ -3,24 +3,24 @@
@interface Test4
{
- char ivar; // expected-note{{ivar is declared here}}
+ char ivar; // expected-note{{instance variable is declared here}}
}
@property int prop;
@end
@implementation Test4
-@synthesize prop = ivar; // expected-error {{type of property 'prop' ('int') does not match type of ivar 'ivar' ('char')}}
+@synthesize prop = ivar; // expected-error {{type of property 'prop' ('int') does not match type of instance variable 'ivar' ('char')}}
@end
@interface Test5
{
- void * _P; // expected-note {{ivar is declared here}}
+ void * _P; // expected-note {{instance variable is declared here}}
}
@property int P;
@end
@implementation Test5
-@synthesize P=_P; // expected-error {{ype of property 'P' ('int') does not match type of ivar '_P' ('void *')}}
+@synthesize P=_P; // expected-error {{ype of property 'P' ('int') does not match type of instance variable '_P' ('void *')}}
@end
diff --git a/test/SemaObjC/property-method-lookup-impl.m b/test/SemaObjC/property-method-lookup-impl.m
index 19d4e684944a..dc490edb1fdc 100644
--- a/test/SemaObjC/property-method-lookup-impl.m
+++ b/test/SemaObjC/property-method-lookup-impl.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface SSyncCEList
{
diff --git a/test/SemaObjC/property-nonfragile-abi.m b/test/SemaObjC/property-nonfragile-abi.m
index 55bf91f383d4..3684cb00ebb4 100644
--- a/test/SemaObjC/property-nonfragile-abi.m
+++ b/test/SemaObjC/property-nonfragile-abi.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
diff --git a/test/SemaObjC/property-noprotocol-warning.m b/test/SemaObjC/property-noprotocol-warning.m
index 71bb86a301ef..e4752c52bc99 100644
--- a/test/SemaObjC/property-noprotocol-warning.m
+++ b/test/SemaObjC/property-noprotocol-warning.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface Object
diff --git a/test/SemaObjC/property-redundant-decl-accessor.m b/test/SemaObjC/property-redundant-decl-accessor.m
index 3b0e825b9d8c..6ff2ceab7ea2 100644
--- a/test/SemaObjC/property-redundant-decl-accessor.m
+++ b/test/SemaObjC/property-redundant-decl-accessor.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Werror -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface MyClass {
const char *_myName;
diff --git a/test/SemaObjC/property-weak.m b/test/SemaObjC/property-weak.m
index a4397a684fc0..d57774bf0fec 100644
--- a/test/SemaObjC/property-weak.m
+++ b/test/SemaObjC/property-weak.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface foo
@property(nonatomic) int foo __attribute__((weak_import));
diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m
index d6495b42308d..76fdf5b242a2 100644
--- a/test/SemaObjC/property.m
+++ b/test/SemaObjC/property.m
@@ -2,7 +2,7 @@
@interface I
{
- int IVAR; // expected-note{{ivar is declared here}}
+ int IVAR; // expected-note{{instance variable is declared here}}
int name;
}
@property int d1;
@@ -18,7 +18,7 @@
@synthesize d1; // expected-error {{synthesized property 'd1' must either be named the same as}}
@dynamic bad; // expected-error {{property implementation must have its declaration in interface 'I'}}
@synthesize prop_id; // expected-error {{synthesized property 'prop_id' must either be named the same}} // expected-note {{previous declaration is here}}
-@synthesize prop_id = IVAR; // expected-error {{type of property 'prop_id' ('id') does not match type of ivar 'IVAR' ('int')}} // expected-error {{property 'prop_id' is already implemented}}
+@synthesize prop_id = IVAR; // expected-error {{type of property 'prop_id' ('id') does not match type of instance variable 'IVAR' ('int')}} // expected-error {{property 'prop_id' is already implemented}}
@synthesize name; // OK! property with same name as an accessible ivar of same name
@end
diff --git a/test/SemaObjC/props-on-prots.m b/test/SemaObjC/props-on-prots.m
index c01e8338628e..6962d6f895c9 100644
--- a/test/SemaObjC/props-on-prots.m
+++ b/test/SemaObjC/props-on-prots.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
diff --git a/test/SemaObjC/protocol-expr-1.m b/test/SemaObjC/protocol-expr-1.m
index fe01d1d47a8d..94a0d9e3e8b5 100644
--- a/test/SemaObjC/protocol-expr-1.m
+++ b/test/SemaObjC/protocol-expr-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol fproto;
diff --git a/test/SemaObjC/protocol-implementation-inherited.m b/test/SemaObjC/protocol-implementation-inherited.m
index c333bb5042d2..45010d5e2e75 100644
--- a/test/SemaObjC/protocol-implementation-inherited.m
+++ b/test/SemaObjC/protocol-implementation-inherited.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol P0
-bar;
diff --git a/test/SemaObjC/protocol-lookup-2.m b/test/SemaObjC/protocol-lookup-2.m
index bf0752312e44..9e8ed8a627b9 100644
--- a/test/SemaObjC/protocol-lookup-2.m
+++ b/test/SemaObjC/protocol-lookup-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface NSObject @end
@protocol ProtocolA
diff --git a/test/SemaObjC/protocol-lookup.m b/test/SemaObjC/protocol-lookup.m
index ed3fbe0f72bf..26718ae2eaa1 100644
--- a/test/SemaObjC/protocol-lookup.m
+++ b/test/SemaObjC/protocol-lookup.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol NSObject
- retain;
- release;
diff --git a/test/SemaObjC/protocol-qualified-class-unsupported.m b/test/SemaObjC/protocol-qualified-class-unsupported.m
index 4bf6b289e7b7..777084d8554b 100644
--- a/test/SemaObjC/protocol-qualified-class-unsupported.m
+++ b/test/SemaObjC/protocol-qualified-class-unsupported.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <stddef.h>
diff --git a/test/SemaObjC/rdar6248119.m b/test/SemaObjC/rdar6248119.m
index 046992c52fe5..a49597839129 100644
--- a/test/SemaObjC/rdar6248119.m
+++ b/test/SemaObjC/rdar6248119.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only %s -verify -fobjc-exceptions
+// expected-no-diagnostics
// Test case for:
// <rdar://problem/6248119> @finally doesn't introduce a new scope
diff --git a/test/SemaObjC/restrict-id-type.m b/test/SemaObjC/restrict-id-type.m
index b24fcb0185e4..24f74c93a027 100644
--- a/test/SemaObjC/restrict-id-type.m
+++ b/test/SemaObjC/restrict-id-type.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -verify %s
+// expected-no-diagnostics
void f0(restrict id a0) {}
diff --git a/test/SemaObjC/selector-1.m b/test/SemaObjC/selector-1.m
index 16d44cbb5515..186e19fead83 100644
--- a/test/SemaObjC/selector-1.m
+++ b/test/SemaObjC/selector-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
@interface I
- (id) compare: (char) arg1;
diff --git a/test/SemaObjC/selector-2.m b/test/SemaObjC/selector-2.m
index fb75369a9a10..17d1872cc7ea 100644
--- a/test/SemaObjC/selector-2.m
+++ b/test/SemaObjC/selector-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wselector -verify %s
+// expected-no-diagnostics
// rdar://8851684
@interface I
- length;
diff --git a/test/SemaObjC/self-declared-in-block.m b/test/SemaObjC/self-declared-in-block.m
index 40a03313b693..36a9ef571d5a 100644
--- a/test/SemaObjC/self-declared-in-block.m
+++ b/test/SemaObjC/self-declared-in-block.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://9154582
@interface Blocky @end
diff --git a/test/SemaObjC/self-in-function.m b/test/SemaObjC/self-in-function.m
index 9027a947a03c..a14ad909dde3 100644
--- a/test/SemaObjC/self-in-function.m
+++ b/test/SemaObjC/self-in-function.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// expected-no-diagnostics
// rdar://9181463
typedef struct objc_class *Class;
diff --git a/test/SemaObjC/setter-dotsyntax.m b/test/SemaObjC/setter-dotsyntax.m
index e0b51e8b51c6..ec47ee2a8e9f 100644
--- a/test/SemaObjC/setter-dotsyntax.m
+++ b/test/SemaObjC/setter-dotsyntax.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://8528170
@interface NSObject @end
diff --git a/test/SemaObjC/super-cat-prot.m b/test/SemaObjC/super-cat-prot.m
index 3e289860c06e..fd9399499ec7 100644
--- a/test/SemaObjC/super-cat-prot.m
+++ b/test/SemaObjC/super-cat-prot.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
diff --git a/test/SemaObjC/super-dealloc-attribute.m b/test/SemaObjC/super-dealloc-attribute.m
new file mode 100644
index 000000000000..35f6dac9bf42
--- /dev/null
+++ b/test/SemaObjC/super-dealloc-attribute.m
@@ -0,0 +1,87 @@
+// 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
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://6386358
+
+#if __has_attribute(objc_requires_super)
+#define NS_REQUIRES_SUPER __attribute((objc_requires_super))
+#endif
+
+@protocol NSObject // expected-note {{protocol is declared here}}
+- MyDealloc NS_REQUIRES_SUPER; // expected-warning {{'objc_requires_super' attribute cannot be applied to methods in protocols}}
+@end
+
+@interface Root
+- MyDealloc __attribute((objc_requires_super));
+- (void)XXX __attribute((objc_requires_super));
+- (void) dealloc __attribute((objc_requires_super)); // expected-warning {{'objc_requires_super' attribute cannot be applied to dealloc}}
+- (void) MyDeallocMeth; // Method in root is not annotated.
+- (void) AnnotMyDeallocMeth __attribute((objc_requires_super));
+- (void) AnnotMyDeallocMethCAT NS_REQUIRES_SUPER;
+
++ (void)registerClass:(id)name __attribute((objc_requires_super));
+@end
+
+@interface Baz : Root<NSObject>
+- MyDealloc;
+- (void) MyDeallocMeth __attribute((objc_requires_super)); // 'Baz' author has annotated method
+- (void) AnnotMyDeallocMeth; // Annotated in root but not here. Annotation is inherited though
+- (void) AnnotMeth __attribute((objc_requires_super)); // 'Baz' author has annotated method
+@end
+
+@implementation Baz
+- MyDealloc {
+ [super MyDealloc];
+ return 0;
+}
+
+- (void)XXX {
+ [super MyDealloc];
+} // expected-warning {{method possibly missing a [super XXX] call}}
+
+- (void) MyDeallocMeth {} // No warning here.
+- (void) AnnotMyDeallocMeth{} // expected-warning {{method possibly missing a [super AnnotMyDeallocMeth] call}}
+- (void) AnnotMeth{}; // No warning here. Annotation is in its class.
+
++ (void)registerClass:(id)name {} // expected-warning {{method possibly missing a [super registerClass:] call}}
+@end
+
+@interface Bar : Baz
+@end
+
+@implementation Bar
+- (void) MyDeallocMeth {} // expected-warning {{method possibly missing a [super MyDeallocMeth] call}}
+- (void) AnnotMyDeallocMeth{} // expected-warning {{method possibly missing a [super AnnotMyDeallocMeth] call}}
+- (void) AnnotMeth{}; // expected-warning {{method possibly missing a [super AnnotMeth] call}}
+@end
+
+@interface Bar(CAT)
+- (void) AnnotMyDeallocMethCAT; // Annotated in root but not here. Annotation is inherited though
+- (void) AnnotMethCAT __attribute((objc_requires_super));
+@end
+
+@implementation Bar(CAT)
+- (void) MyDeallocMeth {} // expected-warning {{method possibly missing a [super MyDeallocMeth] call}}
+- (void) AnnotMyDeallocMeth{} // expected-warning {{method possibly missing a [super AnnotMyDeallocMeth] call}}
+- (void) AnnotMeth{}; // expected-warning {{method possibly missing a [super AnnotMeth] call}}
+- (void) AnnotMyDeallocMethCAT{}; // expected-warning {{method possibly missing a [super AnnotMyDeallocMethCAT] call}}
+- (void) AnnotMethCAT {};
+@end
+
+
+@interface Valid : Baz
+@end
+
+@implementation Valid
+
+- (void)MyDeallocMeth {
+ [super MyDeallocMeth]; // no-warning
+}
+
+
++ (void)registerClass:(id)name {
+ [super registerClass:name]; // no-warning
+}
+
+@end
diff --git a/test/SemaObjC/super-property-message-expr.m b/test/SemaObjC/super-property-message-expr.m
index c25164e15973..81b8f8fa1d6c 100644
--- a/test/SemaObjC/super-property-message-expr.m
+++ b/test/SemaObjC/super-property-message-expr.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface SStoreNodeInfo
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
index 7d3f7c70bb52..0c17bb9392ec 100644
--- a/test/SemaObjC/super-property-notation.m
+++ b/test/SemaObjC/super-property-notation.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface B
+(int) classGetter;
diff --git a/test/SemaObjC/synth-provisional-ivars-1.m b/test/SemaObjC/synth-provisional-ivars-1.m
index 0e155f4840f0..92a9d7165f13 100644
--- a/test/SemaObjC/synth-provisional-ivars-1.m
+++ b/test/SemaObjC/synth-provisional-ivars-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://8913053
typedef unsigned char BOOL;
diff --git a/test/SemaObjC/synthesize-setter-contclass.m b/test/SemaObjC/synthesize-setter-contclass.m
index d75441518725..df954db2dbb5 100644
--- a/test/SemaObjC/synthesize-setter-contclass.m
+++ b/test/SemaObjC/synthesize-setter-contclass.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface TestClass
{
diff --git a/test/SemaObjC/transparent-union.m b/test/SemaObjC/transparent-union.m
index 6f2dbf915ac0..bda0a54bb63f 100644
--- a/test/SemaObjC/transparent-union.m
+++ b/test/SemaObjC/transparent-union.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
typedef union {
struct xx_object_s *_do;
diff --git a/test/SemaObjC/ucn-objc-string.m b/test/SemaObjC/ucn-objc-string.m
index 6070278bb134..f80d1ffb9156 100644
--- a/test/SemaObjC/ucn-objc-string.m
+++ b/test/SemaObjC/ucn-objc-string.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
+// expected-no-diagnostics
@class NSString;
extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
diff --git a/test/SemaObjC/uninit-variables.m b/test/SemaObjC/uninit-variables.m
index cad0f54b2dd3..a3312264f0c2 100644
--- a/test/SemaObjC/uninit-variables.m
+++ b/test/SemaObjC/uninit-variables.m
@@ -1,5 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fblocks %s -verify
+#include <stdarg.h>
+
+@interface NSObject {} @end
+@class NSString;
+
+@interface NSException
++ (void)raise:(NSString *)name format:(NSString *)format, ...;
++ (void)raise:(NSString *)name format:(NSString *)format arguments:(va_list)argList;
+- (void)raise;
+@end
+
// Duplicated from uninit-variables.c.
// Test just to ensure the analysis is working.
int test1() {
@@ -25,3 +36,21 @@ void test3() {
}
}
+int test_abort_on_exceptions(int y, NSException *e, NSString *s, int *z, ...) {
+ int x; // expected-note {{initialize the variable 'x' to silence this warning}}
+ if (y == 1) {
+ va_list alist;
+ va_start(alist, z);
+ [NSException raise:@"Blah" format:@"Blah %@" arguments:alist];
+ return x;
+ }
+ else if (y == 2) {
+ [NSException raise:@"Blah" format:s];
+ return x;
+ }
+ else if (y == 3) {
+ [e raise];
+ return x;
+ }
+ return x; // expected-warning {{variable 'x' is uninitialized when used here}}
+}
diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m
index 5c7542bf4738..3fd1cf04673f 100644
--- a/test/SemaObjC/unused.m
+++ b/test/SemaObjC/unused.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -Wunused -Wunused-parameter -fsyntax-only -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -Wused-but-marked-unused -Wno-objc-protocol-method-implementation -Wunused -Wunused-parameter -fsyntax-only -Wno-objc-root-class %s
int printf(const char *, ...);
@@ -25,12 +25,17 @@ void test2() {
}
@interface foo
-- (int)meth: (int)x: (int)y: (int)z ;
+- (int)meth: (int)x : (int)y : (int)z ;
@end
@implementation foo
-- (int) meth: (int)x:
-(int)y: // expected-warning{{unused}}
+- (int) meth: (int)x: // expected-warning {{'x' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'x' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'x' as parameter name and have an empty entry in the selector}}
+
+(int)y: // expected-warning {{unused}} expected-warning {{'y' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'y' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'y' as parameter name and have an empty entry in the selector}}
(int) __attribute__((unused))z { return x; }
@end
@@ -53,3 +58,17 @@ void test2() {
// rdar://10777111
static NSString *x = @"hi"; // expected-warning {{unused variable 'x'}}
+
+// rdar://12233989
+@interface TestTransitiveUnused
+- (void) a __attribute__((unused));
+- (void) b __attribute__((unused));
+@end
+
+@interface TestTransitiveUnused(CAT)
+@end
+
+@implementation TestTransitiveUnused(CAT)
+- (void) b {}
+- (void) a { [self b]; }
+@end
diff --git a/test/SemaObjC/va-method-1.m b/test/SemaObjC/va-method-1.m
index fe7ccd7632cd..4959df31990f 100644
--- a/test/SemaObjC/va-method-1.m
+++ b/test/SemaObjC/va-method-1.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#include <stdarg.h>
diff --git a/test/SemaObjC/warn-direct-ivar-access.m b/test/SemaObjC/warn-direct-ivar-access.m
index d2295f47655e..088fe0fa264f 100644
--- a/test/SemaObjC/warn-direct-ivar-access.m
+++ b/test/SemaObjC/warn-direct-ivar-access.m
@@ -15,7 +15,7 @@ __attribute__((objc_root_class)) @interface MyObject {
@implementation MyObject
@synthesize myMaster = _myMaster;
-@synthesize isTickledPink = _isTickledPink; // expected-error {{existing ivar '_isTickledPink' for property 'isTickledPink'}}
+@synthesize isTickledPink = _isTickledPink; // expected-error {{existing instance variable '_isTickledPink' for property 'isTickledPink'}}
@synthesize myIntProp = _myIntProp;
- (void) doSomething {
diff --git a/test/SemaObjC/warn-implicit-self-in-block.m b/test/SemaObjC/warn-implicit-self-in-block.m
new file mode 100644
index 000000000000..a7ee16ec700d
--- /dev/null
+++ b/test/SemaObjC/warn-implicit-self-in-block.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -x objective-c -fobjc-arc -fblocks -Wimplicit-retain-self -verify %s
+// rdar://11194874
+
+@interface Root @end
+
+@interface I : Root
+{
+ int _bar;
+}
+@end
+
+@implementation I
+ - (void)foo{
+ ^{
+ _bar = 3; // expected-warning {{block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior}}
+ }();
+ }
+@end
diff --git a/test/SemaObjC/warn-isa-ref.m b/test/SemaObjC/warn-isa-ref.m
index 1932a029b0c7..9d7abd48adff 100644
--- a/test/SemaObjC/warn-isa-ref.m
+++ b/test/SemaObjC/warn-isa-ref.m
@@ -41,7 +41,7 @@ static void func() {
@interface BaseClass {
@public
- Class isa; // expected-note 3 {{ivar is declared here}}
+ Class isa; // expected-note 3 {{instance variable is declared here}}
}
@end
diff --git a/test/SemaObjC/warn-retain-cycle.m b/test/SemaObjC/warn-retain-cycle.m
index 00fd234a0c09..eb4e966c7726 100644
--- a/test/SemaObjC/warn-retain-cycle.m
+++ b/test/SemaObjC/warn-retain-cycle.m
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class -Wno-implicit-retain-self %s
+
+void *_Block_copy(const void *block);
@interface Test0
- (void) setBlock: (void(^)(void)) block;
@@ -24,6 +26,10 @@ void test0(Test0 *x) {
[weakx addBlock: ^{ [x actNow]; }];
[weakx setBlock: ^{ [x actNow]; }];
weakx.block = ^{ [x actNow]; };
+
+ // rdar://11702054
+ x.block = ^{ (void)x.actNow; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}} \
+ // expected-note {{block will be retained by the captured object}}
}
@interface BlockOwner
@@ -123,3 +129,58 @@ void doSomething(unsigned v);
}
@end
+
+void testBlockVariable() {
+ typedef void (^block_t)(void);
+
+ // This case will be caught by -Wuninitialized, and does not create a
+ // retain cycle.
+ block_t a1 = ^{
+ a1(); // no-warning
+ };
+
+ // This case will also be caught by -Wuninitialized.
+ block_t a2;
+ a2 = ^{
+ a2(); // no-warning
+ };
+
+ __block block_t b1 = ^{ // expected-note{{block will be retained by the captured object}}
+ b1(); // expected-warning{{capturing 'b1' strongly in this block is likely to lead to a retain cycle}}
+ };
+
+ __block block_t b2;
+ b2 = ^{ // expected-note{{block will be retained by the captured object}}
+ b2(); // expected-warning{{capturing 'b2' strongly in this block is likely to lead to a retain cycle}}
+ };
+}
+
+
+@interface NSObject
+- (id)copy;
+
+- (void (^)(void))someRandomMethodReturningABlock;
+@end
+
+
+void testCopying(Test0 *obj) {
+ typedef void (^block_t)(void);
+
+ [obj setBlock:[^{ // expected-note{{block will be retained by the captured object}}
+ [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
+ } copy]];
+
+ [obj addBlock:(__bridge_transfer block_t)_Block_copy((__bridge void *)^{ // expected-note{{block will be retained by the captured object}}
+ [obj actNow]; // expected-warning{{capturing 'obj' strongly in this block is likely to lead to a retain cycle}}
+ })];
+
+ [obj addBlock:[^{
+ [obj actNow]; // no-warning
+ } someRandomMethodReturningABlock]];
+
+ extern block_t someRandomFunctionReturningABlock(block_t);
+ [obj setBlock:someRandomFunctionReturningABlock(^{
+ [obj actNow]; // no-warning
+ })];
+}
+
diff --git a/test/SemaObjC/warning-missing-selector-name.m b/test/SemaObjC/warning-missing-selector-name.m
new file mode 100644
index 000000000000..d43031eee0b5
--- /dev/null
+++ b/test/SemaObjC/warning-missing-selector-name.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class -Wmissing-selector-name %s
+// rdar://12263549
+
+@interface Super @end
+@interface INTF : Super
+-(void) Name1:(id)Arg1 Name2:(id)Arg2; // Name1:Name2:
+-(void) Name1:(id) Name2:(id)Arg2; // expected-warning {{'Name2' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'Name2' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'Name2' as parameter name and have an empty entry in the selector}}
+-(void) Name1:(id)Arg1 Name2:(id)Arg2 Name3:(id)Arg3; // Name1:Name2:Name3:
+-(void) Name1:(id)Arg1 Name2:(id) Name3:(id)Arg3; // expected-warning {{'Name3' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'Name3' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'Name3' as parameter name and have an empty entry in the selector}}
+- method:(id) second:(id)second; // expected-warning {{'second' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'second' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'second' as parameter name and have an empty entry in the selector}} \
+ // expected-note {{method definition for 'method::' not found}}
+
+@end
+
+@implementation INTF // expected-warning {{incomplete implementation}}
+-(void) Name1:(id)Arg1 Name2:(id)Arg2{}
+-(void) Name1:(id) Name2:(id)Arg2 {} // expected-warning {{'Name2' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'Name2' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'Name2' as parameter name and have an empty entry in the selector}}
+-(void) Name1:(id)Arg1 Name2:(id)Arg2 Name3:(id)Arg3 {}
+-(void) Name1:(id)Arg1 Name2:(id) Name3:(id)Arg3 {} // expected-warning {{'Name3' used as the name of the previous parameter rather than as part of the selector}} \
+ // expected-note {{introduce a parameter name to make 'Name3' part of the selector}} \
+ // expected-note {{or insert whitespace before ':' to use 'Name3' as parameter name and have an empty entry in the selector}}
+- method:(id)first second:(id)second {return 0; }
+@end
diff --git a/test/SemaObjC/weak-property.m b/test/SemaObjC/weak-property.m
index 8a2adf99b7e4..141c35b9acea 100644
--- a/test/SemaObjC/weak-property.m
+++ b/test/SemaObjC/weak-property.m
@@ -19,6 +19,6 @@
@end
@implementation WeakPropertyTest
-@synthesize x; // expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
+@synthesize x; // expected-error {{existing instance variable 'x' for __weak property 'x' must be __weak}}
@dynamic value1, value, value2, v1,v2,v3,v4;
@end
diff --git a/test/SemaObjC/weak-receiver-warn.m b/test/SemaObjC/weak-receiver-warn.m
index 547f0087bc40..88b867ed0d04 100644
--- a/test/SemaObjC/weak-receiver-warn.m
+++ b/test/SemaObjC/weak-receiver-warn.m
@@ -9,13 +9,13 @@
void test0(Test0 *x) {
__weak Test0 *weakx = x;
- [x addBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
- [x setBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
- x.block = ^{ [weakx actNow]; }; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ [x addBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+ [x setBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+ x.block = ^{ [weakx actNow]; }; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
- [weakx addBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
- [weakx setBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
- weakx.block = ^{ [x actNow]; }; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ [weakx addBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+ [weakx setBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+ weakx.block = ^{ [x actNow]; }; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}
@interface Test
@@ -36,12 +36,12 @@ void test0(Test0 *x) {
if (self.weak_atomic_prop) {
self.weak_atomic_prop = 0;
}
- [self.weak_prop Meth]; // expected-warning {{weak property may be unpredictably null in ARC mode}}
+ [self.weak_prop Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
id pi = self.P;
- [self.weak_atomic_prop Meth]; // expected-warning {{weak property may be unpredictably null in ARC mode}}
+ [self.weak_atomic_prop Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
- [self.P Meth]; // expected-warning {{weak implicit property may be unpredictably null in ARC mode}}
+ [self.P Meth]; // expected-warning {{weak implicit property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}
- (__weak id) P { return 0; }
@@ -52,7 +52,7 @@ void test0(Test0 *x) {
@interface MyClass {
__weak MyClass *_parent;
}
-@property (weak) MyClass *parent; // expected-note 2 {{property declared here}}
+@property (weak) MyClass *parent; // expected-note 4 {{property declared here}}
@end
@implementation MyClass
@@ -60,9 +60,9 @@ void test0(Test0 *x) {
- (void)doSomething
{
- [[self parent] doSomething]; // expected-warning {{weak property may be unpredictably null in ARC mode}}
+ [[self parent] doSomething]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
- (void)self.parent.doSomething; // expected-warning {{weak property may be unpredictably null in ARC mode}}
+ (void)self.parent.doSomething; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}
@end
@@ -74,7 +74,27 @@ void test0(Test0 *x) {
@end
void testProtocol(id <MyProtocol> input) {
- [[input object] Meth]; // expected-warning {{weak property may be unpredictably null in ARC mode}}
- [input.object Meth]; // expected-warning {{weak property may be unpredictably null in ARC mode}}
+ [[input object] Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+ [input.object Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}
+
+@interface Subclass : MyClass
+// Unnecessarily redeclare -parent.
+- (id)parent;
+@end
+
+@implementation Subclass
+
+- (id)parent {
+ return [super parent];
+}
+
+- (void)doSomethingElse {
+ [[self parent] doSomething]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+
+ (void)self.parent.doSomething; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
+}
+
+@end
+
diff --git a/test/SemaObjC/writable-property-in-superclass.m b/test/SemaObjC/writable-property-in-superclass.m
index bbd1f16cffc0..99be5413d7ae 100644
--- a/test/SemaObjC/writable-property-in-superclass.m
+++ b/test/SemaObjC/writable-property-in-superclass.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface MessageStore
@property (assign, readonly) int P;
diff --git a/test/SemaObjCXX/abstract-class-type-ivar.mm b/test/SemaObjCXX/abstract-class-type-ivar.mm
index 823e9c197d35..990ba1c2abd5 100644
--- a/test/SemaObjCXX/abstract-class-type-ivar.mm
+++ b/test/SemaObjCXX/abstract-class-type-ivar.mm
@@ -13,7 +13,7 @@ class CppConcreteSub : public CppAbstractBase {
};
@interface Objc {
- CppConcreteSub _concrete; // expected-error{{ivar type 'CppConcreteSub' is an abstract class}}
+ CppConcreteSub _concrete; // expected-error{{instance variable type 'CppConcreteSub' is an abstract class}}
}
- (CppAbstractBase*)abstract;
@end
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
index e24b9602fb7f..43f6671ac241 100644
--- a/test/SemaObjCXX/arc-0x.mm
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -80,4 +80,16 @@ void testAutoIdTemplate(id obj) {
autoTemplateFunction<id, 2>(obj, obj, [Array new]); // no-warning
}
+// rdar://12229679
+@interface NSObject @end
+typedef __builtin_va_list va_list;
+@interface MyClass : NSObject
+@end
+
+@implementation MyClass
++ (void)fooMethod:(id)firstArg, ... {
+ va_list args;
+ __builtin_va_arg(args, id);
+}
+@end
diff --git a/test/SemaObjCXX/arc-bool-conversion.mm b/test/SemaObjCXX/arc-bool-conversion.mm
index d8f840e871e5..12a3be3022bb 100644
--- a/test/SemaObjCXX/arc-bool-conversion.mm
+++ b/test/SemaObjCXX/arc-bool-conversion.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// expected-no-diagnostics
// rdar://9310049
bool fn(id obj) {
diff --git a/test/SemaObjCXX/arc-libstdcxx.mm b/test/SemaObjCXX/arc-libstdcxx.mm
index 71771b4b1375..537e6b427970 100644
--- a/test/SemaObjCXX/arc-libstdcxx.mm
+++ b/test/SemaObjCXX/arc-libstdcxx.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-runtime-has-weak -verify %s
+// expected-no-diagnostics
@interface A @end
diff --git a/test/SemaObjCXX/arc-memfunc.mm b/test/SemaObjCXX/arc-memfunc.mm
index 274f873fd48a..09556e396cdd 100644
--- a/test/SemaObjCXX/arc-memfunc.mm
+++ b/test/SemaObjCXX/arc-memfunc.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks %s
+// expected-no-diagnostics
struct X0 {
static id makeObject1() __attribute__((ns_returns_retained));
diff --git a/test/SemaObjCXX/arc-non-pod.mm b/test/SemaObjCXX/arc-non-pod.mm
deleted file mode 100644
index 1c5cf7af3a18..000000000000
--- a/test/SemaObjCXX/arc-non-pod.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -Warc-abi -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
-
-// Classes that have an Objective-C object pointer.
-struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
- id x;
-};
-
-struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
- id x[3];
-};
-
-struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
- id x[3][2];
-};
-
-// Don't complain if the type has non-external linkage
-namespace {
- struct HasObjectMember3 {
- id x[3][2];
- };
-}
-
-// Don't complain if the Objective-C pointer type was explicitly given
-// no ownership.
-struct HasObjectMember3 {
- __unsafe_unretained id x[3][2];
-};
-
-struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
- int (^bp)(int);
-};
-
-struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
- int (^bp[2][3])(int);
-};
-
-struct NonPOD {
- NonPOD(const NonPOD&);
-};
-
-struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
- id x;
- NonPOD np;
-};
-
-struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
- NonPOD np;
- id x[3];
-};
-
-struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
- // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
- NonPOD np;
- id x[3][2];
-};
-
-struct HasObjectMemberAndNonPOD3 {
- HasObjectMemberAndNonPOD3 &operator=(const HasObjectMemberAndNonPOD3&);
- ~HasObjectMemberAndNonPOD3();
- NonPOD np;
- id x[3][2];
-};
-
-struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
-// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
- NonPOD np;
- int (^bp)(int);
-};
-
-struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
-// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
- NonPOD np;
- int (^bp[2][3])(int);
-};
-
-int check_non_pod_objc_pointer0[__is_pod(id)? 1 : -1];
-int check_non_pod_objc_pointer1[__is_pod(__strong id)? -1 : 1];
-int check_non_pod_objc_pointer2[__is_pod(__unsafe_unretained id)? 1 : -1];
-int check_non_pod_objc_pointer3[__is_pod(id[2][3])? 1 : -1];
-int check_non_pod_objc_pointer4[__is_pod(__unsafe_unretained id[2][3])? 1 : -1];
-int check_non_pod_block0[__is_pod(int (^)(int))? 1 : -1];
-int check_non_pod_block1[__is_pod(int (^ __unsafe_unretained)(int))? 1 : -1];
-int check_non_pod_block2[__is_pod(int (^ __strong)(int))? -1 : 1];
-
-struct FlexibleArrayMember0 {
- int length;
- id array[]; // expected-error{{flexible array member 'array' of non-POD element type 'id __strong[]'}}
-};
-
-struct FlexibleArrayMember1 {
- int length;
- __unsafe_unretained id array[];
-};
-
-// It's okay to pass a retainable type through an ellipsis.
-void variadic(...);
-void test_variadic() {
- variadic(1, 17, @"Foo");
-}
-
-// It's okay to create a VLA of retainable types.
-void vla(int n) {
- id vla[n];
-}
-
-@interface Crufty {
- union {
- struct {
- id object; // expected-note{{has __strong ownership}}
- } an_object; // expected-error{{union member 'an_object' has a non-trivial copy constructor}}
- void *ptr;
- } storage;
-}
-@end
diff --git a/test/SemaObjCXX/arc-objc-lifetime.mm b/test/SemaObjCXX/arc-objc-lifetime.mm
new file mode 100644
index 000000000000..1e4df741422a
--- /dev/null
+++ b/test/SemaObjCXX/arc-objc-lifetime.mm
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
+// rdar://10244607
+
+typedef const struct __CFString * CFStringRef;
+@class NSString;
+
+NSString *CFBridgingRelease();
+
+typedef NSString * PNSString;
+
+typedef __autoreleasing NSString * AUTORELEASEPNSString;
+
+@interface I @end
+
+@implementation I
+- (CFStringRef)myString
+{
+ CFStringRef myString =
+ (__bridge CFStringRef) (__strong NSString *)CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+
+ myString =
+ (__bridge CFStringRef) (__autoreleasing PNSString) CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+ myString =
+ (__bridge CFStringRef) (AUTORELEASEPNSString) CFBridgingRelease(); // OK
+ myString =
+ (__bridge CFStringRef) (typeof(__strong NSString *)) CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+ return myString;
+}
+
+- (void)decodeValueOfObjCType:(const char *)type at:(void *)addr {
+ __autoreleasing id *stuff = (__autoreleasing id *)addr;
+}
+@end
+
+// rdar://problem/10711456
+__strong I *__strong test1; // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__strong I *(__strong test2); // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__strong I *(__strong (test3)); // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__unsafe_unretained __typeof__(test3) test4;
+typedef __strong I *strong_I;
+__unsafe_unretained strong_I test5;
+
+// rdar://10907090
+typedef void (^T) ();
+@interface NSObject @end
+@protocol P;
+@interface Radar10907090 @end
+
+@implementation Radar10907090
+- (void) MMM : (NSObject*) arg0 : (NSObject<P>*&)arg : (id) arg1 : (id<P>&) arg2 {} // expected-warning {{method parameter of type 'NSObject<P> *__autoreleasing &' with no explicit ownership}} \
+ // expected-warning {{method parameter of type '__autoreleasing id<P> &' with no explicit ownership}}
+- (void) MM : (NSObject*) arg0 : (__strong NSObject**)arg : (id) arg1 : (__strong id*) arg2 {}
+- (void) M : (NSObject**)arg0 : (id*)arg {} // expected-warning {{method parameter of type 'NSObject *__autoreleasing *' with no explicit ownership}} \
+ // expected-warning {{method parameter of type '__autoreleasing id *' with no explicit ownership}}
+- (void) N : (__strong NSObject***) arg0 : (__strong NSObject<P>***)arg : (float**) arg1 : (double) arg2 {}
+- (void) BLOCK : (T&) arg0 : (T)arg : (__strong T*) arg1 {} // expected-warning {{method parameter of type '__autoreleasing T &' (aka 'void (^__autoreleasing &)()') with no explicit ownership}}
+@end
+
+// rdar://12280826
+@class NSMutableDictionary, NSError;
+@interface Radar12280826
+- (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError*&)error;
+@end
+
+@implementation Radar12280826
+- (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError*&)error {}
+@end
+
diff --git a/test/SemaObjCXX/arc-object-init-destroy.mm b/test/SemaObjCXX/arc-object-init-destroy.mm
deleted file mode 100644
index e10e3eac9fc7..000000000000
--- a/test/SemaObjCXX/arc-object-init-destroy.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Warc-abi -fblocks -triple x86_64-apple-darwin10.0.0 %s
-
-typedef __strong id strong_id;
-typedef __weak id weak_id;
-void test_pseudo_destructors(__strong id *sptr, __weak id *wptr) {
- sptr->~id(); // okay
- wptr->~id(); // okay
- sptr->~strong_id(); // okay
- wptr->~weak_id();
- sptr->~weak_id(); // expected-error{{pseudo-destructor destroys object of type '__strong id' with inconsistently-qualified type 'weak_id' (aka '__weak id')}}
- wptr->strong_id::~strong_id(); // expected-error{{pseudo-destructor destroys object of type '__weak id' with inconsistently-qualified type 'strong_id' (aka '__strong id')}}
-
- sptr->id::~id(); // okay
- wptr->id::~id(); // okay
-}
-
-void test_delete(__strong id *sptr, __weak id *wptr) {
- delete sptr;
- delete wptr;
- delete [] sptr; // expected-warning{{destroying an array of '__strong id'; this array must not have been allocated from non-ARC code}}
- delete [] wptr; // expected-warning{{destroying an array of '__weak id'; this array must not have been allocated from non-ARC code}}
-}
-
-void test_new(int n) {
- (void)new strong_id;
- (void)new weak_id;
- (void)new strong_id [n]; // expected-warning{{allocating an array of 'strong_id' (aka '__strong id'); this array must not be deleted in non-ARC code}}
- (void)new weak_id [n]; // expected-warning{{allocating an array of 'weak_id' (aka '__weak id'); this array must not be deleted in non-ARC code}}
-
- (void)new __strong id;
- (void)new __weak id;
- (void)new __strong id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
-
- // Infer '__strong'.
- __strong id *idptr = new id;
- __strong id *idptr2 = new id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
-
- // ... but not for arrays.
- typedef id id_array[2][3];
- (void)new id_array; // expected-error{{'new' cannot allocate an array of 'id' with no explicit ownership}}
-
- typedef __strong id strong_id_array[2][3];
- typedef __strong id strong_id_3[3];
- strong_id_3 *idptr3 = new strong_id_array; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
-}
-
-void test_jump_scope() {
- goto done; // expected-error{{goto into protected scope}}
- __strong id x; // expected-note{{jump bypasses initialization of retaining variable}}
- done:
- return;
-}
diff --git a/test/SemaObjCXX/arc-type-traits.mm b/test/SemaObjCXX/arc-type-traits.mm
index 67bab00cf978..12993a910e54 100644
--- a/test/SemaObjCXX/arc-type-traits.mm
+++ b/test/SemaObjCXX/arc-type-traits.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -std=c++11 %s
+// expected-no-diagnostics
// Check the results of the various type-trait query functions on
// lifetime-qualified types in ARC.
diff --git a/test/SemaObjCXX/argument-dependent-lookup.mm b/test/SemaObjCXX/argument-dependent-lookup.mm
index a25cc68888d7..244c3f7d0193 100644
--- a/test/SemaObjCXX/argument-dependent-lookup.mm
+++ b/test/SemaObjCXX/argument-dependent-lookup.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/9142559>: For the purposes of Argument-Dependent
// Lookup, Objective-C classes are considered to be in the global
diff --git a/test/SemaObjCXX/category-lookup.mm b/test/SemaObjCXX/category-lookup.mm
index 0e870259b735..7ac4d1c5009e 100644
--- a/test/SemaObjCXX/category-lookup.mm
+++ b/test/SemaObjCXX/category-lookup.mm
@@ -6,5 +6,5 @@
@end
void f() {
- NSScriptClassDescription *f; // expected-error {{use of undeclared identifier 'NSScriptClassDescription'}}
+ NSScriptClassDescription *f; // expected-error {{unknown type name 'NSScriptClassDescription'}}
}
diff --git a/test/SemaObjCXX/composite-objc-pointertype.mm b/test/SemaObjCXX/composite-objc-pointertype.mm
index 684f633f71cc..35739a893624 100644
--- a/test/SemaObjCXX/composite-objc-pointertype.mm
+++ b/test/SemaObjCXX/composite-objc-pointertype.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface Foo
@end
diff --git a/test/SemaObjCXX/conversion-ranking.mm b/test/SemaObjCXX/conversion-ranking.mm
index 6c1408bf21f6..b34c9a24ed5a 100644
--- a/test/SemaObjCXX/conversion-ranking.mm
+++ b/test/SemaObjCXX/conversion-ranking.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol P1
@end
diff --git a/test/SemaObjCXX/conversion-to-objc-pointer-2.mm b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm
index b03d4d89e920..063ce3275913 100644
--- a/test/SemaObjCXX/conversion-to-objc-pointer-2.mm
+++ b/test/SemaObjCXX/conversion-to-objc-pointer-2.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar: // 7963410
@protocol NSObject @end
diff --git a/test/SemaObjCXX/conversion-to-objc-pointer.mm b/test/SemaObjCXX/conversion-to-objc-pointer.mm
index 235aaac8d09c..41bb4ff37a0a 100644
--- a/test/SemaObjCXX/conversion-to-objc-pointer.mm
+++ b/test/SemaObjCXX/conversion-to-objc-pointer.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar: // 7963410
template<class T>
diff --git a/test/SemaObjCXX/debugger-support.mm b/test/SemaObjCXX/debugger-support.mm
new file mode 100644
index 000000000000..e8e382a1b3b2
--- /dev/null
+++ b/test/SemaObjCXX/debugger-support.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fdebugger-support -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+@class NSString;
+void testCompareAgainstPtr(int *ptr, NSString *ns) {
+ if (ptr == 17) {}
+ if (ns != 42) {}
+}
diff --git a/test/SemaObjCXX/decltype.mm b/test/SemaObjCXX/decltype.mm
new file mode 100644
index 000000000000..9c4ac16c93f0
--- /dev/null
+++ b/test/SemaObjCXX/decltype.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
+struct HasValueType {
+ typedef int value_type;
+};
+
+__attribute__((objc_root_class))
+@interface Foo
+{
+@protected
+ HasValueType foo;
+}
+
+@property (nonatomic) HasValueType bar;
+@end
+
+@implementation Foo
+@synthesize bar;
+
+- (void)test {
+ decltype(foo)::value_type vt1;
+ decltype(self->foo)::value_type vt2;
+ decltype(self.bar)::value_type vt3;
+}
+@end
diff --git a/test/SemaObjCXX/delay-parsing-cfunctions.mm b/test/SemaObjCXX/delay-parsing-cfunctions.mm
index fa65dbea9ece..4035d00b8a45 100644
--- a/test/SemaObjCXX/delay-parsing-cfunctions.mm
+++ b/test/SemaObjCXX/delay-parsing-cfunctions.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -std=c++11 -fsyntax-only -Werror -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10387088
struct X {
diff --git a/test/SemaObjCXX/delay-parsing-cplusfuncs.mm b/test/SemaObjCXX/delay-parsing-cplusfuncs.mm
index b0227099c1e2..d0d7922252e6 100644
--- a/test/SemaObjCXX/delay-parsing-cplusfuncs.mm
+++ b/test/SemaObjCXX/delay-parsing-cplusfuncs.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -Werror -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10387088
@interface MyClass
diff --git a/test/SemaObjCXX/delay-parsing-func-tryblock.mm b/test/SemaObjCXX/delay-parsing-func-tryblock.mm
index 8cf615ec3264..ecee7be629c3 100644
--- a/test/SemaObjCXX/delay-parsing-func-tryblock.mm
+++ b/test/SemaObjCXX/delay-parsing-func-tryblock.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -fcxx-exceptions -fsyntax-only -Werror -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// rdar://10387088
@interface MyClass
diff --git a/test/SemaObjCXX/expr-objcxx.mm b/test/SemaObjCXX/expr-objcxx.mm
index e70a001b7041..8ea4dabe16dd 100644
--- a/test/SemaObjCXX/expr-objcxx.mm
+++ b/test/SemaObjCXX/expr-objcxx.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
// rdar://8366474
void *P = @selector(foo::bar::);
diff --git a/test/SemaObjCXX/format-strings.mm b/test/SemaObjCXX/format-strings.mm
new file mode 100644
index 000000000000..2fb92e27560a
--- /dev/null
+++ b/test/SemaObjCXX/format-strings.mm
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic %s
+
+#include <stdarg.h>
+
+extern "C" {
+extern int scanf(const char *restrict, ...);
+extern int printf(const char *restrict, ...);
+extern int vprintf(const char *restrict, va_list);
+}
+
+@class NSString;
+
+@interface Format
++ (void)print:(NSString *)format, ... __attribute__((format(NSString, 1, 2)));
+@end
+
+
+namespace Templates {
+ template<typename T>
+ void my_uninstantiated_print(const T &arg) {
+ [Format print:@"%d", arg];
+ }
+
+ template<typename T>
+ void my_print(const T &arg) {
+ [Format print:@"%d", arg]; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+
+ void use_my_print() {
+ my_print("abc"); // expected-note {{requested here}}
+ }
+
+
+ template<typename T>
+ class UninstantiatedPrinter {
+ public:
+ static void print(const T &arg) {
+ [Format print:@"%d", arg]; // no-warning
+ }
+ };
+
+ template<typename T>
+ class Printer {
+ public:
+ void print(const T &arg) {
+ [Format print:@"%d", arg]; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+ };
+
+ void use_class(Printer<const char *> &p) {
+ p.print("abc"); // expected-note {{requested here}}
+ }
+
+
+ template<typename T>
+ class UninstantiatedWrapper {
+ public:
+ class Printer {
+ public:
+ void print(const T &arg) {
+ [Format print:@"%d", arg]; // no-warning
+ }
+ };
+ };
+
+ template<typename T>
+ class Wrapper {
+ public:
+ class Printer {
+ public:
+ void print(const T &arg) {
+ [Format print:@"%d", arg]; // expected-warning {{format specifies type 'int' but the argument has type 'const char *'}}
+ }
+ };
+ };
+
+ void use_class(Wrapper<const char *>::Printer &p) {
+ p.print("abc"); // expected-note {{requested here}}
+ }
+}
+
diff --git a/test/SemaObjCXX/function-pointer-void-star.mm b/test/SemaObjCXX/function-pointer-void-star.mm
index 8d3d6251734f..7c8321538d62 100644
--- a/test/SemaObjCXX/function-pointer-void-star.mm
+++ b/test/SemaObjCXX/function-pointer-void-star.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern "C" id (*_dealloc)(id) ;
diff --git a/test/SemaObjCXX/instantiate-method-return.mm b/test/SemaObjCXX/instantiate-method-return.mm
index 2a3ae3231280..9fad82feaeb7 100644
--- a/test/SemaObjCXX/instantiate-method-return.mm
+++ b/test/SemaObjCXX/instantiate-method-return.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
// PR7386
@class NSObject;
diff --git a/test/SemaObjCXX/ivar-lookup.mm b/test/SemaObjCXX/ivar-lookup.mm
index fc99c15fd379..d99e61780281 100644
--- a/test/SemaObjCXX/ivar-lookup.mm
+++ b/test/SemaObjCXX/ivar-lookup.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
@interface Ivar
- (float*)method;
@end
diff --git a/test/SemaObjCXX/ivar-struct.mm b/test/SemaObjCXX/ivar-struct.mm
index 3f9c7eb1a503..c8c9ca9cbbf0 100644
--- a/test/SemaObjCXX/ivar-struct.mm
+++ b/test/SemaObjCXX/ivar-struct.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface A {
struct X {
int x, y;
diff --git a/test/SemaObjCXX/linkage-spec.mm b/test/SemaObjCXX/linkage-spec.mm
index 584571de9636..25b57a9a5c68 100644
--- a/test/SemaObjCXX/linkage-spec.mm
+++ b/test/SemaObjCXX/linkage-spec.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern "C" {
@class Protocol;
}
diff --git a/test/SemaObjCXX/namespace-lookup.mm b/test/SemaObjCXX/namespace-lookup.mm
index 205b443ffcab..c5521c14353d 100644
--- a/test/SemaObjCXX/namespace-lookup.mm
+++ b/test/SemaObjCXX/namespace-lookup.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// <rdar://problem/9388207>
@interface A
diff --git a/test/SemaObjCXX/null_objc_pointer.mm b/test/SemaObjCXX/null_objc_pointer.mm
index 0da9e50f5a1c..e0232bf3c872 100644
--- a/test/SemaObjCXX/null_objc_pointer.mm
+++ b/test/SemaObjCXX/null_objc_pointer.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wnull-arithmetic %s
+// expected-no-diagnostics
#define NULL __null
@interface X
diff --git a/test/SemaObjCXX/nullptr.mm b/test/SemaObjCXX/nullptr.mm
index 2b29b043923a..73a921e8c895 100644
--- a/test/SemaObjCXX/nullptr.mm
+++ b/test/SemaObjCXX/nullptr.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fblocks -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface A
@end
diff --git a/test/SemaObjCXX/overload-gc.mm b/test/SemaObjCXX/overload-gc.mm
index 5488ea56315c..ffb8680cc03b 100644
--- a/test/SemaObjCXX/overload-gc.mm
+++ b/test/SemaObjCXX/overload-gc.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-darwin9 -fobjc-gc -verify %s
+// expected-no-diagnostics
void f0(__weak id *);
diff --git a/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm b/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm
index d0f8404b6027..7ada2f4239a1 100644
--- a/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm
+++ b/test/SemaObjCXX/pointer-to-objc-pointer-conv.mm
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// REQUIRES: LP64
@interface G
@end
diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm
index 2237411aaf0c..2a462e4ffa37 100644
--- a/test/SemaObjCXX/propert-dot-error.mm
+++ b/test/SemaObjCXX/propert-dot-error.mm
@@ -63,7 +63,7 @@ class Forward;
void testD(D *d) {
d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward::'}}
- d->Forward::ivar = 12; // expected-error{{ivar access cannot be qualified with 'Forward::'}}
+ d->Forward::ivar = 12; // expected-error{{instance variable access cannot be qualified with 'Forward::'}}
d.D::property = 17; // expected-error{{expected a class or namespace}}
d->D::ivar = 12; // expected-error{{expected a class or namespace}}
}
diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm
index 3c6b13858686..0783eebc11c5 100644
--- a/test/SemaObjCXX/properties.mm
+++ b/test/SemaObjCXX/properties.mm
@@ -106,3 +106,26 @@ void test7(Test7 *ptr) {
delete ptr.implicit_struct_property;
delete ptr.explicit_struct_property;
}
+
+// Make sure the returned value from property assignment is void,
+// because there isn't any other viable way to handle it for
+// non-trivial classes.
+class NonTrivial1 {
+public:
+ ~NonTrivial1();
+};
+class NonTrivial2 {
+public:
+ NonTrivial2();
+ NonTrivial2(const NonTrivial2&);
+};
+@interface TestNonTrivial
+@property(assign, nonatomic) NonTrivial1 p1;
+@property(assign, nonatomic) NonTrivial2 p2;
+@end
+TestNonTrivial *TestNonTrivialObj;
+
+extern void* VoidType;
+extern decltype(TestNonTrivialObj.p1 = NonTrivial1())* VoidType;
+extern decltype(TestNonTrivialObj.p2 = NonTrivial2())* VoidType;
+
diff --git a/test/SemaObjCXX/property-synthesis-error.mm b/test/SemaObjCXX/property-synthesis-error.mm
index 4f64a3a3385e..b6ab85ccab0d 100644
--- a/test/SemaObjCXX/property-synthesis-error.mm
+++ b/test/SemaObjCXX/property-synthesis-error.mm
@@ -16,7 +16,7 @@
@interface MyClass ()
-@property (readwrite) NSMutableArray * array;
+@property (readwrite, retain) NSMutableArray * array;
@end
@@ -83,3 +83,24 @@ struct ConvertToIncomplete { operator IncompleteStruct&(); };
@implementation SynthIncompleteRef // expected-error {{cannot synthesize property 'x' with incomplete type 'IncompleteStruct'}}
@synthesize y; // expected-error {{cannot synthesize property 'y' with incomplete type 'IncompleteStruct'}}
@end
+
+
+// Check error handling for instantiation during property synthesis.
+template<typename T> class TemplateClass1 {
+ T *x; // expected-error {{'x' declared as a pointer to a reference of type 'int &'}}
+};
+template<typename T> class TemplateClass2 {
+ TemplateClass2& operator=(TemplateClass1<T>);
+ TemplateClass2& operator=(TemplateClass2) { T(); } // expected-error {{reference to type 'int' requires an initializer}} \
+ // expected-note 2 {{implicitly declared private here}} \
+ // expected-note {{'operator=' declared here}}
+};
+__attribute__((objc_root_class)) @interface InterfaceWithTemplateProperties
+@property TemplateClass2<int&> intprop;
+@property TemplateClass2<int&> &floatprop;
+@end
+@implementation InterfaceWithTemplateProperties // expected-error 2 {{'operator=' is a private member of 'TemplateClass2<int &>'}} \
+ // expected-error {{atomic property of reference type 'TemplateClass2<int &> &' cannot have non-trivial assignment operator}} \
+ // expected-note {{in instantiation of template class}} \
+ // expected-note {{in instantiation of member function}}
+@end
diff --git a/test/SemaObjCXX/property-type-mismatch.mm b/test/SemaObjCXX/property-type-mismatch.mm
index 059793cf5ceb..2b267ad96eef 100644
--- a/test/SemaObjCXX/property-type-mismatch.mm
+++ b/test/SemaObjCXX/property-type-mismatch.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// rdar://9740328
@protocol P1;
diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm
index 3a522005abee..f63e17d98efc 100644
--- a/test/SemaObjCXX/references.mm
+++ b/test/SemaObjCXX/references.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -emit-llvm -o - %s
+// expected-no-diagnostics
// Test reference binding.
diff --git a/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm b/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm
index fcabaded7c4d..4d7c049bbfea 100644
--- a/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm
+++ b/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface NSString @end
diff --git a/test/SemaObjCXX/reserved-keyword-methods.mm b/test/SemaObjCXX/reserved-keyword-methods.mm
index 1302128ac0f0..12608dea161a 100644
--- a/test/SemaObjCXX/reserved-keyword-methods.mm
+++ b/test/SemaObjCXX/reserved-keyword-methods.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#define FOR_EACH_KEYWORD(macro) \
macro(asm) \
diff --git a/test/SemaObjCXX/standard-conversion-to-bool.mm b/test/SemaObjCXX/standard-conversion-to-bool.mm
index 2e6984872d79..c36b63bd6413 100644
--- a/test/SemaObjCXX/standard-conversion-to-bool.mm
+++ b/test/SemaObjCXX/standard-conversion-to-bool.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@class NSString;
id a;
diff --git a/test/SemaObjCXX/static-cast.mm b/test/SemaObjCXX/static-cast.mm
index e2827028de59..494ee253e252 100644
--- a/test/SemaObjCXX/static-cast.mm
+++ b/test/SemaObjCXX/static-cast.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@protocol NSTextViewDelegate;
diff --git a/test/SemaObjCXX/vla.mm b/test/SemaObjCXX/vla.mm
index d6da1c0cf40e..e1d556e9921a 100644
--- a/test/SemaObjCXX/vla.mm
+++ b/test/SemaObjCXX/vla.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
@interface Data
- (unsigned)length;
diff --git a/test/SemaOpenCL/cond.cl b/test/SemaOpenCL/cond.cl
index 79dc82db190d..802ad9b785a8 100644
--- a/test/SemaOpenCL/cond.cl
+++ b/test/SemaOpenCL/cond.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
typedef __attribute__((ext_vector_type(4))) float float4;
diff --git a/test/SemaOpenCL/init.cl b/test/SemaOpenCL/init.cl
index b3ecfecb5db6..a156921254b6 100644
--- a/test/SemaOpenCL/init.cl
+++ b/test/SemaOpenCL/init.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
typedef float float8 __attribute((ext_vector_type(8)));
diff --git a/test/SemaOpenCL/vec_compare.cl b/test/SemaOpenCL/vec_compare.cl
index dd91aa592ab2..567629c10d56 100644
--- a/test/SemaOpenCL/vec_compare.cl
+++ b/test/SemaOpenCL/vec_compare.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
typedef __attribute__((ext_vector_type(2))) unsigned int uint2;
typedef __attribute__((ext_vector_type(2))) int int2;
diff --git a/test/SemaOpenCL/vector_literals_const.cl b/test/SemaOpenCL/vector_literals_const.cl
index e761816db4b7..ee5ae2002a3c 100644
--- a/test/SemaOpenCL/vector_literals_const.cl
+++ b/test/SemaOpenCL/vector_literals_const.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
typedef int int2 __attribute((ext_vector_type(2)));
typedef int int3 __attribute((ext_vector_type(3)));
diff --git a/test/SemaTemplate/ackermann.cpp b/test/SemaTemplate/ackermann.cpp
index 9525bfcc4f43..fc523e392eaf 100644
--- a/test/SemaTemplate/ackermann.cpp
+++ b/test/SemaTemplate/ackermann.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// template<unsigned M, unsigned N>
// struct Ackermann {
diff --git a/test/SemaTemplate/alias-church-numerals.cpp b/test/SemaTemplate/alias-church-numerals.cpp
index 69d77163ab67..a1613230ac0d 100644
--- a/test/SemaTemplate/alias-church-numerals.cpp
+++ b/test/SemaTemplate/alias-church-numerals.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
template<typename W> using R = T<V, W>;
diff --git a/test/SemaTemplate/alias-template-template-param.cpp b/test/SemaTemplate/alias-template-template-param.cpp
index c22fccb6788e..0b17d10d0cb6 100644
--- a/test/SemaTemplate/alias-template-template-param.cpp
+++ b/test/SemaTemplate/alias-template-template-param.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
template<template<typename> class D> using C = D<int>;
diff --git a/test/SemaTemplate/array-to-pointer-decay.cpp b/test/SemaTemplate/array-to-pointer-decay.cpp
index 072c0e52edc6..26d277d7dc05 100644
--- a/test/SemaTemplate/array-to-pointer-decay.cpp
+++ b/test/SemaTemplate/array-to-pointer-decay.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
struct mystruct {
int member;
diff --git a/test/SemaTemplate/atomics.cpp b/test/SemaTemplate/atomics.cpp
index e9fdc9de3d23..19b607f738a8 100644
--- a/test/SemaTemplate/atomics.cpp
+++ b/test/SemaTemplate/atomics.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR8345
template<typename T> T f(T* value) {
diff --git a/test/SemaTemplate/class-template-ctor-initializer.cpp b/test/SemaTemplate/class-template-ctor-initializer.cpp
index 44bb4bda791e..6043327b7bab 100644
--- a/test/SemaTemplate/class-template-ctor-initializer.cpp
+++ b/test/SemaTemplate/class-template-ctor-initializer.cpp
@@ -53,3 +53,20 @@ namespace PR7259 {
return 0;
}
}
+
+namespace NonDependentError {
+ struct Base { Base(int); }; // expected-note 2{{candidate}}
+
+ template<typename T>
+ struct Derived1 : Base {
+ Derived1() : Base(1, 2) {} // expected-error {{no matching constructor}}
+ };
+
+ template<typename T>
+ struct Derived2 : Base {
+ Derived2() : BaseClass(1) {} // expected-error {{does not name a non-static data member or base}}
+ };
+
+ Derived1<void> d1;
+ Derived2<void> d2;
+}
diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp
index 3b027787249b..b674537ea71c 100644
--- a/test/SemaTemplate/class-template-id.cpp
+++ b/test/SemaTemplate/class-template-id.cpp
@@ -40,7 +40,7 @@ typedef N::C<float> c2;
// PR5655
template<typename T> struct Foo { }; // expected-note{{template is declared here}}
-void f(void) { Foo bar; } // expected-error{{without a template argument list}}
+void f(void) { Foo bar; } // expected-error{{use of class template Foo requires template arguments}}
// rdar://problem/8254267
template <typename T> class Party;
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
index 2f9fe0e4855b..80c4aaf85601 100644
--- a/test/SemaTemplate/constexpr-instantiate.cpp
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -75,3 +75,136 @@ namespace Reference {
constexpr int n = const_cast<int&>(S<int>::r);
static_assert(n == 5, "");
}
+
+namespace Unevaluated {
+ // We follow g++ in treating any reference to a constexpr function template
+ // specialization as requiring an instantiation, even if it occurs in an
+ // unevaluated context.
+ //
+ // We go slightly further than g++, and also trigger the implicit definition
+ // of a defaulted special member in the same circumstances. This seems scary,
+ // since a lot of classes have constexpr special members in C++11, but the
+ // only observable impact should be the implicit instantiation of constexpr
+ // special member templates (defaulted special members should only be
+ // generated if they are well-formed, and non-constexpr special members in a
+ // base or member cause the class's special member to not be constexpr).
+ //
+ // FIXME: None of this is required by the C++ standard. The rules in this
+ // area are poorly specified, so this is subject to change.
+ namespace NotConstexpr {
+ template<typename T> struct S {
+ S() : n(0) {}
+ S(const S&) : n(T::error) {}
+ int n;
+ };
+ struct U : S<int> {};
+ decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it wasn't declared constexpr
+ }
+ namespace Constexpr {
+ template<typename T> struct S {
+ constexpr S() : n(0) {}
+ constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}}
+ int n;
+ };
+ struct U : S<int> {}; // expected-note {{instantiation}}
+ decltype(U(U())) u; // expected-note {{here}}
+ }
+
+ namespace PR11851_Comment0 {
+ template<int x> constexpr int f() { return x; }
+ template<int i> void ovf(int (&x)[f<i>()]);
+ void f() { int x[10]; ovf<10>(x); }
+ }
+
+ namespace PR11851_Comment1 {
+ template<typename T>
+ constexpr bool Integral() {
+ return true;
+ }
+ template<typename T, bool Int = Integral<T>()>
+ struct safe_make_unsigned {
+ typedef T type;
+ };
+ template<typename T>
+ using Make_unsigned = typename safe_make_unsigned<T>::type;
+ template <typename T>
+ struct get_distance_type {
+ using type = int;
+ };
+ template<typename R>
+ auto size(R) -> Make_unsigned<typename get_distance_type<R>::type>;
+ auto check() -> decltype(size(0));
+ }
+
+ namespace PR11851_Comment6 {
+ template<int> struct foo {};
+ template<class> constexpr int bar() { return 0; }
+ template<class T> foo<bar<T>()> foobar();
+ auto foobar_ = foobar<int>();
+ }
+
+ namespace PR11851_Comment9 {
+ struct S1 {
+ constexpr S1() {}
+ constexpr operator int() const { return 0; }
+ };
+ int k1 = sizeof(short{S1(S1())});
+
+ struct S2 {
+ constexpr S2() {}
+ constexpr operator int() const { return 123456; }
+ };
+ int k2 = sizeof(short{S2(S2())}); // expected-error {{cannot be narrowed}} expected-note {{override}}
+ }
+
+ namespace PR12288 {
+ template <typename> constexpr bool foo() { return true; }
+ template <bool> struct bar {};
+ template <typename T> bar<foo<T>()> baz() { return bar<foo<T>()>(); }
+ int main() { baz<int>(); }
+ }
+
+ namespace PR13423 {
+ template<bool, typename> struct enable_if {};
+ template<typename T> struct enable_if<true, T> { using type = T; };
+
+ template<typename T> struct F {
+ template<typename U>
+ static constexpr bool f() { return sizeof(T) < U::size; }
+
+ template<typename U>
+ static typename enable_if<f<U>(), void>::type g() {} // expected-note {{disabled by 'enable_if'}}
+ };
+
+ struct U { static constexpr int size = 2; };
+
+ void h() { F<char>::g<U>(); }
+ void i() { F<int>::g<U>(); } // expected-error {{no matching function}}
+ }
+
+ namespace PR14203 {
+ struct duration { constexpr duration() {} };
+
+ template <typename>
+ void sleep_for() {
+ constexpr duration max = duration();
+ }
+ }
+}
+
+namespace NoInstantiationWhenSelectingOverload {
+ // Check that we don't instantiate conversion functions when we're checking
+ // for the existence of an implicit conversion sequence, only when a function
+ // is actually chosen by overload resolution.
+ struct S {
+ template<typename T> constexpr S(T) : n(T::error) {} // expected-error {{no members}}
+ int n;
+ };
+
+ void f(S);
+ void f(int);
+
+ void g() { f(0); }
+ void h() { (void)sizeof(f(0)); }
+ void i() { (void)sizeof(f("oops")); } // expected-note {{instantiation of}}
+}
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
index ccef811e2224..f47c07187cb2 100644
--- a/test/SemaTemplate/current-instantiation.cpp
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -2,7 +2,7 @@
// This test concerns the identity of dependent types within the
// canonical type system, specifically focusing on the difference
-// between members of the current instantiation and membmers of an
+// between members of the current instantiation and members of an
// unknown specialization. This considers C++ [temp.type], which
// specifies type equivalence within a template, and C++0x
// [temp.dep.type], which defines what it means to be a member of the
@@ -235,3 +235,15 @@ namespace rdar10194295 {
template<typename X<XT>::Enum>
class X<XT>::Inner { };
}
+
+namespace RebuildDependentScopeDeclRefExpr {
+ template<int> struct N {};
+ template<typename T> struct X {
+ static const int thing = 0;
+ N<thing> data();
+ N<thing> foo();
+ };
+ template<typename T> N<X<T>::thing> X<T>::data() {}
+ // FIXME: We should issue a typo-correction here.
+ template<typename T> N<X<T>::think> X<T>::foo() {} // expected-error {{no member named 'think' in 'X<T>'}}
+}
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index cf3899f5eda7..0714c5e51648 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -2,7 +2,7 @@
// Note that the error count below doesn't matter. We just want to
// make sure that the parser doesn't crash.
-// CHECK: 13 errors
+// CHECK: 15 errors
// PR7511
template<a>
@@ -87,3 +87,26 @@ void register_object_imp ( )
{
cout << endl<1>;
}
+
+// PR12933
+namespacae PR12933 {
+ template<typename S>
+ template<typename T>
+ void function(S a, T b) {}
+
+ int main() {
+ function(0, 1);
+ return 0;
+ }
+}
+
+// A buildbot failure from libcxx
+namespace libcxx_test {
+ template <class _Ptr, bool> struct __pointer_traits_element_type;
+ template <class _Ptr> struct __pointer_traits_element_type<_Ptr, true>;
+ template <template <class, class...> class _Sp, class _Tp, class ..._Args> struct __pointer_traits_element_type<_Sp<_Tp, _Args...>, true> {
+ typedef char type;
+ };
+ template <class T> struct B {};
+ __pointer_traits_element_type<B<int>, true>::type x;
+}
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index 77143136c3d2..4c815f655875 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// expected-no-diagnostics
// Test default template arguments for function templates.
template<typename T = int>
diff --git a/test/SemaTemplate/dependent-base-member-init.cpp b/test/SemaTemplate/dependent-base-member-init.cpp
index 1d4fed3e1d26..a278e79f9123 100644
--- a/test/SemaTemplate/dependent-base-member-init.cpp
+++ b/test/SemaTemplate/dependent-base-member-init.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR4381
template<class T> struct X {};
diff --git a/test/SemaTemplate/dependent-expr.cpp b/test/SemaTemplate/dependent-expr.cpp
index a1ddd249f7fe..d75b0f3e3029 100644
--- a/test/SemaTemplate/dependent-expr.cpp
+++ b/test/SemaTemplate/dependent-expr.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5908
template <typename Iterator>
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index 924bad9257b9..efa4d28723d8 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -319,8 +319,30 @@ namespace PR11421 {
template < unsigned > struct X {
static const unsigned dimension = 3;
template<unsigned dim=dimension>
- struct Y: Y<dim> { }; // expected-error {{incomplete type}} expected-note {{is not complete until the closing}}
+ struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
};
typedef X<3> X3;
-X3::Y<>::iterator it; // expected-note {{requested here}}
+X3::Y<>::iterator it; // expected-error {{no type named 'iterator' in 'PR11421::X<3>::Y<3>'}}
+}
+
+namespace rdar12629723 {
+ template<class T>
+ struct X {
+ struct C : public C { }; // expected-error{{circular inheritance between 'rdar12629723::X::C' and 'rdar12629723::X::C'}}
+
+ struct B;
+
+ struct A : public B { // expected-note{{'rdar12629723::X::A' declared here}}
+ virtual void foo() { }
+ };
+ struct B;
+
+ struct D : T::foo { };
+ struct E : D { };
+ };
+
+ template<class T>
+ struct X<T>::B : public A { // expected-error{{circular inheritance between 'rdar12629723::X::A' and 'rdar12629723::X::B'}}
+ virtual void foo() { }
+ };
}
diff --git a/test/SemaTemplate/dependent-sized_array.cpp b/test/SemaTemplate/dependent-sized_array.cpp
index cf0e0f37ee04..6fdcaa63e5ad 100644
--- a/test/SemaTemplate/dependent-sized_array.cpp
+++ b/test/SemaTemplate/dependent-sized_array.cpp
@@ -15,3 +15,14 @@ void f1() {
int a1[] = { 1, 2, 3, N };
int a3[sizeof(a1)/sizeof(int) != 4? 1 : -1]; // expected-error{{negative}}
}
+
+namespace PR13788 {
+ template <unsigned __N>
+ struct S {
+ int V;
+ };
+ template <int N>
+ void foo() {
+ S<0> arr[N] = {{ 4 }};
+ }
+}
diff --git a/test/SemaTemplate/derived.cpp b/test/SemaTemplate/derived.cpp
new file mode 100644
index 000000000000..1fb9401c94c2
--- /dev/null
+++ b/test/SemaTemplate/derived.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T> class vector2 {};
+template<typename T> class vector : vector2<T> {};
+
+template<typename T> void Foo2(vector2<const T*> V) {} // expected-note{{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'int'}}
+template<typename T> void Foo(vector<const T*> V) {} // expected-note {{candidate template ignored: can't deduce a type for 'T' which would make 'const T' equal 'int'}}
+
+void test() {
+ Foo2(vector2<int*>()); // expected-error{{no matching function for call to 'Foo2'}}
+ Foo(vector<int*>()); // expected-error{{no matching function for call to 'Foo'}}
+}
diff --git a/test/SemaTemplate/enum-argument.cpp b/test/SemaTemplate/enum-argument.cpp
index 7d237570678f..7ff419613990 100644
--- a/test/SemaTemplate/enum-argument.cpp
+++ b/test/SemaTemplate/enum-argument.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
enum Enum { val = 1 };
template <Enum v> struct C {
diff --git a/test/SemaTemplate/example-typelist.cpp b/test/SemaTemplate/example-typelist.cpp
index 082aeb83fbdd..9ce06e665cf7 100644
--- a/test/SemaTemplate/example-typelist.cpp
+++ b/test/SemaTemplate/example-typelist.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// A simple cons-style typelist
struct nil { };
diff --git a/test/SemaTemplate/inject-templated-friend-post.cpp b/test/SemaTemplate/inject-templated-friend-post.cpp
index 39c445ca0f99..c86f718bb5f1 100644
--- a/test/SemaTemplate/inject-templated-friend-post.cpp
+++ b/test/SemaTemplate/inject-templated-friend-post.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang %s -S -emit-llvm -o - | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
-// RUN: %clang %s -S -emit-llvm -o - -DPROTOTYPE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
-// RUN: %clang %s -S -emit-llvm -o - -DINSTANTIATE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
-// RUN: %clang %s -S -emit-llvm -o - -DPROTOTYPE -DINSTANTIATE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
+// RUN: %clang %s -std=c++98 -S -emit-llvm -o - | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
+// RUN: %clang %s -std=c++98 -S -emit-llvm -o - -DPROTOTYPE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
+// RUN: %clang %s -std=c++98 -S -emit-llvm -o - -DINSTANTIATE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
+// RUN: %clang %s -std=c++98 -S -emit-llvm -o - -DPROTOTYPE -DINSTANTIATE | grep -e "define linkonce_odr.*_ZlsR11std_ostreamRK8StreamerI3FooE"
// RUN: %clang_cc1 %s -DREDEFINE -verify
// RUN: %clang_cc1 %s -DPROTOTYPE -DREDEFINE -verify
// PR8007: friend function not instantiated, reordered version.
diff --git a/test/SemaTemplate/instantiate-array.cpp b/test/SemaTemplate/instantiate-array.cpp
index b8229d3f641a..41d1cfe138ab 100644
--- a/test/SemaTemplate/instantiate-array.cpp
+++ b/test/SemaTemplate/instantiate-array.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// expected-no-diagnostics
#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
diff --git a/test/SemaTemplate/instantiate-attr.cpp b/test/SemaTemplate/instantiate-attr.cpp
index bbadb6375b5b..1e94614f371d 100644
--- a/test/SemaTemplate/instantiate-attr.cpp
+++ b/test/SemaTemplate/instantiate-attr.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template <typename T>
struct A {
char a __attribute__((aligned(16)));
@@ -24,3 +25,12 @@ namespace test1 {
int test1[__builtin_offsetof(type, a) == 0 ? 1 : -1];
int test2[__builtin_offsetof(type, b) == 4 ? 1 : -1];
}
+
+namespace test2 {
+ template <class type>
+ struct fastscriptmember {
+ type Member __attribute__ ((packed));
+ char x;
+ };
+ int test0[sizeof(fastscriptmember<int>) == 5 ? 1 : -1];
+}
diff --git a/test/SemaTemplate/instantiate-decl-init.cpp b/test/SemaTemplate/instantiate-decl-init.cpp
index 6b76d72e3261..9658fc1465cd 100644
--- a/test/SemaTemplate/instantiate-decl-init.cpp
+++ b/test/SemaTemplate/instantiate-decl-init.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5426 - the non-dependent obj would be fully processed and wrapped in a
// CXXConstructExpr at definition time, which would lead to a failure at
diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp
index 49b1b63f5152..7cdeda6fb9da 100644
--- a/test/SemaTemplate/instantiate-declref-ice.cpp
+++ b/test/SemaTemplate/instantiate-declref-ice.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<int i> struct x {
static const int j = i;
x<j>* y;
diff --git a/test/SemaTemplate/instantiate-deeply.cpp b/test/SemaTemplate/instantiate-deeply.cpp
index c5f65945afcb..ba38b2b2351c 100644
--- a/test/SemaTemplate/instantiate-deeply.cpp
+++ b/test/SemaTemplate/instantiate-deeply.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -verify %s
+// expected-no-diagnostics
template<typename a> struct A {
template <typename b> struct B {
template <typename c> struct C {
diff --git a/test/SemaTemplate/instantiate-dependent-nested-name.cpp b/test/SemaTemplate/instantiate-dependent-nested-name.cpp
index eb1d3fba10ed..06a1ed4119d2 100644
--- a/test/SemaTemplate/instantiate-dependent-nested-name.cpp
+++ b/test/SemaTemplate/instantiate-dependent-nested-name.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR4382
template<typename T> struct X { static const T A = 1; };
template<typename T, bool = X<T>::A> struct Y { typedef T A; };
diff --git a/test/SemaTemplate/instantiate-elab-type-specifier.cpp b/test/SemaTemplate/instantiate-elab-type-specifier.cpp
index e5e10a85cf2f..5db9b56c21a4 100644
--- a/test/SemaTemplate/instantiate-elab-type-specifier.cpp
+++ b/test/SemaTemplate/instantiate-elab-type-specifier.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5681
template <class T> struct Base {
diff --git a/test/SemaTemplate/instantiate-enum-2.cpp b/test/SemaTemplate/instantiate-enum-2.cpp
index aa3b590cada4..9a90a9cd6ce7 100644
--- a/test/SemaTemplate/instantiate-enum-2.cpp
+++ b/test/SemaTemplate/instantiate-enum-2.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
+// expected-no-diagnostics
template<int IntBits> struct X {
enum {
diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
index c560c6ba2a3b..97bf00303bbe 100644
--- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
+++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
@@ -34,18 +34,6 @@ template<> struct S<10> {};
void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}}
-template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
-// expected-error 16{{call to function 'go' that is neither visible}} \
-// expected-note 16{{'go' should be declared prior to the call site}} \
-// expected-error {{recursive template instantiation exceeded maximum depth of 16}} \
-// expected-error {{use of undeclared identifier 'go'}} \
-
-void f() {
- int k = go(0); // \
- // expected-note {{in instantiation of exception specification for 'go<int>' requested here}}
-}
-
-
namespace dr1330_example {
template <class T> struct A {
void f(...) throw (typename T::X); // expected-error {{'int'}}
diff --git a/test/SemaTemplate/instantiate-friend-class.cpp b/test/SemaTemplate/instantiate-friend-class.cpp
index c87b8d0bf9b2..32aa3014b9cb 100644
--- a/test/SemaTemplate/instantiate-friend-class.cpp
+++ b/test/SemaTemplate/instantiate-friend-class.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR4794
template <class T> class X
diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp
index 20b62c1e537e..c151fbb9a5ba 100644
--- a/test/SemaTemplate/instantiate-local-class.cpp
+++ b/test/SemaTemplate/instantiate-local-class.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
template<typename T>
void f0() {
struct X;
diff --git a/test/SemaTemplate/instantiate-member-expr.cpp b/test/SemaTemplate/instantiate-member-expr.cpp
index a31569a0c395..6ba94b28df62 100644
--- a/test/SemaTemplate/instantiate-member-expr.cpp
+++ b/test/SemaTemplate/instantiate-member-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic
template<typename T>
struct S {
S() { }
@@ -66,3 +66,18 @@ namespace test2 {
template class B<int>;
}
+
+namespace PR14124 {
+ template<typename T> struct S {
+ int value;
+ };
+ template<typename T> void f() { S<T>::value; } // expected-error {{invalid use of non-static data member 'value'}}
+ template void f<int>(); // expected-note {{in instantiation of}}
+
+ struct List { List *next; };
+ template<typename T, T *(T::*p) = &T::next> struct A {};
+ A<List> a; // ok
+ void operator&(struct Whatever);
+ template<typename T, T *(T::*p) = &T::next> struct B {};
+ B<List> b; // still ok
+}
diff --git a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
index 027c1e8bb769..04975e30448b 100644
--- a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
+++ b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5311
template<typename T>
diff --git a/test/SemaTemplate/instantiate-overload-candidates.cpp b/test/SemaTemplate/instantiate-overload-candidates.cpp
index 5b7e60dccfdd..7542dbd8ab9b 100644
--- a/test/SemaTemplate/instantiate-overload-candidates.cpp
+++ b/test/SemaTemplate/instantiate-overload-candidates.cpp
@@ -19,3 +19,33 @@ template <typename T> S_<NoDefinition>::type f(T*, NoDefinition*); // expected-n
void test(int x) {
f(&x, 0);
}
+
+// Ensure that we instantiate an overloaded function if it's selected by
+// overload resolution when initializing a function pointer.
+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}}
+
+namespace PR13098 {
+ struct A {
+ A(int);
+ void operator++() {}
+ void operator+(int) {}
+ void operator+(A) {}
+ void operator[](int) {}
+ void operator[](A) {}
+ };
+ struct B : A {
+ using A::operator++;
+ using A::operator+;
+ using A::operator[];
+ };
+ template<typename T> void f(B b) {
+ ++b;
+ b + 0;
+ b[0];
+ }
+ template void f<void>(B);
+}
diff --git a/test/SemaTemplate/instantiate-overloaded-arrow.cpp b/test/SemaTemplate/instantiate-overloaded-arrow.cpp
index ee36427db87b..b21c7a34ad4c 100644
--- a/test/SemaTemplate/instantiate-overloaded-arrow.cpp
+++ b/test/SemaTemplate/instantiate-overloaded-arrow.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// PR5488
struct X {
diff --git a/test/SemaTemplate/instantiate-sizeof.cpp b/test/SemaTemplate/instantiate-sizeof.cpp
index 00d63d0c2fe5..bf66fdc17c65 100644
--- a/test/SemaTemplate/instantiate-sizeof.cpp
+++ b/test/SemaTemplate/instantiate-sizeof.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-no-diagnostics
// Make sure we handle contexts correctly with sizeof
template<typename T> void f(T n) {
diff --git a/test/SemaTemplate/instantiation-default-3.cpp b/test/SemaTemplate/instantiation-default-3.cpp
index dae6b18f32c2..76189ea90bfb 100644
--- a/test/SemaTemplate/instantiation-default-3.cpp
+++ b/test/SemaTemplate/instantiation-default-3.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> struct A { };
diff --git a/test/SemaTemplate/instantiation-depth-exception-spec.cpp b/test/SemaTemplate/instantiation-depth-exception-spec.cpp
new file mode 100644
index 000000000000..6caa4a60e6f8
--- /dev/null
+++ b/test/SemaTemplate/instantiation-depth-exception-spec.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s
+
+template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
+// expected-error 16{{call to function 'go' that is neither visible}} \
+// expected-note 16{{'go' should be declared prior to the call site}} \
+// expected-error {{recursive template instantiation exceeded maximum depth of 16}}
+
+void f() {
+ int k = go(0); // \
+ // expected-note {{in instantiation of exception specification for 'go<int>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiation-depth-subst-2.cpp b/test/SemaTemplate/instantiation-depth-subst-2.cpp
index a29d6b5a1b4c..ef2a5c765d9c 100644
--- a/test/SemaTemplate/instantiation-depth-subst-2.cpp
+++ b/test/SemaTemplate/instantiation-depth-subst-2.cpp
@@ -1,9 +1,6 @@
// RUN: %clang_cc1 -verify %s -ftemplate-depth 2
template<int N> struct S { };
-// FIXME: We produce the same 'instantiation depth' error here many times
-// (2^(depth+1) in total), due to additional lookups performed as part of
-// error recovery in DiagnoseTwoPhaseOperatorLookup.
-template<typename T> S<T() + T()> operator+(T, T); // expected-error 8{{}} expected-note 10{{}}
+template<typename T> S<T() + T()> operator+(T, T); // expected-error {{instantiation exceeded maximum depth}} expected-note 3{{while substituting}}
S<0> s;
-int k = s + s; // expected-error {{invalid operands to binary expression}}
+int k = s + s;
diff --git a/test/SemaTemplate/instantiation-depth-subst.cpp b/test/SemaTemplate/instantiation-depth-subst.cpp
index 58e637411c66..06795f9514d3 100644
--- a/test/SemaTemplate/instantiation-depth-subst.cpp
+++ b/test/SemaTemplate/instantiation-depth-subst.cpp
@@ -3,7 +3,7 @@
// PR9793
template<typename T> auto f(T t) -> decltype(f(t)); // \
// expected-error {{recursive template instantiation exceeded maximum depth of 2}} \
-// expected-note 3 {{while substituting}} \
-// expected-note {{candidate}}
+// expected-note 3 {{while substituting}}
-int k = f(0); // expected-error {{no matching function for call to 'f'}}
+struct S {};
+int k = f(S{});
diff --git a/test/SemaTemplate/issue150.cpp b/test/SemaTemplate/issue150.cpp
index af3b93c907c1..a04be35a29e7 100644
--- a/test/SemaTemplate/issue150.cpp
+++ b/test/SemaTemplate/issue150.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
// Core issue 150: Template template parameters and default arguments
diff --git a/test/SemaTemplate/lookup-dependent-bases.cpp b/test/SemaTemplate/lookup-dependent-bases.cpp
index 2710caf22125..4fcfbd196407 100644
--- a/test/SemaTemplate/lookup-dependent-bases.cpp
+++ b/test/SemaTemplate/lookup-dependent-bases.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// expected-no-diagnostics
class C {
public:
diff --git a/test/SemaTemplate/member-access-ambig.cpp b/test/SemaTemplate/member-access-ambig.cpp
index f8a01d5fff2a..5c2d7617033f 100644
--- a/test/SemaTemplate/member-access-ambig.cpp
+++ b/test/SemaTemplate/member-access-ambig.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-comparison %s
// PR8439
class A
@@ -43,3 +43,22 @@ namespace PR11134 {
};
}
+namespace AddrOfMember {
+ struct A { int X; };
+ typedef int (A::*P);
+ template<typename T> struct S : T {
+ void f() {
+ P(&T::X) // expected-error {{cannot cast from type 'int *' to member pointer type 'P'}}
+ == &A::X;
+ }
+ };
+
+ void g() {
+ S<A>().f(); // ok, &T::X is 'int (A::*)', not 'int *', even though T is a base class
+ }
+
+ struct B : A { static int X; };
+ void h() {
+ S<B>().f(); // expected-note {{here}}
+ }
+}
diff --git a/test/SemaTemplate/member-initializers.cpp b/test/SemaTemplate/member-initializers.cpp
index 40f56b34dae0..6791048874f8 100644
--- a/test/SemaTemplate/member-initializers.cpp
+++ b/test/SemaTemplate/member-initializers.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T> struct A {
A() : j(10), i(10) { }
diff --git a/test/SemaTemplate/nested-linkage.cpp b/test/SemaTemplate/nested-linkage.cpp
index 6c0791c2efc8..59746ea9c10e 100644
--- a/test/SemaTemplate/nested-linkage.cpp
+++ b/test/SemaTemplate/nested-linkage.cpp
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
extern "C" { extern "C++" { template<class C> C x(); } }
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
index 7849bae4d571..47502536caf7 100644
--- a/test/SemaTemplate/nested-template.cpp
+++ b/test/SemaTemplate/nested-template.cpp
@@ -155,3 +155,8 @@ namespace PR10924 {
{
};
}
+
+class Outer1 {
+ template <typename T> struct X;
+ template <typename T> int X<T>::func() {} // expected-error{{out-of-line definition of 'func' from class 'X<T>' without definition}}
+};
diff --git a/test/SemaTemplate/operator-function-id-template.cpp b/test/SemaTemplate/operator-function-id-template.cpp
index 9a0884e8136d..96dfe26cc596 100644
--- a/test/SemaTemplate/operator-function-id-template.cpp
+++ b/test/SemaTemplate/operator-function-id-template.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T>
struct A {
diff --git a/test/SemaTemplate/overload-uneval.cpp b/test/SemaTemplate/overload-uneval.cpp
index 8d8a2f42cf28..c952ef8ec7c4 100644
--- a/test/SemaTemplate/overload-uneval.cpp
+++ b/test/SemaTemplate/overload-uneval.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s
+// expected-no-diagnostics
// Tests that overload resolution is treated as an unevaluated context.
// PR5541
diff --git a/test/SemaTemplate/pragma-ms_struct.cpp b/test/SemaTemplate/pragma-ms_struct.cpp
index f04dc5ccae45..fe0b494b9a57 100644
--- a/test/SemaTemplate/pragma-ms_struct.cpp
+++ b/test/SemaTemplate/pragma-ms_struct.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-osx10.7.0 %s
+// expected-no-diagnostics
#pragma ms_struct on
diff --git a/test/SemaTemplate/temp_class_spec_blocks.cpp b/test/SemaTemplate/temp_class_spec_blocks.cpp
index b7b96df69ba5..4b99716d582e 100644
--- a/test/SemaTemplate/temp_class_spec_blocks.cpp
+++ b/test/SemaTemplate/temp_class_spec_blocks.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+// expected-no-diagnostics
template<typename T>
struct is_unary_block {
static const bool value = false;
diff --git a/test/SemaTemplate/template-class-traits.cpp b/test/SemaTemplate/template-class-traits.cpp
index 471029445256..63ce8f434da3 100644
--- a/test/SemaTemplate/template-class-traits.cpp
+++ b/test/SemaTemplate/template-class-traits.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
diff --git a/test/SemaTemplate/typo-dependent-name.cpp b/test/SemaTemplate/typo-dependent-name.cpp
index 96554e9dcf4a..78cedd0c98ca 100644
--- a/test/SemaTemplate/typo-dependent-name.cpp
+++ b/test/SemaTemplate/typo-dependent-name.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
template<typename T>
struct Base {
diff --git a/test/SemaTemplate/unresolved-construct.cpp b/test/SemaTemplate/unresolved-construct.cpp
index bb9ed8e4e081..ef010fbdd174 100644
--- a/test/SemaTemplate/unresolved-construct.cpp
+++ b/test/SemaTemplate/unresolved-construct.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
class A
{
public:
diff --git a/test/Tooling/clang-check-ast-dump.cpp b/test/Tooling/clang-check-ast-dump.cpp
index e29072bcfe87..43686bd250c2 100644
--- a/test/Tooling/clang-check-ast-dump.cpp
+++ b/test/Tooling/clang-check-ast-dump.cpp
@@ -26,6 +26,9 @@
// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::n "%s" -- 2>&1 | FileCheck -check-prefix CHECK-ATTR %s
// CHECK-ATTR: test_namespace
// CHECK-ATTR-NEXT: int n __attribute__((aligned((BinaryOperator
+//
+// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::AfterNullNode "%s" -- 2>&1 | FileCheck -check-prefix CHECK-AFTER-NULL %s
+// CHECK-AFTER-NULL: class AfterNullNode
namespace test_namespace {
@@ -37,4 +40,10 @@ public:
int n __attribute__((aligned(1+1)));
};
+// Used to fail with -ast-dump-filter X
+template<template<typename T> class C> class Z {};
+
+// Check that traversal continues after the previous construct.
+class AfterNullNode {};
+
}
diff --git a/test/lit.cfg b/test/lit.cfg
index 7bc9620926fa..e91e66052e27 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -4,6 +4,7 @@ import os
import platform
import re
import subprocess
+import tempfile
# Configuration file for the 'lit' test runner.
@@ -165,11 +166,6 @@ def inferClang(PATH):
return clang
-# When running under valgrind, we mangle '-vg' onto the end of the triple so we
-# can check it with XFAIL and XTARGET.
-if lit.useValgrind:
- config.target_triple += '-vg'
-
config.clang = inferClang(config.environment['PATH']).replace('\\', '/')
if not lit.quiet:
lit.note('using clang: %r' % config.clang)
@@ -191,7 +187,7 @@ config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s'
getClangBuiltinIncludeDir(config.clang))) )
config.substitutions.append( ('%clangxx', ' ' + config.clang +
- ' -ccc-clang-cxx -ccc-cxx '))
+ ' -ccc-cxx '))
config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') )
@@ -222,10 +218,29 @@ if platform.system() not in ['FreeBSD']:
if platform.system() not in ['Windows'] or lit.getBashPath() != '':
config.available_features.add('shell')
-# ANSI escape sequences in non-dump terminal
+# For tests that require Darwin to run.
+if platform.system() in ['Darwin']:
+ config.available_features.add('system-darwin')
+
+# ANSI escape sequences in non-dumb terminal
if platform.system() not in ['Windows']:
config.available_features.add('ansi-escape-sequences')
+# 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())
+ os.close(handle)
+ os.remove(path)
+ return isInsensitive
+
+if is_filesystem_case_insensitive():
+ config.available_features.add('case-insensitive-filesystem')
+
+# [PR8833] LLP64-incompatible tests
+if not re.match(r'^x86_64.*-(win32|mingw32)$', config.target_triple):
+ config.available_features.add('LP64')
+
# Registered Targets
def get_llc_props(tool):
set_of_targets = set()
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 3a6fef5575ce..cccff5d22f67 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -10,7 +10,5 @@ add_subdirectory(clang-check)
# subdirectory. It contains tools developed as part of the Clang/LLVM project
# on top of the Clang tooling platform. We keep them in a separate repository
# to keep the primary Clang repository small and focused.
-if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/extra AND
- EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extra/CMakeLists.txt)
- add_subdirectory(extra)
-endif()
+# It also may be included by LLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR.
+add_llvm_external_project(clang-tools-extra extra)
diff --git a/tools/Makefile b/tools/Makefile
index e7aa2fa4ffa0..23197a15b4c1 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -17,4 +17,9 @@ DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
# Recurse into the extra repository of tools if present.
OPTIONAL_DIRS := extra
+ifeq ($(BUILD_CLANG_ONLY),YES)
+ DIRS := driver libclang c-index-test
+ OPTIONAL_DIRS :=
+endif
+
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index f36b14a679d7..a7ce58684902 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -12,5 +12,5 @@ add_clang_executable(arcmt-test
target_link_libraries(arcmt-test
clangARCMigrate
clangEdit
- clangRewrite
+ clangRewriteCore
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index 719da75869e8..06e20165d76a 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -18,7 +18,7 @@ NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clangARCMigrate.a clangRewrite.a \
+USEDLIBS = clangARCMigrate.a clangRewriteCore.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 3983c249022e..b745893922c6 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -105,11 +105,12 @@ public:
static bool checkForMigration(StringRef resourcesPath,
ArrayRef<const char *> Args) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
// Chain in -verify checker, if requested.
VerifyDiagnosticConsumer *verifyDiag = 0;
if (VerifyDiags) {
@@ -150,11 +151,12 @@ static bool performTransformations(StringRef resourcesPath,
if (checkForMigration(resourcesPath, Args))
return true;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient));
CompilerInvocation origCI;
if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index b59afdac16da..3372daebcb86 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -22,7 +22,13 @@ NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clang.a clangARCMigrate.a clangRewrite.a \
+
+# Note that 'USEDLIBS' must include all of the core clang libraries
+# as clang.dll is unavailable on cygming yet.
+USEDLIBS = clang.a \
+ clangARCMigrate.a \
+ clangRewriteFrontend.a \
+ clangRewriteCore.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 6379194c55db..6f28c546cf37 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -7,6 +7,13 @@ add_clang_executable(c-index-test
c-index-test.c
)
+if(NOT MSVC)
+ set_property(
+ SOURCE c-index-test.c
+ PROPERTY COMPILE_FLAGS "-std=c89"
+ )
+endif()
+
target_link_libraries(c-index-test
libclang
)
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 09eff0f095e6..b81678bf6edc 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -17,9 +17,6 @@ INTERNAL_TOOL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-# Don't install this. It is used for tests.
-NO_INSTALL = 1
-
# Include this here so we can get the configuration of the targets that have
# been configured for construction. We have to do this early so we can set up
# LINK_COMPONENTS before including Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 5df21ec2a85d..3e4404cbaa09 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -512,8 +512,7 @@ static void ValidateCommentXML(const char *Str,
#endif
}
-static void PrintCursorComments(CXTranslationUnit TU,
- CXCursor Cursor,
+static void PrintCursorComments(CXCursor Cursor,
CommentXMLValidationData *ValidationData) {
{
CXString RawComment;
@@ -543,7 +542,7 @@ static void PrintCursorComments(CXTranslationUnit TU,
clang_FullComment_getAsHTML(Comment));
{
CXString XML;
- XML = clang_FullComment_getAsXML(TU, Comment);
+ XML = clang_FullComment_getAsXML(Comment);
PrintCXStringWithPrefix("FullCommentAsXML", XML);
ValidateCommentXML(clang_getCString(XML), ValidationData);
clang_disposeString(XML);
@@ -554,6 +553,19 @@ static void PrintCursorComments(CXTranslationUnit TU,
}
}
+typedef struct {
+ unsigned line;
+ unsigned col;
+} LineCol;
+
+static int lineCol_cmp(const void *p1, const void *p2) {
+ const LineCol *lhs = p1;
+ const LineCol *rhs = p2;
+ if (lhs->line != rhs->line)
+ return (int)lhs->line - (int)rhs->line;
+ return (int)lhs->col - (int)rhs->col;
+}
+
static void PrintCursor(CXCursor Cursor,
CommentXMLValidationData *ValidationData) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
@@ -718,13 +730,21 @@ static void PrintCursor(CXCursor Cursor,
clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
if (num_overridden) {
unsigned I;
+ LineCol lineCols[50];
+ assert(num_overridden <= 50);
printf(" [Overrides ");
for (I = 0; I != num_overridden; ++I) {
CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
+ lineCols[I].line = line;
+ lineCols[I].col = column;
+ }
+ /* Make the order of the override list deterministic. */
+ qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
+ for (I = 0; I != num_overridden; ++I) {
if (I)
printf(", ");
- printf("@%d:%d", line, column);
+ printf("@%d:%d", lineCols[I].line, lineCols[I].col);
}
printf("]");
clang_disposeOverriddenCursors(overridden);
@@ -760,7 +780,7 @@ static void PrintCursor(CXCursor Cursor,
PrintRange(RefNameRange, "RefName");
}
- PrintCursorComments(TU, Cursor, ValidationData);
+ PrintCursorComments(Cursor, ValidationData);
}
}
@@ -1935,6 +1955,31 @@ static int inspect_cursor_at(int argc, const char **argv) {
printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
if (clang_Cursor_isDynamicCall(Cursor))
printf(" Dynamic-call");
+ if (Cursor.kind == CXCursor_ObjCMessageExpr) {
+ CXType T = clang_Cursor_getReceiverType(Cursor);
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" Receiver-type=%s", clang_getCString(S));
+ clang_disposeString(S);
+ }
+
+ {
+ CXModule mod = clang_Cursor_getModule(Cursor);
+ CXString name;
+ unsigned i, numHeaders;
+ if (mod) {
+ name = clang_Module_getFullName(mod);
+ numHeaders = clang_Module_getNumTopLevelHeaders(mod);
+ printf(" ModuleName=%s Headers(%d):",
+ clang_getCString(name), numHeaders);
+ clang_disposeString(name);
+ for (i = 0; i < numHeaders; ++i) {
+ CXFile file = clang_Module_getTopLevelHeader(mod, i);
+ CXString filename = clang_getFileName(file);
+ printf("\n%s", clang_getCString(filename));
+ clang_disposeString(filename);
+ }
+ }
+ }
if (completionString != NULL) {
printf("\nCompletion string: ");
@@ -2062,12 +2107,49 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+#define MAX_IMPORTED_ASTFILES 200
+
+typedef struct {
+ char **filenames;
+ unsigned num_files;
+} ImportedASTFilesData;
+
+static ImportedASTFilesData *importedASTs_create() {
+ ImportedASTFilesData *p;
+ p = malloc(sizeof(ImportedASTFilesData));
+ p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
+ p->num_files = 0;
+ return p;
+}
+
+static void importedASTs_dispose(ImportedASTFilesData *p) {
+ unsigned i;
+ if (!p)
+ return;
+
+ for (i = 0; i < p->num_files; ++i)
+ free(p->filenames[i]);
+ free(p->filenames);
+ free(p);
+}
+
+static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
+ unsigned i;
+ assert(p && file);
+ for (i = 0; i < p->num_files; ++i)
+ if (strcmp(file, p->filenames[i]) == 0)
+ return;
+ assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
+ p->filenames[p->num_files++] = strdup(file);
+}
+
typedef struct {
const char *check_prefix;
int first_check_printed;
int fail_for_error;
int abort;
const char *main_filename;
+ ImportedASTFilesData *importedASTs;
} IndexData;
static void printCheck(IndexData *data) {
@@ -2098,7 +2180,7 @@ static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
index_data = (IndexData *)client_data;
clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
if (line == 0) {
- printf("<null loc>");
+ printf("<invalid>");
return;
}
if (!file) {
@@ -2186,6 +2268,7 @@ static const char *getEntityKindString(CXIdxEntityKind kind) {
case CXIdxEntity_CXXDestructor: return "destructor";
case CXIdxEntity_CXXConversionFunction: return "conversion-func";
case CXIdxEntity_CXXTypeAlias: return "type-alias";
+ case CXIdxEntity_CXXInterface: return "c++-__interface";
}
assert(0 && "Garbage entity kind");
return 0;
@@ -2323,7 +2406,37 @@ static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
printf(" | name: \"%s\"", info->filename);
printf(" | hash loc: ");
printCXIndexLoc(info->hashLoc, client_data);
- printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled);
+ printf(" | isImport: %d | isAngled: %d | isModule: %d\n",
+ info->isImport, info->isAngled, info->isModuleImport);
+
+ return (CXIdxClientFile)info->file;
+}
+
+static CXIdxClientFile index_importedASTFile(CXClientData client_data,
+ const CXIdxImportedASTFileInfo *info) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ if (index_data->importedASTs) {
+ CXString filename = clang_getFileName(info->file);
+ importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
+ clang_disposeString(filename);
+ }
+
+ printf("[importedASTFile]: ");
+ printCXIndexFile((CXIdxClientFile)info->file);
+ if (info->module) {
+ CXString name = clang_Module_getFullName(info->module);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printf(" | name: \"%s\"", clang_getCString(name));
+ printf(" | isImplicit: %d\n", info->isImplicit);
+ clang_disposeString(name);
+ } else {
+ /* PCH file, the rest are not relevant. */
+ printf("\n");
+ }
return (CXIdxClientFile)info->file;
}
@@ -2458,7 +2571,7 @@ static IndexerCallbacks IndexCB = {
index_diagnostic,
index_enteredMainFile,
index_ppIncludedFile,
- 0, /*importedASTFile*/
+ index_importedASTFile,
index_startedTranslationUnit,
index_indexDeclaration,
index_indexEntityReference
@@ -2475,7 +2588,7 @@ static unsigned getIndexOptions(void) {
return index_opts;
}
-static int index_file(int argc, const char **argv) {
+static int index_file(int argc, const char **argv, int full) {
const char *check_prefix;
CXIndex Idx;
CXIndexAction idxAction;
@@ -2508,15 +2621,40 @@ static int index_file(int argc, const char **argv) {
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = 0;
+
+ if (full)
+ index_data.importedASTs = importedASTs_create();
index_opts = getIndexOptions();
idxAction = clang_IndexAction_create(Idx);
result = clang_indexSourceFile(idxAction, &index_data,
&IndexCB,sizeof(IndexCB), index_opts,
- 0, argv, argc, 0, 0, 0, 0);
+ 0, argv, argc, 0, 0, 0,
+ getDefaultParsingOptions());
if (index_data.fail_for_error)
result = -1;
+
+ if (full) {
+ CXTranslationUnit TU;
+ unsigned i;
+
+ for (i = 0; i < index_data.importedASTs->num_files; ++i) {
+ if (!CreateTranslationUnit(Idx, index_data.importedASTs->filenames[i],
+ &TU)) {
+ result = -1;
+ goto finished;
+ }
+ result = clang_indexTranslationUnit(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB),
+ index_opts, TU);
+ clang_disposeTranslationUnit(TU);
+ }
+ }
+finished:
+ importedASTs_dispose(index_data.importedASTs);
clang_IndexAction_dispose(idxAction);
clang_disposeIndex(Idx);
return result;
@@ -2551,6 +2689,7 @@ static int index_tu(int argc, const char **argv) {
return 1;
}
idxAction = 0;
+ TU = 0;
result = 1;
if (!CreateTranslationUnit(Idx, argv[0], &TU))
@@ -2560,6 +2699,8 @@ static int index_tu(int argc, const char **argv) {
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = 0;
index_opts = getIndexOptions();
idxAction = clang_IndexAction_create(Idx);
@@ -2571,6 +2712,7 @@ static int index_tu(int argc, const char **argv) {
finished:
clang_IndexAction_dispose(idxAction);
+ clang_disposeTranslationUnit(TU);
clang_disposeIndex(Idx);
return result;
@@ -2994,7 +3136,8 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
argc - num_unsaved_files,
unsaved_files,
num_unsaved_files,
- CXTranslationUnit_Incomplete);
+ CXTranslationUnit_Incomplete |
+ CXTranslationUnit_ForSerialization);
if (!TU) {
fprintf(stderr, "Unable to load translation unit!\n");
free_remapped_files(unsaved_files, num_unsaved_files);
@@ -3212,8 +3355,10 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
- " c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n");
+ fprintf(stderr,
" c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
+ " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
" c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n");
@@ -3271,7 +3416,9 @@ int cindextest_main(int argc, const char **argv) {
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
- return index_file(argc - 2, argv + 2);
+ return index_file(argc - 2, argv + 2, /*full=*/0);
+ if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
+ return index_file(argc - 2, argv + 2, /*full=*/1);
if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
return index_tu(argc - 2, argv + 2);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index 85e229f45a4e..f5d7616fc4f7 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_executable(clang-check
target_link_libraries(clang-check
clangTooling
clangBasic
+ clangRewriteFrontend
)
install(TARGETS clang-check
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index 9e58077b5a0e..6c081ac0769e 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -1,4 +1,4 @@
-//===- tools/clang-check/ClangCheck.cpp - Clang check tool ----------------===//
+//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements a clang-check tool that runs the
-// clang::SyntaxOnlyAction over a number of translation units.
+// This file implements a clang-check tool that runs clang based on the info
+// stored in a compilation database.
//
// This tool uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
@@ -16,20 +16,24 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/CommandLine.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CommandLineClangTool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
-static const char *MoreHelpText =
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::extrahelp MoreHelp(
"\tFor example, to run clang-check on all files in a subtree of the\n"
"\tsource tree, use:\n"
"\n"
@@ -41,26 +45,90 @@ static const char *MoreHelpText =
"\n"
"\tNote, that path/in/subtree and current directory should follow the\n"
"\trules described above.\n"
- "\n";
+ "\n"
+);
+
+static OwningPtr<OptTable> Options(createDriverOptTable());
+static cl::opt<bool> ASTDump(
+ "ast-dump",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)));
+static cl::opt<bool> ASTList(
+ "ast-list",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_list)));
+static cl::opt<bool> ASTPrint(
+ "ast-print",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_print)));
+static cl::opt<std::string> ASTDumpFilter(
+ "ast-dump-filter",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)));
+
+static cl::opt<bool> Fixit(
+ "fixit",
+ cl::desc(Options->getOptionHelpText(options::OPT_fixit)));
+static cl::opt<bool> FixWhatYouCan(
+ "fix-what-you-can",
+ cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)));
namespace {
-class ActionFactory {
+
+// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
+// into a header file and reuse that.
+class FixItOptions : public clang::FixItOptions {
+public:
+ FixItOptions() {
+ FixWhatYouCan = ::FixWhatYouCan;
+ }
+
+ std::string RewriteFilename(const std::string& filename, int &fd) {
+ assert(llvm::sys::path::is_absolute(filename) &&
+ "clang-fixit expects absolute paths only.");
+
+ // We don't need to do permission checking here since clang will diagnose
+ // any I/O errors itself.
+
+ fd = -1; // No file descriptor for file.
+
+ return filename;
+ }
+};
+
+/// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
+/// in the final error counts.
+///
+/// This has the side-effect that clang-check -fixit exits with code 0 on
+/// successfully fixing all errors.
+class FixItRewriter : public clang::FixItRewriter {
+public:
+ FixItRewriter(clang::DiagnosticsEngine& Diags,
+ clang::SourceManager& SourceMgr,
+ const clang::LangOptions& LangOpts,
+ clang::FixItOptions* FixItOpts)
+ : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
+ }
+
+ virtual bool IncludeInDiagnosticCounts() const { return false; }
+};
+
+/// \brief Subclasses \c clang::FixItAction so that we can install the custom
+/// \c FixItRewriter.
+class FixItAction : public clang::FixItAction {
public:
- ActionFactory()
- : Options(createDriverOptTable()),
- ASTDump(
- "ast-dump",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_dump))),
- ASTList(
- "ast-list",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_list))),
- ASTPrint(
- "ast-print",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_print))),
- ASTDumpFilter(
- "ast-dump-filter",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter))) {}
+ virtual bool BeginSourceFileAction(clang::CompilerInstance& CI,
+ StringRef Filename) {
+ FixItOpts.reset(new FixItOptions);
+ Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts(), FixItOpts.get()));
+ return true;
+ }
+};
+
+} // namespace
+// Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6.
+// "Non-global symbol: ... can't be a weak_definition"
+namespace clang_check {
+class ClangCheckActionFactory {
+public:
clang::ASTConsumer *newASTConsumer() {
if (ASTList)
return clang::CreateASTDeclNodeLister();
@@ -70,19 +138,15 @@ public:
return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
return new clang::ASTConsumer();
}
-private:
- OwningPtr<OptTable> Options;
- cl::opt<bool> ASTDump;
- cl::opt<bool> ASTList;
- cl::opt<bool> ASTPrint;
- cl::opt<std::string> ASTDumpFilter;
};
}
int main(int argc, const char **argv) {
- ActionFactory Factory;
- CommandLineClangTool Tool;
- cl::extrahelp MoreHelp(MoreHelpText);
- Tool.initialize(argc, 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));
}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
index 6775c65a6453..28f94f626072 100644
--- a/tools/clang-check/Makefile
+++ b/tools/clang-check/Makefile
@@ -18,7 +18,7 @@ include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
- clangEdit.a clangAST.a clangLex.a clangBasic.a
+ clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
+ clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
-
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index 7162451b4e73..abd69fd0af61 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -60,7 +60,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
- new DiagnosticsEngine(DiagIDs, DiagsBuffer));
+ new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
// Try to build a CompilerInvocation.
OwningPtr<CompilerInvocation> Invocation(
@@ -71,7 +71,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// Build the diagnostics parser
IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
- CompilerInstance::createDiagnostics(Invocation->getDiagnosticOpts(),
+ CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
argc, argv);
if (!FinalDiags)
return NULL;
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index 9db2c26dd92d..bf9f766c309a 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -14,11 +14,13 @@
#include "DiagTool.h"
#include "DiagnosticNames.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/DenseSet.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
+#include "llvm/Support/Process.h"
DEF_DIAGTOOL("tree",
"Show warning flags in a tree view",
@@ -31,11 +33,39 @@ static void printUsage() {
llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n";
}
+static bool showColors(llvm::raw_ostream &out) {
+ if (&out != &llvm::errs() && &out != &llvm::outs())
+ return false;
+ return llvm::errs().is_displayed() && llvm::outs().is_displayed();
+}
+
+static void setColor(bool ShowColors, llvm::raw_ostream &out,
+ llvm::raw_ostream::Colors Color) {
+ if (ShowColors)
+ out << llvm::sys::Process::OutputColor(Color, false, false);
+}
+
+static void resetColor(bool ShowColors, llvm::raw_ostream &out) {
+ if (ShowColors)
+ out << llvm::sys::Process::ResetColor();
+}
+
+static clang::DiagnosticsEngine::Level getLevel(unsigned DiagID) {
+ // FIXME: This feels like a hack.
+ static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
+ new DiagnosticOptions);
+ return Diags.getDiagnosticLevel(DiagID, SourceLocation());
+}
+
static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group,
bool FlagsOnly, unsigned Indent = 0) {
out.indent(Indent * 2);
+
+ bool ShowColors = showColors(out);
+ setColor(ShowColors, out, llvm::raw_ostream::YELLOW);
out << "-W" << Group.getName() << "\n";
-
+ resetColor(ShowColors, out);
+
++Indent;
for (GroupRecord::subgroup_iterator I = Group.subgroup_begin(),
E = Group.subgroup_end();
@@ -47,8 +77,15 @@ static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group,
for (GroupRecord::diagnostics_iterator I = Group.diagnostics_begin(),
E = Group.diagnostics_end();
I != E; ++I) {
+ if (ShowColors) {
+ if (getLevel(I->DiagID) != DiagnosticsEngine::Ignored) {
+ setColor(ShowColors, out, llvm::raw_ostream::GREEN);
+ }
+ }
out.indent(Indent * 2);
- out << I->getName() << "\n";
+ out << I->getName();
+ resetColor(ShowColors, out);
+ out << "\n";
}
}
}
@@ -106,7 +143,7 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
++argv;
}
}
-
+
bool ShowAll = false;
StringRef RootGroup;
@@ -127,6 +164,14 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
return -1;
}
+ if (showColors(out)) {
+ out << '\n';
+ setColor(true, out, llvm::raw_ostream::GREEN);
+ out << "GREEN";
+ resetColor(true, out);
+ out << " = enabled by default\n\n";
+ }
+
if (ShowAll)
return showAll(out, FlagsOnly);
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 71d77669caec..2545610477f2 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -29,7 +29,8 @@ target_link_libraries(clang
clangParse
clangEdit
clangARCMigrate
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangSema
clangSerialization
clangStaticAnalyzerFrontend
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 270d4fdda863..f07b0f2c92f7 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -35,7 +35,8 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
clangStaticAnalyzerCore.a \
- clangAnalysis.a clangARCMigrate.a clangRewrite.a \
+ clangAnalysis.a clangARCMigrate.a \
+ clangRewriteFrontend.a clangRewriteCore.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index f8e8a6b4f6bf..f1968560c80f 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -47,86 +47,11 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-// FIXME: Define the need for this testing away.
-static int cc1_test(DiagnosticsEngine &Diags,
- const char **ArgBegin, const char **ArgEnd) {
- using namespace clang::driver;
-
- llvm::errs() << "cc1 argv:";
- for (const char **i = ArgBegin; i != ArgEnd; ++i)
- llvm::errs() << " \"" << *i << '"';
- llvm::errs() << "\n";
-
- // Parse the arguments.
- OptTable *Opts = createDriverOptTable();
- unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
- MissingArgIndex, MissingArgCount);
-
- // Check for missing argument error.
- if (MissingArgCount)
- Diags.Report(clang::diag::err_drv_missing_argument)
- << Args->getArgString(MissingArgIndex) << MissingArgCount;
-
- // Dump the parsed arguments.
- llvm::errs() << "cc1 parsed options:\n";
- for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
- it != ie; ++it)
- (*it)->dump();
-
- // Create a compiler invocation.
- llvm::errs() << "cc1 creating invocation.\n";
- CompilerInvocation Invocation;
- if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags))
- return 1;
-
- // Convert the invocation back to argument strings.
- std::vector<std::string> InvocationArgs;
- Invocation.toArgs(InvocationArgs);
-
- // Dump the converted arguments.
- SmallVector<const char*, 32> Invocation2Args;
- llvm::errs() << "invocation argv :";
- for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
- Invocation2Args.push_back(InvocationArgs[i].c_str());
- llvm::errs() << " \"" << InvocationArgs[i] << '"';
- }
- llvm::errs() << "\n";
-
- // Convert those arguments to another invocation, and check that we got the
- // same thing.
- CompilerInvocation Invocation2;
- if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
- Invocation2Args.end(), Diags))
- return 1;
-
- // FIXME: Implement CompilerInvocation comparison.
- if (true) {
- //llvm::errs() << "warning: Invocations differ!\n";
-
- std::vector<std::string> Invocation2Args;
- Invocation2.toArgs(Invocation2Args);
- llvm::errs() << "invocation2 argv:";
- for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
- llvm::errs() << " \"" << Invocation2Args[i] << '"';
- llvm::errs() << "\n";
- }
-
- return 0;
-}
-
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- // Run clang -cc1 test.
- if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
- DiagnosticsEngine Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(),
- DiagnosticOptions()));
- return cc1_test(Diags, ArgBegin + 1, ArgEnd);
- }
-
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
@@ -135,8 +60,9 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
- DiagnosticsEngine Diags(DiagID, DiagsBuffer);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
bool Success;
Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
ArgBegin, ArgEnd, Diags);
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 7dd54bd6a028..5587e404955c 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -19,9 +19,9 @@
#include "clang/Driver/CC1AsOptions.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -51,7 +51,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;
@@ -189,7 +189,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
ie = Args->filtered_end(); it != ie; ++it, First=false) {
const Arg *A = it;
if (First)
- Opts.InputFile = A->getValue(*Args);
+ Opts.InputFile = A->getValue();
else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
Success = false;
@@ -201,7 +201,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.LLVMArgs.push_back("-fatal-assembler-warnings");
Opts.OutputPath = Args->getLastArgValue(OPT_o);
if (Arg *A = Args->getLastArg(OPT_filetype)) {
- StringRef Name = A->getValue(*Args);
+ StringRef Name = A->getValue();
unsigned OutputType = StringSwitch<unsigned>(Name)
.Case("asm", FT_Asm)
.Case("null", FT_Null)
@@ -329,7 +329,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
- MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
@@ -343,7 +343,7 @@ 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);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
CE, Opts.RelaxAll,
Opts.NoExecStack));
@@ -394,11 +394,12 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
InitializeAllAsmParsers();
// Construct our diagnostic client.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
+ = new TextDiagnosticPrinter(errs(), &*DiagOpts);
DiagClient->setPrefix("clang -cc1as");
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- DiagnosticsEngine Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 12a93298c08a..81979ec72684 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Compilation.h"
@@ -19,7 +20,6 @@
#include "clang/Driver/Option.h"
#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
@@ -375,7 +375,7 @@ int main(int argc_, const char **argv_) {
llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
- DiagnosticOptions DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
{
// Note that ParseDiagnosticArgs() uses the cc1 option table.
OwningPtr<OptTable> CC1Opts(createDriverOptTable());
@@ -385,17 +385,17 @@ int main(int argc_, const char **argv_) {
// 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.
- (void) ParseDiagnosticArgs(DiagOpts, *Args);
+ (void) ParseDiagnosticArgs(*DiagOpts, *Args);
}
// Now we can create the DiagnosticsEngine with a properly-filled-out
// DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
+ = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- DiagnosticsEngine Diags(DiagID, DiagClient);
- ProcessWarningOptions(Diags, DiagOpts);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+ ProcessWarningOptions(Diags, *DiagOpts);
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index bd27b4cad123..3a6c408bff1f 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -145,8 +145,8 @@ RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
///
/// \param Cursor the cursor to visit.
///
-/// \param CheckRegionOfInterest if true, then the caller already checked that
-/// this cursor is within the region of interest.
+/// \param CheckedRegionOfInterest if true, then the caller already checked
+/// that this cursor is within the region of interest.
///
/// \returns true if the visitation should be aborted, false if it
/// should continue.
@@ -182,8 +182,13 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
case CXChildVisit_Continue:
return false;
- case CXChildVisit_Recurse:
- return VisitChildren(Cursor);
+ case CXChildVisit_Recurse: {
+ bool ret = VisitChildren(Cursor);
+ if (PostChildrenVisitor)
+ if (PostChildrenVisitor(Cursor, ClientData))
+ return true;
+ return ret;
+ }
}
llvm_unreachable("Invalid CXChildVisitResult!");
@@ -566,6 +571,16 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
continue;
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
+ // Ignore synthesized ivars here, otherwise if we have something like:
+ // @synthesize prop = _prop;
+ // and '_prop' is not declared, we will encounter a '_prop' ivar before
+ // encountering the 'prop' synthesize declaration and we will think that
+ // we passed the region-of-interest.
+ if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) {
+ if (ivarD->getSynthesize())
+ continue;
+ }
+
// FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
// declarations is a mismatch with the compiler semantics.
if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
@@ -1006,12 +1021,12 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
// Visit synthesized methods since they will be skipped when visiting
// the @interface.
if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
- if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
- if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
@@ -1312,7 +1327,12 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
if (Expr *E = TAL.getSourceDeclExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
-
+
+ case TemplateArgument::NullPtr:
+ if (Expr *E = TAL.getSourceNullPtrExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
case TemplateArgument::Expression:
if (Expr *E = TAL.getSourceExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
@@ -1622,6 +1642,7 @@ DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
+DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
#undef DEF_JOB
class DeclVisit : public VisitorJob {
@@ -2198,6 +2219,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
case CXChildVisit_Break: return true;
case CXChildVisit_Continue: break;
case CXChildVisit_Recurse:
+ if (PostChildrenVisitor)
+ WL.push_back(PostChildrenVisit(0, Cursor));
EnqueueWorkList(WL, S);
break;
}
@@ -2314,6 +2337,11 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
}
break;
}
+
+ case VisitorJob::PostChildrenVisitKind:
+ if (PostChildrenVisitor(Parent, ClientData))
+ return true;
+ break;
}
}
return false;
@@ -2528,12 +2556,13 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
bool IncludeBriefCommentsInCodeCompletion
= options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+ bool ForSerialization = options & CXTranslationUnit_ForSerialization;
// Configure the diagnostics.
- DiagnosticOptions DiagOpts;
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
- command_line_args));
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ num_command_line_args,
+ command_line_args));
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -2615,6 +2644,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
/*AllowPCHWithCompilerErrors=*/true,
SkipFunctionBodies,
/*UserFilesAreVolatile=*/true,
+ ForSerialization,
&ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {
@@ -2689,7 +2719,8 @@ static void clang_saveTranslationUnit_Impl(void *UserData) {
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
setThreadBackgroundPriority();
- STUI->result = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ bool hadError = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None;
}
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
@@ -3018,6 +3049,10 @@ static CXString getDeclSpelling(Decl *D) {
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return createCXString(Property->getIdentifier()->getName());
+ if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D))
+ if (Module *Mod = ImportD->getImportedModule())
+ return createCXString(Mod->getFullModuleName());
+
return createCXString("");
}
@@ -3219,6 +3254,18 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc());
}
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) {
+ ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs();
+ if (!Locs.empty())
+ return cxloc::translateSourceRange(Ctx,
+ SourceRange(Locs.front(), Locs.back()));
+ }
+ return clang_getNullRange();
+ }
+
// FIXME: A CXCursor_InclusionDirective should give the location of the
// filename, but we don't keep track of this.
@@ -3510,8 +3557,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("BreakStmt");
case CXCursor_ReturnStmt:
return createCXString("ReturnStmt");
- case CXCursor_AsmStmt:
- return createCXString("AsmStmt");
+ case CXCursor_GCCAsmStmt:
+ return createCXString("GCCAsmStmt");
case CXCursor_MSAsmStmt:
return createCXString("MSAsmStmt");
case CXCursor_ObjCAtTryStmt:
@@ -3614,6 +3661,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ObjCDynamicDecl");
case CXCursor_CXXAccessSpecifier:
return createCXString("CXXAccessSpecifier");
+ case CXCursor_ModuleImportDecl:
+ return createCXString("ModuleImport");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3810,7 +3859,8 @@ unsigned clang_isInvalid(enum CXCursorKind K) {
}
unsigned clang_isDeclaration(enum CXCursorKind K) {
- return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
+ return (K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl) ||
+ (K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl);
}
unsigned clang_isReference(enum CXCursorKind K) {
@@ -3957,7 +4007,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
- if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
+ if (!clang_isDeclaration(C.kind))
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
@@ -4092,7 +4142,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
return SourceRange(Start, End);
}
- if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4115,7 +4165,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
/// \brief Retrieves the "raw" cursor extent, which is then extended to include
/// the decl-specifier-seq for declarations.
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
- if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4809,6 +4859,9 @@ typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data);
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data);
+
namespace {
class AnnotateTokensWorker {
AnnotateTokensData &Annotated;
@@ -4820,6 +4873,13 @@ class AnnotateTokensWorker {
CursorVisitor AnnotateVis;
SourceManager &SrcMgr;
bool HasContextSensitiveKeywords;
+
+ struct PostChildrenInfo {
+ CXCursor Cursor;
+ SourceRange CursorRange;
+ unsigned BeforeChildrenTokenIdx;
+ };
+ llvm::SmallVector<PostChildrenInfo, 8> PostChildrenInfos;
bool MoreTokens() const { return TokIdx < NumTokens; }
unsigned NextToken() const { return TokIdx; }
@@ -4848,12 +4908,15 @@ public:
AnnotateTokensVisitor, this,
/*VisitPreprocessorLast=*/true,
/*VisitIncludedEntities=*/false,
- RegionOfInterest),
+ RegionOfInterest,
+ /*VisitDeclsOnly=*/false,
+ AnnotateTokensPostChildrenVisitor),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
+ bool postVisitChildren(CXCursor cursor);
void AnnotateTokens();
/// \brief Determine whether the annotator saw any cursors that have
@@ -4861,6 +4924,10 @@ public:
bool hasContextSensitiveKeywords() const {
return HasContextSensitiveKeywords;
}
+
+ ~AnnotateTokensWorker() {
+ assert(PostChildrenInfos.empty());
+ }
};
}
@@ -5062,7 +5129,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
// Adjust the annotated range based specific declarations.
const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
- if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(cursorK)) {
Decl *D = cxcursor::getCursorDecl(cursor);
SourceLocation StartLoc;
@@ -5121,25 +5188,47 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
}
}
- // Visit children to get their cursor information.
- const unsigned BeforeChildren = NextToken();
- VisitChildren(cursor);
+ // Before recursing into the children keep some state that we are going
+ // to use in the AnnotateTokensWorker::postVisitChildren callback to do some
+ // extra work after the child nodes are visited.
+ // Note that we don't call VisitChildren here to avoid traversing statements
+ // code-recursively which can blow the stack.
+
+ PostChildrenInfo Info;
+ Info.Cursor = cursor;
+ Info.CursorRange = cursorRange;
+ Info.BeforeChildrenTokenIdx = NextToken();
+ PostChildrenInfos.push_back(Info);
+
+ return CXChildVisit_Recurse;
+}
+
+bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) {
+ if (PostChildrenInfos.empty())
+ return false;
+ const PostChildrenInfo &Info = PostChildrenInfos.back();
+ if (!clang_equalCursors(Info.Cursor, cursor))
+ return false;
+
+ const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx;
const unsigned AfterChildren = NextToken();
+ SourceRange cursorRange = Info.CursorRange;
// Scan the tokens that are at the end of the cursor, but are not captured
// but the child cursors.
annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange);
-
+
// Scan the tokens that are at the beginning of the cursor, but are not
// capture by the child cursors.
for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
break;
-
+
Cursors[I] = cursor;
}
- return CXChildVisit_Continue;
+ PostChildrenInfos.pop_back();
+ return false;
}
static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
@@ -5148,6 +5237,12 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
}
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->
+ postVisitChildren(cursor);
+}
+
namespace {
/// \brief Uses the macro expansions in the preprocessing record to find
@@ -5732,13 +5827,61 @@ CXString clang_Cursor_getBriefCommentText(CXCursor C) {
CXComment clang_Cursor_getParsedComment(CXCursor C) {
if (!clang_isDeclaration(C.kind))
- return cxcomment::createCXComment(NULL);
+ return cxcomment::createCXComment(NULL, NULL);
const Decl *D = getCursorDecl(C);
const ASTContext &Context = getCursorContext(C);
- const comments::FullComment *FC = Context.getCommentForDecl(D);
+ const comments::FullComment *FC = Context.getCommentForDecl(D, /*PP=*/ NULL);
+
+ return cxcomment::createCXComment(FC, getCursorTU(C));
+}
+
+CXModule clang_Cursor_getModule(CXCursor C) {
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C)))
+ return ImportD->getImportedModule();
+ }
+
+ return 0;
+}
+
+CXModule clang_Module_getParent(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->Parent;
+}
+
+CXString clang_Module_getName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->Name);
+}
- return cxcomment::createCXComment(FC);
+CXString clang_Module_getFullName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->getFullModuleName());
+}
+
+unsigned clang_Module_getNumTopLevelHeaders(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->TopHeaders.size();
+}
+
+CXFile clang_Module_getTopLevelHeader(CXModule CXMod, unsigned Index) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+
+ if (Index < Mod->TopHeaders.size())
+ return const_cast<FileEntry *>(Mod->TopHeaders[Index]);
+
+ return 0;
}
} // end: extern "C"
@@ -5994,6 +6137,9 @@ void SetSafetyThreadStackSize(unsigned Value) {
}
void clang::setThreadBackgroundPriority() {
+ if (getenv("LIBCLANG_BGPRIO_DISABLE"))
+ return;
+
// FIXME: Move to llvm/Support and make it cross-platform.
#ifdef __APPLE__
setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index 240b0f6c1fe1..9bc3efa095d3 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -67,8 +67,9 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
= dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(
getCursorDecl(C))) {
switch (PartialSpec->getTagKind()) {
- case TTK_Class: return CXCursor_ClassDecl;
+ case TTK_Interface:
case TTK_Struct: return CXCursor_StructDecl;
+ case TTK_Class: return CXCursor_ClassDecl;
case TTK_Union: return CXCursor_UnionDecl;
case TTK_Enum: return CXCursor_NoDeclFound;
}
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 0073b509e8a3..46af661d0e5c 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -223,8 +223,6 @@ clang_getCompletionParent(CXCompletionString completion_string,
if (!CCStr)
return createCXString((const char *)0);
- if (kind)
- *kind = CCStr->getParentContextKind();
return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
}
@@ -248,6 +246,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Diagnostics produced while performing code completion.
SmallVector<StoredDiagnostic, 8> Diagnostics;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+
/// \brief Diag object
IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
@@ -307,8 +307,10 @@ static llvm::sys::cas_flag CodeCompletionResultObjects;
AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
+ DiagOpts(new DiagnosticOptions),
Diag(new DiagnosticsEngine(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ &*DiagOpts)),
FileSystemOpts(FileSystemOpts),
FileMgr(new FileManager(FileSystemOpts)),
SourceMgr(new SourceManager(*Diag, *FileMgr)),
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 14722e018491..3154480ae198 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -19,7 +19,7 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/DiagnosticRenderer.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -87,7 +87,7 @@ public:
class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
public:
CXDiagnosticRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts,
+ DiagnosticOptions *DiagOpts,
CXDiagnosticSetImpl *mainSet)
: DiagnosticNoteRenderer(LangOpts, DiagOpts),
CurrentSet(mainSet), MainSet(mainSet) {}
@@ -191,9 +191,9 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
if (!TU->Diagnostics) {
CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
TU->Diagnostics = Set;
- DiagnosticOptions DOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
- DOpts, Set);
+ &*DOpts, Set);
for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
ei = AU->stored_diag_end(); it != ei; ++it) {
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index c885dd546c39..614003272951 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -402,6 +402,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
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;
@@ -413,6 +414,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
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;
@@ -424,6 +426,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
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;
@@ -725,10 +728,12 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
break;
case TemplateArgument::Declaration:
- if (Decl *D = Arg.getAsDecl())
- Visit(D);
+ Visit(Arg.getAsDecl());
break;
-
+
+ case TemplateArgument::NullPtr:
+ break;
+
case TemplateArgument::TemplateExpansion:
Out << 'P'; // pack expansion of...
// Fall through
@@ -800,36 +805,11 @@ bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
if (!D || D->getLocStart().isInvalid())
return true;
- // Check if the cursor has 'NoLinkage'.
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
- switch (ND->getLinkage()) {
- case ExternalLinkage:
- // Generate USRs for all entities with external linkage.
- break;
- case NoLinkage:
- case UniqueExternalLinkage:
- // We allow enums, typedefs, and structs that have no linkage to
- // have USRs that are anchored to the file they were defined in
- // (e.g., the header). This is a little gross, but in principal
- // enums/anonymous structs/etc. defined in a common header file
- // are referred to across multiple translation units.
- if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
- isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) ||
- isa<VarDecl>(ND) || isa<NamespaceDecl>(ND))
- break;
- // Fall-through.
- case InternalLinkage:
- if (isa<FunctionDecl>(ND))
- break;
- }
+ USRGenerator UG(&D->getASTContext(), &Buf);
+ UG->Visit(const_cast<Decl*>(D));
- {
- USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(const_cast<Decl*>(D));
-
- if (UG->ignoreResults())
- return true;
- }
+ if (UG->ignoreResults())
+ return true;
return false;
}
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 283276f801f1..1426c42b4621 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -43,7 +43,8 @@ set(SOURCES
set(LIBRARIES
clangARCMigrate
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangFrontend
clangDriver
clangSerialization
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index c5c9ca8cf383..fa149a0ff9d0 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -15,12 +15,11 @@
#include "CXString.h"
#include "CXComment.h"
#include "CXCursor.h"
-#include "CXTranslationUnit.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h"
-#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -94,9 +93,9 @@ unsigned clang_Comment_getNumChildren(CXComment CXC) {
CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
const Comment *C = getASTNode(CXC);
if (!C || ChildIdx >= C->child_count())
- return createCXComment(NULL);
+ return createCXComment(NULL, NULL);
- return createCXComment(*(C->child_begin() + ChildIdx));
+ return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
}
unsigned clang_Comment_isWhitespace(CXComment CXC) {
@@ -134,7 +133,8 @@ CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
if (!ICC)
return createCXString((const char *) 0);
- return createCXString(ICC->getCommandName(), /*DupString=*/ false);
+ const CommandTraits &Traits = getCommandTraits(CXC);
+ return createCXString(ICC->getCommandName(Traits), /*DupString=*/ false);
}
enum CXCommentInlineCommandRenderKind
@@ -221,7 +221,8 @@ CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
if (!BCC)
return createCXString((const char *) 0);
- return createCXString(BCC->getCommandName(), /*DupString=*/ false);
+ const CommandTraits &Traits = getCommandTraits(CXC);
+ return createCXString(BCC->getCommandName(Traits), /*DupString=*/ false);
}
unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
@@ -244,9 +245,9 @@ CXString clang_BlockCommandComment_getArgText(CXComment CXC,
CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
if (!BCC)
- return createCXComment(NULL);
+ return createCXComment(NULL, NULL);
- return createCXComment(BCC->getParagraph());
+ return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
}
CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
@@ -254,7 +255,7 @@ CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
if (!PCC || !PCC->hasParamName())
return createCXString((const char *) 0);
- return createCXString(PCC->getParamName(), /*DupString=*/ false);
+ return createCXString(PCC->getParamNameAsWritten(), /*DupString=*/ false);
}
unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
@@ -305,7 +306,7 @@ CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
if (!TPCC || !TPCC->hasParamName())
return createCXString((const char *) 0);
- return createCXString(TPCC->getParamName(), /*DupString=*/ false);
+ return createCXString(TPCC->getParamNameAsWritten(), /*DupString=*/ false);
}
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
@@ -405,7 +406,8 @@ public:
/// Separate parts of a FullComment.
struct FullCommentParts {
/// Take a full comment apart and initialize members accordingly.
- FullCommentParts(const FullComment *C);
+ FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits);
const BlockContentComment *Brief;
const ParagraphComment *FirstParagraph;
@@ -415,9 +417,9 @@ struct FullCommentParts {
SmallVector<const BlockContentComment *, 8> MiscBlocks;
};
-FullCommentParts::FullCommentParts(const FullComment *C) :
+FullCommentParts::FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits) :
Brief(NULL), FirstParagraph(NULL), Returns(NULL) {
- const CommandTraits Traits;
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
const Comment *Child = *I;
@@ -440,12 +442,12 @@ FullCommentParts::FullCommentParts(const FullComment *C) :
case Comment::BlockCommandCommentKind: {
const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
- StringRef CommandName = BCC->getCommandName();
- if (!Brief && Traits.isBriefCommand(CommandName)) {
+ const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
+ if (!Brief && Info->IsBriefCommand) {
Brief = BCC;
break;
}
- if (!Returns && Traits.isReturnsCommand(CommandName)) {
+ if (!Returns && Info->IsReturnsCommand) {
Returns = BCC;
break;
}
@@ -483,7 +485,8 @@ FullCommentParts::FullCommentParts(const FullComment *C) :
case Comment::VerbatimLineCommentKind: {
const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
- if (!Traits.isDeclarationCommand(VLC->getCommandName()))
+ const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
+ if (!Info->IsDeclarationCommand)
MiscBlocks.push_back(VLC);
break;
}
@@ -533,7 +536,11 @@ class CommentASTToHTMLConverter :
public ConstCommentVisitor<CommentASTToHTMLConverter> {
public:
/// \param Str accumulator for HTML.
- CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
+ CommentASTToHTMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits) :
+ FC(FC), Result(Str), Traits(Traits)
+ { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -561,10 +568,11 @@ public:
void appendToResultWithHTMLEscaping(StringRef S);
private:
- const CommandTraits Traits;
-
+ const FullComment *FC;
/// Output stream for HTML.
llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
};
} // end unnamed namespace
@@ -637,14 +645,14 @@ void CommentASTToHTMLConverter::visitParagraphComment(
void CommentASTToHTMLConverter::visitBlockCommandComment(
const BlockCommandComment *C) {
- StringRef CommandName = C->getCommandName();
- if (Traits.isBriefCommand(CommandName)) {
+ const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
+ if (Info->IsBriefCommand) {
Result << "<p class=\"para-brief\">";
visitNonStandaloneParagraphComment(C->getParagraph());
Result << "</p>";
return;
}
- if (Traits.isReturnsCommand(CommandName)) {
+ if (Info->IsReturnsCommand) {
Result << "<p class=\"para-returns\">"
"<span class=\"word-returns\">Returns</span> ";
visitNonStandaloneParagraphComment(C->getParagraph());
@@ -661,10 +669,11 @@ void CommentASTToHTMLConverter::visitParamCommandComment(
Result << "<dt class=\"param-name-index-"
<< C->getParamIndex()
<< "\">";
- } else
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ } else {
Result << "<dt class=\"param-name-index-invalid\">";
-
- appendToResultWithHTMLEscaping(C->getParamName());
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
Result << "</dt>";
if (C->isParamIndexValid()) {
@@ -687,10 +696,12 @@ void CommentASTToHTMLConverter::visitTParamCommandComment(
<< "\">";
else
Result << "<dt class=\"tparam-name-index-other\">";
- } else
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ } else {
Result << "<dt class=\"tparam-name-index-invalid\">";
-
- appendToResultWithHTMLEscaping(C->getParamName());
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
+
Result << "</dt>";
if (C->isPositionValid()) {
@@ -735,7 +746,7 @@ void CommentASTToHTMLConverter::visitVerbatimLineComment(
}
void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C);
+ FullCommentParts Parts(C, Traits);
bool FirstParagraphIsBrief = false;
if (Parts.Brief)
@@ -822,7 +833,7 @@ CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
return createCXString((const char *) 0);
SmallString<128> HTML;
- CommentASTToHTMLConverter Converter(HTML);
+ CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
Converter.visit(HTC);
return createCXString(HTML.str(), /* DupString = */ true);
}
@@ -833,7 +844,7 @@ CXString clang_FullComment_getAsHTML(CXComment CXC) {
return createCXString((const char *) 0);
SmallString<1024> HTML;
- CommentASTToHTMLConverter Converter(HTML);
+ CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
Converter.visit(FC);
return createCXString(HTML.str(), /* DupString = */ true);
}
@@ -845,9 +856,11 @@ class CommentASTToXMLConverter :
public ConstCommentVisitor<CommentASTToXMLConverter> {
public:
/// \param Str accumulator for XML.
- CommentASTToXMLConverter(const SourceManager &SM,
- SmallVectorImpl<char> &Str) :
- SM(SM), Result(Str) { }
+ CommentASTToXMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits,
+ const SourceManager &SM) :
+ FC(FC), Result(Str), Traits(Traits), SM(SM) { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -870,11 +883,27 @@ public:
void appendToResultWithXMLEscaping(StringRef S);
private:
- const SourceManager &SM;
+ const FullComment *FC;
/// Output stream for XML.
llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
+ const SourceManager &SM;
};
+
+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.SuppressAttributes = true;
+ PPolicy.TerseOutput = true;
+ ThisDecl->CurrentDecl->print(OS, PPolicy,
+ /*Indentation*/0, /*PrintInstantiation*/true);
+}
+
} // end unnamed namespace
void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
@@ -947,7 +976,8 @@ void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandCommen
void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->getParamName());
+ appendToResultWithXMLEscaping(C->isParamIndexValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
Result << "</Name>";
if (C->isParamIndexValid())
@@ -973,7 +1003,8 @@ void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandCommen
void CommentASTToXMLConverter::visitTParamCommandComment(
const TParamCommandComment *C) {
Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->getParamName());
+ appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
Result << "</Name>";
if (C->isPositionValid() && C->getDepth() == 1) {
@@ -991,7 +1022,7 @@ void CommentASTToXMLConverter::visitVerbatimBlockComment(
if (NumLines == 0)
return;
- Result << llvm::StringSwitch<const char *>(C->getCommandName())
+ Result << llvm::StringSwitch<const char *>(C->getCommandName(Traits))
.Case("code", "<Verbatim xml:space=\"preserve\" kind=\"code\">")
.Default("<Verbatim xml:space=\"preserve\" kind=\"verbatim\">");
for (unsigned i = 0; i != NumLines; ++i) {
@@ -1015,7 +1046,7 @@ void CommentASTToXMLConverter::visitVerbatimLineComment(
}
void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C);
+ FullCommentParts Parts(C, Traits);
const DeclInfo *DI = C->getDeclInfo();
StringRef RootEndTag;
@@ -1083,7 +1114,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
{
// Print line and column number.
- SourceLocation Loc = DI->ThisDecl->getLocation();
+ SourceLocation Loc = DI->CurrentDecl->getLocation();
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
FileID FID = LocInfo.first;
unsigned FileOffset = LocInfo.second;
@@ -1104,7 +1135,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << ">";
bool FoundName = false;
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->ThisDecl)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
if (DeclarationName DeclName = ND->getDeclName()) {
Result << "<Name>";
std::string Name = DeclName.getAsString();
@@ -1119,7 +1150,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
{
// Print USR.
SmallString<128> USR;
- cxcursor::getDeclCursorUSR(DI->ThisDecl, USR);
+ cxcursor::getDeclCursorUSR(DI->CommentDecl, USR);
if (!USR.empty()) {
Result << "<USR>";
appendToResultWithXMLEscaping(USR);
@@ -1132,6 +1163,15 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << "<Other><Name>unknown</Name>";
}
+ {
+ // Pretty-print the declaration.
+ Result << "<Declaration>";
+ SmallString<128> Declaration;
+ getSourceTextOfDeclaration(DI, Declaration);
+ appendToResultWithXMLEscaping(Declaration);
+ Result << "</Declaration>";
+ }
+
bool FirstParagraphIsBrief = false;
if (Parts.Brief) {
Result << "<Abstract>";
@@ -1163,6 +1203,72 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
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;
@@ -1213,15 +1319,16 @@ void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
extern "C" {
-CXString clang_FullComment_getAsXML(CXTranslationUnit TU, CXComment CXC) {
+CXString clang_FullComment_getAsXML(CXComment CXC) {
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
if (!FC)
return createCXString((const char *) 0);
+ CXTranslationUnit TU = CXC.TranslationUnit;
SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
SmallString<1024> XML;
- CommentASTToXMLConverter Converter(SM, XML);
+ CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM);
Converter.visit(FC);
return createCXString(XML.str(), /* DupString = */ true);
}
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index 753877e6c7e3..513431709f48 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -15,20 +15,29 @@
#define LLVM_CLANG_CXCOMMENT_H
#include "clang-c/Index.h"
+#include "CXTranslationUnit.h"
#include "clang/AST/Comment.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Frontend/ASTUnit.h"
namespace clang {
+namespace comments {
+ class CommandTraits;
+}
+
namespace cxcomment {
-inline CXComment createCXComment(const comments::Comment *C) {
+inline CXComment createCXComment(const comments::Comment *C,
+ CXTranslationUnit TU) {
CXComment Result;
- Result.Data = C;
+ Result.ASTNode = C;
+ Result.TranslationUnit = TU;
return Result;
}
inline const comments::Comment *getASTNode(CXComment CXC) {
- return static_cast<const comments::Comment *>(CXC.Data);
+ return static_cast<const comments::Comment *>(CXC.ASTNode);
}
template<typename T>
@@ -40,6 +49,14 @@ inline const T *getASTNodeAs(CXComment CXC) {
return dyn_cast<T>(C);
}
+inline ASTContext &getASTContext(CXComment CXC) {
+ return static_cast<ASTUnit *>(CXC.TranslationUnit->TUData)->getASTContext();
+}
+
+inline comments::CommandTraits &getCommandTraits(CXComment CXC) {
+ return getASTContext(CXC).getCommentCommandTraits();
+}
+
} // end namespace cxcomment
} // end namespace clang
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 2757af434c3e..8d3e1690edc5 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -15,6 +15,7 @@
#include "CXTranslationUnit.h"
#include "CXCursor.h"
+#include "CXType.h"
#include "CXString.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/AST/Decl.h"
@@ -145,8 +146,8 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
K = CXCursor_ReturnStmt;
break;
- case Stmt::AsmStmtClass:
- K = CXCursor_AsmStmt;
+ case Stmt::GCCAsmStmtClass:
+ K = CXCursor_GCCAsmStmt;
break;
case Stmt::MSAsmStmtClass:
@@ -432,6 +433,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ case Stmt::FunctionParmPackExprClass:
case Stmt::UnresolvedLookupExprClass:
K = CXCursor_DeclRefExpr;
break;
@@ -794,194 +796,20 @@ CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
-static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU,
- ObjCContainerDecl *Container,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods,
- bool MovedToSuper) {
- if (!Container)
- return;
-
- // In categories look for overriden methods from protocols. A method from
- // category is not "overriden" since it is considered as the "same" method
- // (same USR) as the one from the interface.
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
- // Check whether we have a matching method at this category but only if we
- // are at the super class level.
- if (MovedToSuper)
- if (ObjCMethodDecl *
- Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- if (Method != Overridden) {
- // We found an override at this category; there is no need to look
- // into its protocols.
- Methods.push_back(MakeCXCursor(Overridden, TU));
- return;
- }
-
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
- return;
- }
-
- // Check whether we have a matching method at this level.
- if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- if (Method != Overridden) {
- // We found an override at this level; there is no need to look
- // into other protocols or categories.
- Methods.push_back(MakeCXCursor(Overridden, TU));
- return;
- }
-
- if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
- PEnd = Protocol->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
- }
-
- if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
- for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
- PEnd = Interface->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
-
- for (ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethodsRecurse(TU, Category, Method, Methods,
- MovedToSuper);
-
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
- return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods,
- /*MovedToSuper=*/true);
- }
-}
-
-static inline void CollectOverriddenMethods(CXTranslationUnit TU,
- ObjCContainerDecl *Container,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- CollectOverriddenMethodsRecurse(TU, Container, Method, Methods,
- /*MovedToSuper=*/false);
-}
-
-static void collectOverriddenMethodsSlow(CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &overridden) {
- assert(Method->isOverriding());
-
- if (ObjCProtocolDecl *
- ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
- CollectOverriddenMethods(TU, ProtD, Method, overridden);
-
- } else if (ObjCImplDecl *
- IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
- ObjCInterfaceDecl *ID = IMD->getClassInterface();
- if (!ID)
- return;
- // Start searching for overridden methods using the method from the
- // interface as starting point.
- if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- Method = IFaceMeth;
- CollectOverriddenMethods(TU, ID, Method, overridden);
-
- } else if (ObjCCategoryDecl *
- CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
- ObjCInterfaceDecl *ID = CatD->getClassInterface();
- if (!ID)
- return;
- // Start searching for overridden methods using the method from the
- // interface as starting point.
- if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- Method = IFaceMeth;
- CollectOverriddenMethods(TU, ID, Method, overridden);
-
- } else {
- CollectOverriddenMethods(TU,
- dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
- Method, overridden);
- }
-}
-
-static void collectOnCategoriesAfterLocation(SourceLocation Loc,
- ObjCInterfaceDecl *Class,
- CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- if (!Class)
- return;
-
- SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
- for (ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
- CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, true);
-
- collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), TU,
- Method, Methods);
-}
-
-/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
-/// returns false.
-/// You'd think that in that case there are no overrides but categories can
-/// "introduce" new overridden methods that are missed by Sema because the
-/// overrides lookup that it does for methods, inside implementations, will
-/// stop at the interface level (if there is a method there) and not look
-/// further in super classes.
-static void collectOverriddenMethodsFast(CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- assert(!Method->isOverriding());
-
- ObjCContainerDecl *ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
- if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
- return;
- ObjCInterfaceDecl *Class = Method->getClassInterface();
- if (!Class)
- return;
-
- collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
- TU, Method, Methods);
-}
-
void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden) {
assert(clang_isDeclaration(cursor.kind));
- Decl *D = getCursorDecl(cursor);
+ const NamedDecl *D = dyn_cast_or_null<NamedDecl>(getCursorDecl(cursor));
if (!D)
return;
- // Handle C++ member functions.
CXTranslationUnit TU = getCursorTU(cursor);
- if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
- for (CXXMethodDecl::method_iterator
- M = CXXMethod->begin_overridden_methods(),
- MEnd = CXXMethod->end_overridden_methods();
- M != MEnd; ++M)
- overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
- return;
- }
-
- ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
- if (!Method)
- return;
+ SmallVector<const NamedDecl *, 8> OverDecls;
+ D->getASTContext().getOverriddenMethods(D, OverDecls);
- if (Method->isRedeclaration()) {
- Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
- getMethod(Method->getSelector(), Method->isInstanceMethod());
- }
-
- if (!Method->isOverriding()) {
- collectOverriddenMethodsFast(TU, Method, overridden);
- } else {
- collectOverriddenMethodsSlow(TU, Method, overridden);
- assert(!overridden.empty() &&
- "ObjCMethodDecl's overriding bit is not as expected");
+ for (SmallVector<const NamedDecl *, 8>::iterator
+ I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) {
+ overridden.push_back(MakeCXCursor(const_cast<NamedDecl*>(*I), TU));
}
}
@@ -1345,4 +1173,16 @@ int clang_Cursor_isDynamicCall(CXCursor C) {
return 0;
}
+CXType clang_Cursor_getReceiverType(CXCursor C) {
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+ const Expr *E = 0;
+ if (clang_isExpression(C.kind))
+ E = getCursorExpr(C);
+
+ if (const ObjCMessageExpr *MsgE = dyn_cast_or_null<ObjCMessageExpr>(E))
+ return cxtype::MakeCXType(MsgE->getReceiverType(), TU);
+
+ return cxtype::MakeCXType(QualType(), TU);
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 15f818a244d7..4e031d2d5506 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -464,6 +464,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86Pascal);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
+ TCALLINGCONV(PnaclCall);
}
#undef TCALLINGCONV
}
@@ -615,7 +616,7 @@ long long clang_getArraySize(CXType CT) {
}
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
- if ((C.kind < CXCursor_FirstDecl) || (C.kind > CXCursor_LastDecl))
+ if (!clang_isDeclaration(C.kind))
return cxstring::createCXString("");
Decl *D = static_cast<Decl*>(C.data[0]);
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 88b70a490eb7..7cf75086b9b4 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -1,4 +1,4 @@
-//===- CursorVisitor.h - CursorVisitor interface --------------------------===//
+//===- CursorVisitor.h - CursorVisitor interface ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -32,7 +32,7 @@ public:
NestedNameSpecifierLocVisitKind,
DeclarationNameInfoVisitKind,
MemberRefVisitKind, SizeOfPackExprPartsKind,
- LambdaExprPartsKind };
+ LambdaExprPartsKind, PostChildrenVisitKind };
protected:
void *data[3];
CXCursor parent;
@@ -46,7 +46,6 @@ protected:
public:
Kind getKind() const { return K; }
const CXCursor &getParent() const { return parent; }
- static bool classof(VisitorJob *VJ) { return true; }
};
typedef SmallVector<VisitorJob, 10> VisitorWorkList;
@@ -55,6 +54,13 @@ typedef SmallVector<VisitorJob, 10> VisitorWorkList;
class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
public TypeLocVisitor<CursorVisitor, bool>
{
+public:
+ /// \brief Callback called after child nodes of a cursor have been visited.
+ /// Return true to break visitation or false to continue.
+ typedef bool (*PostChildrenVisitorTy)(CXCursor cursor,
+ CXClientData client_data);
+
+private:
/// \brief The translation unit we are traversing.
CXTranslationUnit TU;
ASTUnit *AU;
@@ -69,6 +75,8 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \brief The visitor function.
CXCursorVisitor Visitor;
+ PostChildrenVisitorTy PostChildrenVisitor;
+
/// \brief The opaque client data, to be passed along to the visitor.
CXClientData ClientData;
@@ -137,9 +145,11 @@ public:
bool VisitPreprocessorLast,
bool VisitIncludedPreprocessingEntries = false,
SourceRange RegionOfInterest = SourceRange(),
- bool VisitDeclsOnly = false)
+ bool VisitDeclsOnly = false,
+ PostChildrenVisitorTy PostChildrenVisitor = 0)
: TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
- Visitor(Visitor), ClientData(ClientData),
+ Visitor(Visitor), PostChildrenVisitor(PostChildrenVisitor),
+ ClientData(ClientData),
VisitPreprocessorLast(VisitPreprocessorLast),
VisitIncludedEntities(VisitIncludedPreprocessingEntries),
RegionOfInterest(RegionOfInterest),
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index acf883894098..3614206dee92 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -130,8 +130,20 @@ public:
}
bool VisitDeclStmt(DeclStmt *S) {
- if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
IndexCtx.indexDeclGroupRef(S->getDeclGroup());
+ return true;
+ }
+
+ DeclGroupRef DG = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
+ const Decl *D = *I;
+ if (!D)
+ continue;
+ if (!IndexCtx.isFunctionLocalDecl(D))
+ IndexCtx.indexTopLevelDecl(D);
+ }
+
return true;
}
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
index 7560398395a5..4b6706fba783 100644
--- a/tools/libclang/IndexDecl.cpp
+++ b/tools/libclang/IndexDecl.cpp
@@ -110,7 +110,7 @@ public:
return true;
}
- bool VisitTypedefDecl(TypedefNameDecl *D) {
+ bool VisitTypedefNameDecl(TypedefNameDecl *D) {
IndexCtx.handleTypedefName(D);
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
return true;
@@ -194,7 +194,7 @@ public:
bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Methods associated with a property, even user-declared ones, are
// handled when we handle the property.
- if (D->isSynthesized())
+ if (D->isPropertyAccessor())
return true;
handleObjCMethod(D);
@@ -228,12 +228,12 @@ public:
}
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
- if (MD->isSynthesized())
+ if (MD->isPropertyAccessor())
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
- if (MD->isSynthesized())
+ if (MD->isPropertyAccessor())
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
@@ -305,6 +305,11 @@ public:
IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
return true;
}
+
+ bool VisitImportDecl(ImportDecl *D) {
+ IndexCtx.importedModule(D);
+ return true;
+ }
};
} // anonymous namespace
@@ -325,7 +330,7 @@ void IndexingContext::indexDeclContext(const DeclContext *DC) {
}
}
-void IndexingContext::indexTopLevelDecl(Decl *D) {
+void IndexingContext::indexTopLevelDecl(const Decl *D) {
if (isNotFromSourceFile(D->getLocation()))
return;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 8fe9c36556f7..714a36ebddf7 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -68,13 +68,15 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
bool isImport = (IncludeTok.is(tok::identifier) &&
IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
- IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled);
+ IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled,
+ Imported);
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
@@ -189,6 +191,13 @@ public:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+
+ if (!PPOpts.ImplicitPCHInclude.empty()) {
+ IndexCtx.importedPCH(
+ CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude));
+ }
+
IndexCtx.setASTContext(CI.getASTContext());
Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
@@ -281,13 +290,13 @@ static void clang_indexSourceFile_Impl(void *UserData) {
CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
// Configure the diagnostics.
- DiagnosticOptions DiagOpts;
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
- command_line_args,
- CaptureDiag,
- /*ShouldOwnClient=*/true,
- /*ShouldCloneClient=*/false));
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ num_command_line_args,
+ command_line_args,
+ CaptureDiag,
+ /*ShouldOwnClient=*/true,
+ /*ShouldCloneClient=*/false));
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -346,9 +355,6 @@ static void clang_indexSourceFile_Impl(void *UserData) {
// precompiled headers are involved), we disable it.
CInvok->getLangOpts()->SpellChecking = false;
- if (!requestedToGetTU)
- CInvok->getPreprocessorOpts().DetailedRecord = false;
-
if (index_options & CXIndexOpt_SuppressWarnings)
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
@@ -374,7 +380,6 @@ static void clang_indexSourceFile_Impl(void *UserData) {
bool PrecompilePreamble = false;
bool CacheCodeCompletionResults = false;
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
- PPOpts.DetailedRecord = false;
PPOpts.AllowPCHWithCompilerErrors = true;
if (requestedToGetTU) {
@@ -383,11 +388,15 @@ static void clang_indexSourceFile_Impl(void *UserData) {
// FIXME: Add a flag for modules.
CacheCodeCompletionResults
= TU_options & CXTranslationUnit_CacheCompletionResults;
- if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
- PPOpts.DetailedRecord = true;
- }
}
+ if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
+ PPOpts.DetailedRecord = true;
+ }
+
+ if (!requestedToGetTU && !CInvok->getLangOpts()->Modules)
+ PPOpts.DetailedRecord = false;
+
DiagnosticErrorTrap DiagTrap(*Diags);
bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags,
IndexAction.get(),
@@ -435,57 +444,39 @@ static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) {
if (!PP.getPreprocessingRecord())
return;
- PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
-
// FIXME: Only deserialize inclusion directives.
- // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
- // that it depends on.
- bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
PreprocessingRecord::iterator I, E;
- if (OnlyLocal) {
- I = PPRec.local_begin();
- E = PPRec.local_end();
- } else {
- I = PPRec.begin();
- E = PPRec.end();
- }
+ llvm::tie(I, E) = Unit.getLocalPreprocessingEntities();
+ bool isModuleFile = Unit.isModuleFile();
for (; I != E; ++I) {
PreprocessedEntity *PPE = *I;
if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
- IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(),
- ID->getFile(), ID->getKind() == InclusionDirective::Import,
- !ID->wasInQuotes());
+ SourceLocation Loc = ID->getSourceRange().getBegin();
+ // Modules have synthetic main files as input, give an invalid location
+ // if the location points to such a file.
+ if (isModuleFile && Unit.isInMainFileID(Loc))
+ Loc = SourceLocation();
+ IdxCtx.ppIncludedFile(Loc, ID->getFileName(),
+ ID->getFile(),
+ ID->getKind() == InclusionDirective::Import,
+ !ID->wasInQuotes(), ID->importedModule());
}
}
}
-static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
- // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
- // that it depends on.
-
- bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
-
- if (OnlyLocal) {
- for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(),
- TLEnd = Unit.top_level_end();
- TL != TLEnd; ++TL) {
- IdxCtx.indexTopLevelDecl(*TL);
- if (IdxCtx.shouldAbort())
- return;
- }
+static bool topLevelDeclVisitor(void *context, const Decl *D) {
+ IndexingContext &IdxCtx = *static_cast<IndexingContext*>(context);
+ IdxCtx.indexTopLevelDecl(D);
+ if (IdxCtx.shouldAbort())
+ return false;
+ return true;
+}
- } else {
- TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl();
- for (TranslationUnitDecl::decl_iterator
- I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) {
- IdxCtx.indexTopLevelDecl(*I);
- if (IdxCtx.shouldAbort())
- return;
- }
- }
+static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ Unit.visitLocalTopLevelDecls(&IdxCtx, topLevelDeclVisitor);
}
static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) {
@@ -539,6 +530,11 @@ static void clang_indexTranslationUnit_Impl(void *UserData) {
if (!Unit)
return;
+ ASTUnit::ConcurrencyCheck Check(*Unit);
+
+ if (const FileEntry *PCHFile = Unit->getPCHFile())
+ IndexCtx->importedPCH(PCHFile);
+
FileManager &FileMgr = Unit->getFileManager();
if (Unit->getOriginalSourceFileName().empty())
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index ace5c75a96f7..d4daa49de910 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -1,4 +1,4 @@
-//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//===- IndexingContext.cpp - Higher level API functions -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -204,6 +204,26 @@ void IndexingContext::setPreprocessor(Preprocessor &PP) {
static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP);
}
+bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
+ assert(D);
+
+ if (!D->getParentFunctionOrMethod())
+ return false;
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ switch (ND->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ return true;
+ case UniqueExternalLinkage:
+ case ExternalLinkage:
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool IndexingContext::shouldAbort() {
if (!CB.abortQuery)
return false;
@@ -220,7 +240,8 @@ void IndexingContext::enteredMainFile(const FileEntry *File) {
void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
StringRef filename,
const FileEntry *File,
- bool isImport, bool isAngled) {
+ bool isImport, bool isAngled,
+ bool isModuleImport) {
if (!CB.ppIncludedFile)
return;
@@ -228,11 +249,44 @@ void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
SA.toCStr(filename),
(CXFile)File,
- isImport, isAngled };
+ isImport, isAngled, isModuleImport };
CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
FileMap[File] = idxFile;
}
+void IndexingContext::importedModule(const ImportDecl *ImportD) {
+ if (!CB.importedASTFile)
+ return;
+
+ Module *Mod = ImportD->getImportedModule();
+ if (!Mod)
+ return;
+ std::string ModuleName = Mod->getFullModuleName();
+
+ CXIdxImportedASTFileInfo Info = {
+ (CXFile)Mod->getASTFile(),
+ Mod,
+ getIndexLoc(ImportD->getLocation()),
+ ImportD->isImplicit()
+ };
+ CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info);
+ (void)astFile;
+}
+
+void IndexingContext::importedPCH(const FileEntry *File) {
+ if (!CB.importedASTFile)
+ return;
+
+ CXIdxImportedASTFileInfo Info = {
+ (CXFile)File,
+ /*module=*/NULL,
+ getIndexLoc(SourceLocation()),
+ /*isImplicit=*/false
+ };
+ CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info);
+ (void)astFile;
+}
+
void IndexingContext::startedTranslationUnit() {
CXIdxClientContainer idxCont = 0;
if (CB.startedTranslationUnit)
@@ -590,7 +644,7 @@ bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
return false;
if (Loc.isInvalid())
return false;
- if (!shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod())
+ if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
return false;
if (isNotFromSourceFile(D->getLocation()))
return false;
@@ -855,6 +909,10 @@ void IndexingContext::getEntityInfo(const NamedDecl *D,
EntityInfo.kind = CXIdxEntity_CXXClass;
EntityInfo.lang = CXIdxEntityLang_CXX;
break;
+ case TTK_Interface:
+ EntityInfo.kind = CXIdxEntity_CXXInterface;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
case TTK_Enum:
EntityInfo.kind = CXIdxEntity_Enum; break;
}
@@ -1065,6 +1123,8 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
return false;
if (isa<ObjCMethodDecl>(D))
return false;
+ if (isa<ImportDecl>(D))
+ return false;
return true;
}
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index 00e109644c23..0fc7238ee23d 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -1,4 +1,4 @@
-//===- IndexingContext.h - Higher level API functions ------------------------===//
+//===- IndexingContext.h - Higher level API functions -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -100,8 +100,6 @@ struct DeclInfo : public CXIdxDeclInfo {
numAttributes = 0;
declAsContainer = semanticContainer = lexicalContainer = 0;
}
-
- static bool classof(const DeclInfo *) { return true; }
};
struct ObjCContainerDeclInfo : public DeclInfo {
@@ -126,7 +124,6 @@ struct ObjCContainerDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
}
- static bool classof(const ObjCContainerDeclInfo *D) { return true; }
private:
void init(bool isForwardRef, bool isImplementation) {
@@ -152,7 +149,6 @@ struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCInterface;
}
- static bool classof(const ObjCInterfaceDeclInfo *D) { return true; }
};
struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
@@ -167,7 +163,6 @@ struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCProtocol;
}
- static bool classof(const ObjCProtocolDeclInfo *D) { return true; }
};
struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
@@ -183,7 +178,6 @@ struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCCategory;
}
- static bool classof(const ObjCCategoryDeclInfo *D) { return true; }
};
struct ObjCPropertyDeclInfo : public DeclInfo {
@@ -197,7 +191,6 @@ struct ObjCPropertyDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCProperty;
}
- static bool classof(const ObjCPropertyDeclInfo *D) { return true; }
};
struct CXXClassDeclInfo : public DeclInfo {
@@ -209,7 +202,6 @@ struct CXXClassDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_CXXClass;
}
- static bool classof(const CXXClassDeclInfo *D) { return true; }
};
struct AttrInfo : public CXIdxAttrInfo {
@@ -221,8 +213,6 @@ struct AttrInfo : public CXIdxAttrInfo {
loc = Loc;
this->A = A;
}
-
- static bool classof(const AttrInfo *) { return true; }
};
struct IBOutletCollectionInfo : public AttrInfo {
@@ -240,7 +230,6 @@ struct IBOutletCollectionInfo : public AttrInfo {
static bool classof(const AttrInfo *A) {
return A->kind == CXIdxAttr_IBOutletCollection;
}
- static bool classof(const IBOutletCollectionInfo *D) { return true; }
};
class AttrListInfo {
@@ -251,8 +240,8 @@ class AttrListInfo {
SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
unsigned ref_cnt;
- AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT
- void operator=(const AttrListInfo&); // DO NOT IMPLEMENT
+ AttrListInfo(const AttrListInfo &) LLVM_DELETED_FUNCTION;
+ void operator=(const AttrListInfo &) LLVM_DELETED_FUNCTION;
public:
AttrListInfo(const Decl *D, IndexingContext &IdxCtx);
@@ -370,6 +359,8 @@ public:
return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
}
+ static bool isFunctionLocalDecl(const Decl *D);
+
bool shouldAbort();
bool hasDiagnosticCallback() const { return CB.diagnostic; }
@@ -378,7 +369,10 @@ public:
void ppIncludedFile(SourceLocation hashLoc,
StringRef filename, const FileEntry *File,
- bool isImport, bool isAngled);
+ bool isImport, bool isAngled, bool isModuleImport);
+
+ void importedModule(const ImportDecl *ImportD);
+ void importedPCH(const FileEntry *File);
void startedTranslationUnit();
@@ -451,7 +445,7 @@ public:
bool isNotFromSourceFile(SourceLocation Loc) const;
- void indexTopLevelDecl(Decl *D);
+ void indexTopLevelDecl(const Decl *D);
void indexTUDeclsInObjCContainer();
void indexDeclGroupRef(DeclGroupRef DG);
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 975d3812d10c..93f63cf86c84 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -17,10 +17,11 @@ SHARED_LIBRARY = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
- clangSerialization.a \
- clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
- clangAST.a clangLex.a clangTooling.a clangBasic.a
+USEDLIBS = clangARCMigrate.a clangRewriteCore.a clangRewriteFrontend.a \
+ clangFrontend.a clangDriver.a \
+ clangSerialization.a \
+ clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+ clangAST.a clangLex.a clangTooling.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
@@ -51,4 +52,10 @@ ifeq ($(HOST_OS),Darwin)
LLVMLibsOptions += -Wl,-install_name \
-Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
+
+ # If we're doing an Apple-style build, add the LTO object path.
+ ifeq ($(RC_BUILDIT),YES)
+ TempFile := $(shell mkdir -p ${OBJROOT}/dSYMs ; mktemp ${OBJROOT}/dSYMs/clang-lto.XXXXXX)
+ LLVMLibsOptions += -Wl,-object_path_lto -Wl,$(TempFile)
+ endif
endif
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 7131025ee1e0..4844204a5f73 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -657,6 +657,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type:
@@ -689,6 +690,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type: {
@@ -1753,7 +1755,7 @@ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
return true; \
}
-DEF_TRAVERSE_STMT(AsmStmt, {
+DEF_TRAVERSE_STMT(GCCAsmStmt, {
StmtQueue.queue(S->getAsmString());
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
StmtQueue.queue(S->getInputConstraintLiteral(I));
@@ -1762,7 +1764,7 @@ DEF_TRAVERSE_STMT(AsmStmt, {
StmtQueue.queue(S->getOutputConstraintLiteral(I));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- StmtQueue.queue(S->getClobber(I));
+ StmtQueue.queue(S->getClobberStringLiteral(I));
}
// children() iterates over inputExpr and outputExpr.
})
@@ -2141,6 +2143,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { })
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
+DEF_TRAVERSE_STMT(FunctionParmPackExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
DEF_TRAVERSE_STMT(AtomicExpr, { })
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 610bd91c6a5f..4495b66bdc13 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -13,8 +13,15 @@ clang_Cursor_getNumArguments
clang_Cursor_getObjCSelectorIndex
clang_Cursor_getSpellingNameRange
clang_Cursor_getTranslationUnit
+clang_Cursor_getReceiverType
clang_Cursor_isDynamicCall
clang_Cursor_isNull
+clang_Cursor_getModule
+clang_Module_getParent
+clang_Module_getName
+clang_Module_getFullName
+clang_Module_getNumTopLevelHeaders
+clang_Module_getTopLevelHeader
clang_IndexAction_create
clang_IndexAction_dispose
clang_Range_isNull
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index c7636f9e8e8f..8717225c18db 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -346,6 +346,7 @@ 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,
'-mios-simulator-version-min' => 0, # This really has 1 argument, but always has '='
@@ -353,6 +354,7 @@ my %CompilerLinkerOptionMap = (
'-arch' => 1,
'-m32' => 0,
'-m64' => 0,
+ '-stdlib' => 0, # This is really a 1 argument, but always has '='
'-v' => 0,
'-fpascal-strings' => 0,
'-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '='
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 65c4893124f3..a13b235aa93d 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -93,30 +93,13 @@ if (grep /^--help-checkers$/, @ARGV) {
}
##----------------------------------------------------------------------------##
-# Some initial preprocessing of Clang options.
+# Declaration of Clang options. Populated later.
##----------------------------------------------------------------------------##
-# Find 'clang'
-my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
-if (!defined $ClangSB || ! -x $ClangSB) {
- $ClangSB = Cwd::realpath("$RealBin/clang");
-}
my $Clang;
-if (!defined $ClangSB || ! -x $ClangSB) {
- # Default to looking for 'clang' in the path.
- $Clang = `which clang`;
- chomp $Clang;
- if ($Clang eq "") {
- DieDiag("No 'clang' executable found in path.\n");
- }
-}
-else {
- $Clang = $ClangSB;
-}
-my $ClangCXX = $Clang;
-$ClangCXX =~ s/\-\d+\.\d+$//;
-$ClangCXX .= "++";
-my $ClangVersion = HtmlEscape(`$Clang --version`);
+my $ClangSB;
+my $ClangCXX;
+my $ClangVersion;
##----------------------------------------------------------------------------##
# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
@@ -1003,74 +986,107 @@ ENDTEXT
print <<ENDTEXT;
OPTIONS:
- -analyze-headers - Also analyze functions in #included files.
+ -analyze-headers
+
+ Also analyze functions in #included files. By default, such functions
+ are skipped unless they are called by functions within the main source file.
- -o - Target directory for HTML report files. Subdirectories
- will be created as needed to represent separate "runs" of
- the analyzer. If this option is not specified, a directory
- is created in /tmp (TMPDIR on Mac OS X) to store the reports.
-
- -h - Display this message.
+ -o <output location>
+
+ Specifies the output directory for analyzer reports. Subdirectories will be
+ created as needed to represent separate "runs" of the analyzer. If this
+ option is not specified, a directory is created in /tmp (TMPDIR on Mac OS X)
+ to store the reports.
+
+ -h
--help
- -k - Add a "keep on going" option to the specified build command.
- --keep-going This option currently supports make and xcodebuild.
- This is a convenience option; one can specify this
- behavior directly using build options.
+ Display this message.
- --html-title [title] - Specify the title used on generated HTML pages.
- --html-title=[title] If not specified, a default title will be used.
+ -k
+ --keep-going
+
+ Add a "keep on going" option to the specified build command. This option
+ currently supports make and xcodebuild. This is a convenience option; one
+ can specify this behavior directly using build options.
- -plist - By default the output of scan-build is a set of HTML files.
- This option outputs the results as a set of .plist files.
-
- -plist-html - By default the output of scan-build is a set of HTML files.
- This option outputs the results as a set of HTML
- and .plist files.
-
- --status-bugs - By default, the exit status of $Prog is the same as the
- executed build command. Specifying this option causes the
- exit status of $Prog to be 1 if it found potential bugs
- and 0 otherwise.
+ --html-title [title]
+ --html-title=[title]
- --use-cc [compiler path] - $Prog attempts to guess the default compiler for
- --use-cc=[compiler path] your C and Objective-C code. Use this option
- to specify an alternate compiler.
+ Specify the title used on generated HTML pages. If not specified, a default
+ title will be used.
- --use-c++ [compiler path] - $Prog attempts to guess the default compiler for
- --use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
- to specify an alternate compiler.
+ -plist
+
+ By default the output of scan-build is a set of HTML files. This option
+ outputs the results as a set of .plist files.
+
+ -plist-html
+
+ By default the output of scan-build is a set of HTML files. This option
+ outputs the results as a set of HTML and .plist files.
+
+ --status-bugs
+
+ By default, the exit status of scan-build is the same as the executed build
+ command. Specifying this option causes the exit status of scan-build to be 1
+ if it found potential bugs and 0 otherwise.
+
+ --use-cc [compiler path]
+ --use-cc=[compiler path]
+
+ scan-build analyzes a project by interposing a "fake compiler", which
+ executes a real compiler for compilation and the static analyzer for analysis.
+ Because of the current implementation of interposition, scan-build does not
+ know what compiler your project normally uses. Instead, it simply overrides
+ the CC environment variable, and guesses your default compiler.
+
+ In the future, this interposition mechanism to be improved, but if you need
+ scan-build to use a specific compiler for *compilation* then you can use
+ this option to specify a path to that compiler.
+
+ --use-c++ [compiler path]
+ --use-c++=[compiler path]
+
+ This is the same as "-use-cc" but for C++ code.
+
+ -v
+
+ Enable verbose output from scan-build. A second and third '-v' increases
+ verbosity.
- -v - Verbose output from $Prog and the analyzer.
- A second and third '-v' increases verbosity.
+ -V
+ --view
- -V - View analysis results in a web browser when the build
- --view completes.
+ View analysis results in a web browser when the build completes.
ADVANCED OPTIONS:
- -constraints [model] - Specify the contraint engine used by the analyzer.
- By default the 'range' model is used. Specifying
- 'basic' uses a simpler, less powerful constraint model
- used by checker-0.160 and earlier.
-
- -store [model] - Specify the store model used by the analyzer. By default,
- the 'region' store model is used. 'region' specifies a field-
- sensitive store model. Users can also specify 'basic', which
- is far less precise but can more quickly analyze code.
- 'basic' was the default store model for checker-0.221 and
- earlier.
-
- -no-failure-reports - Do not create a 'failures' subdirectory that includes
- analyzer crash reports and preprocessed source files.
+ -no-failure-reports
+
+ Do not create a 'failures' subdirectory that includes analyzer crash reports
+ and preprocessed source files.
- -stats - Generates visitation statistics for the project being analyzed.
+ -stats
+
+ Generates visitation statistics for the project being analyzed.
- -maxloop N - specifiy the number of times a block can be visited before giving
- up. Default is 4. Increase for more comprehensive coverage at a
- cost of speed.
- -internal-stats - Generate internal analyzer statistics.
+ -maxloop <loop count>
+
+ Specifiy the number of times a block can be visited before giving up.
+ Default is 4. Increase for more comprehensive coverage at a cost of speed.
+
+ -internal-stats
+
+ Generate internal analyzer statistics.
+
+ --use-analyzer [Xcode|path to clang]
+ --use-analyzer=[Xcode|path to clang]
+ scan-build 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.
+
CONTROLLING CHECKERS:
A default group of checkers are always run unless explicitly disabled.
@@ -1119,85 +1135,86 @@ foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
}
# Query clang for complete list of checkers.
-pipe(FROM_CHILD, TO_PARENT);
-my $pid = fork();
-if ($pid == 0) {
- close FROM_CHILD;
- open(STDOUT,">&", \*TO_PARENT);
- open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
-}
-close(TO_PARENT);
-my $foundCheckers = 0;
-while(<FROM_CHILD>) {
- if (/CHECKERS:/) {
- $foundCheckers = 1;
- last;
+if (defined $Clang && -x $Clang) {
+ pipe(FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
}
-}
-if (!$foundCheckers) {
- print " *** Could not query Clang for the list of available checkers.";
-}
-else {
- print("\nAVAILABLE CHECKERS:\n\n");
- my $skip = 0;
+ close(TO_PARENT);
+ my $foundCheckers = 0;
while(<FROM_CHILD>) {
- if (/experimental/) {
- $skip = 1;
- next;
- }
- if ($skip) {
- next if (!/^\s\s[^\s]/);
- $skip = 0;
+ if (/CHECKERS:/) {
+ $foundCheckers = 1;
+ last;
}
- s/^\s\s//;
- if (/^([^\s]+)/) {
- # Is the checker enabled?
- my $checker = $1;
- my $enabled = 0;
- my $aggregate = "";
- foreach my $domain (split /\./, $checker) {
- $aggregate .= $domain;
- if ($EnabledCheckers{$aggregate}) {
- $enabled =1;
- last;
- }
- # append a dot, if an additional domain is added in the next iteration
- $aggregate .= ".";
+ }
+ if (!$foundCheckers) {
+ print " *** Could not query Clang for the list of available checkers.";
+ }
+ else {
+ print("\nAVAILABLE CHECKERS:\n\n");
+ my $skip = 0;
+ while(<FROM_CHILD>) {
+ if (/experimental/) {
+ $skip = 1;
+ next;
+ }
+ if ($skip) {
+ next if (!/^\s\s[^\s]/);
+ $skip = 0;
}
+ s/^\s\s//;
+ if (/^([^\s]+)/) {
+ # Is the checker enabled?
+ my $checker = $1;
+ my $enabled = 0;
+ my $aggregate = "";
+ foreach my $domain (split /\./, $checker) {
+ $aggregate .= $domain;
+ if ($EnabledCheckers{$aggregate}) {
+ $enabled =1;
+ last;
+ }
+ # append a dot, if an additional domain is added in the next iteration
+ $aggregate .= ".";
+ }
- if ($enabled) {
- print " + ";
+ if ($enabled) {
+ print " + ";
+ }
+ else {
+ print " ";
+ }
}
else {
print " ";
}
+ print $_;
}
- else {
- print " ";
- }
- print $_;
- }
+ print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
+ }
+ waitpid($pid,0);
+ close(FROM_CHILD);
}
-waitpid($pid,0);
-close(FROM_CHILD);
print <<ENDTEXT
- NOTE: "+" indicates that an analysis is enabled by default.
-
BUILD OPTIONS
You can specify any build option acceptable to the build command.
EXAMPLE
- $Prog -o /tmp/myhtmldir make -j4
+ scan-build -o /tmp/myhtmldir make -j4
- The above example causes analysis reports to be deposited into
- a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
- A different subdirectory is created each time $Prog analyzes a project.
- The analyzer should support most parallel builds, but not distributed builds.
+The above example causes analysis reports to be deposited into a subdirectory
+of "/tmp/myhtmldir" and to run "make" with the "-j4" option. A different
+subdirectory is created each time scan-build analyzes a project. The analyzer
+should support most parallel builds, but not distributed builds.
ENDTEXT
}
@@ -1251,6 +1268,7 @@ if (!@ARGV) {
my $displayHelp = 0;
+my $AnalyzerDiscoveryMethod;
while (@ARGV) {
@@ -1418,6 +1436,16 @@ while (@ARGV) {
push @PluginsToLoad, "-load", shift @ARGV;
next;
}
+ if ($arg eq "--use-analyzer") {
+ shift @ARGV;
+ $AnalyzerDiscoveryMethod = shift @ARGV;
+ next;
+ }
+ if ($arg =~ /^--use-analyzer=(.+)$/) {
+ shift @ARGV;
+ $AnalyzerDiscoveryMethod = $1;
+ next;
+ }
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
@@ -1429,11 +1457,50 @@ if (!@ARGV and $displayHelp == 0) {
$displayHelp = 1;
}
+# Find 'clang'
+if (!defined $AnalyzerDiscoveryMethod) {
+ $Clang = Cwd::realpath("$RealBin/bin/clang");
+ if (!defined $Clang || ! -x $Clang) {
+ $Clang = Cwd::realpath("$RealBin/clang");
+ }
+ if (!defined $Clang || ! -x $Clang) {
+ if (!$displayHelp) {
+ DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
+ " Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
+ }
+ }
+}
+else {
+ if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) {
+ my $xcrun = `which xcrun`;
+ chomp $xcrun;
+ if ($xcrun eq "") {
+ DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n");
+ }
+ $Clang = `$xcrun -toolchain XcodeDefault -find clang`;
+ chomp $Clang;
+ if ($Clang eq "") {
+ DieDiag("No 'clang' executable found by 'xcrun'\n");
+ }
+ }
+ else {
+ $Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
+ if (! -x $Clang) {
+ DieDiag("Cannot find an executable clang at '$Clang'\n");
+ }
+ }
+}
+
if ($displayHelp) {
DisplayHelp();
exit 1;
}
+$ClangCXX = $Clang;
+$ClangCXX =~ s/\-\d+\.\d+$//;
+$ClangCXX .= "++";
+$ClangVersion = HtmlEscape(`$Clang --version`);
+
# Determine where results go.
$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
@@ -1457,15 +1524,12 @@ if (!defined $CmdCXX || ! -x $CmdCXX) {
DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
}
-if (!defined $ClangSB || ! -x $ClangSB) {
- Diag("'clang' executable not found in '$RealBin/bin'.\n");
- Diag("Using 'clang' from path: $Clang\n");
-}
+Diag("Using '$Clang' for static analysis\n");
SetHtmlEnv(\@ARGV, $HtmlDir);
if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
-if ($MaxLoop > 0) { push @AnalysesToRun, '-analyzer-max-loop=$MaxLoop'; }
+if ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; }
# Delay setting up other environment variables in case we can do true
# interposition.
diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/scan-build.1
index 0f43196665cb..0c7ef1d00b87 100644
--- a/tools/scan-build/scan-build.1
+++ b/tools/scan-build/scan-build.1
@@ -1,9 +1,9 @@
.\" This file is distributed under the University of Illinois Open Source
.\" License. See LICENSE.TXT for details.
-.\" $Id: scan-build.1 157412 2012-05-24 20:16:00Z kremenek $
+.\" $Id: scan-build.1 167537 2012-11-07 17:12:37Z jrose $
.Dd May 25, 2012
+.Dt SCAN-BUILD 1
.Os "clang" "3.1"
-.Dt SCAN-BUILD \&1 CLANG
.Sh NAME
.Nm scan-build
.Nd Clang static analyzer
@@ -139,7 +139,7 @@ which is far less precise but can more quickly analyze code.
was the default store model for checker-0.221 and earlier.
.\"
.El
-.Sh RETURN VALUES
+.Sh EXIT STATUS
.Nm
returns the value returned by
.Ar build_command
@@ -188,10 +188,10 @@ Check for undefined results of binary operators.
.It core.VLASize
Check for declarations of VLA of undefined or zero size.
.It core.builtin.BuiltinFunctions
-Evaluate compiler builtin functions, e.g.
+Evaluate compiler builtin functions, e.g.
.Fn alloca .
.It core.builtin.NoReturnFunctions
-Evaluate
+Evaluate
.Ql panic
functions that are known to not return to the caller.
.It core.uninitialized.ArraySubscript
@@ -270,9 +270,10 @@ Check for proper uses of
.Fn CFNumberCreate .
.It osx.coreFoundation.CFRetainRelease
Check for null arguments to
-.Fn CFRetain
+.Fn CFRetain ,
+.Fn CFRelease ,
and
-.Fn CFRelease .
+.Fn CFMakeCollectable .
.It osx.coreFoundation.containers.OutOfBounds
Checks for index out-of-bounds when using the
.Vt CFArray
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index c280bb4d40a3..93824af255d6 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -20,10 +20,19 @@ def FindClangSpecs(path):
if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
yield os.path.join(root, f)
-def ModifySpec(path, pathToChecker):
+def ModifySpec(path, isBuiltinAnalyzer, pathToChecker):
t = tempfile.NamedTemporaryFile(delete=False)
foundAnalyzer = False
with open(path) as f:
+ if isBuiltinAnalyzer:
+ # First search for CLANG_ANALYZER_EXEC. Newer
+ # versions of Xcode set EXEC_PATH to be CLANG_ANALYZER_EXEC.
+ with open(path) as f2:
+ for line in f2:
+ if line.find("CLANG_ANALYZER_EXEC") >= 0:
+ pathToChecker = "$(CLANG_ANALYZER_EXEC)"
+ break
+ # Now create a new file.
for line in f:
if not foundAnalyzer:
if line.find("Static Analyzer") >= 0:
@@ -63,6 +72,7 @@ def main():
print "(-) You must quit Xcode first before modifying its configuration files."
return
+ isBuiltinAnalyzer = False
if options.path:
# Expand tildes.
path = os.path.expanduser(options.path)
@@ -74,19 +84,25 @@ def main():
else:
print "(+) Using the Clang bundled with Xcode"
path = options.default
+ isBuiltinAnalyzer = True
try:
xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
except AttributeError:
# Fall back to the default install location when using Python < 2.7.0
xcode_path = "/Developer"
- if (re.search("Xcode.app", xcode_path)):
+ if (xcode_path.find(".app/") != -1):
# Cut off the 'Developer' dir, as the xcspec lies in another part
# of the Xcode.app subtree.
xcode_path = os.path.dirname(xcode_path)
+ foundSpec = False
for x in FindClangSpecs(xcode_path):
- ModifySpec(x, path)
+ foundSpec = True
+ ModifySpec(x, isBuiltinAnalyzer, path)
+
+ if foundSpec == False:
+ print "(-) No compiler configuration file was found. Xcode's analyzer has not been updated."
if __name__ == '__main__':
main()
diff --git a/tools/scan-view/ScanView.py b/tools/scan-view/ScanView.py
index c6dddba6a764..32570b985838 100644
--- a/tools/scan-view/ScanView.py
+++ b/tools/scan-view/ScanView.py
@@ -707,6 +707,11 @@ File Bug</h3>
return None
def send_path(self, path):
+ # If the requested path is outside the root directory, do not open it
+ rel = os.path.abspath(os.path.join(self.server.root, path))
+ if not rel.startswith(os.path.abspath(self.server.root) ):
+ return self.send_404()
+
ctype = self.guess_type(path)
if ctype.startswith('text/'):
# Patch file instead
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 63418a2937a1..1ea293ee83ae 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -1,8 +1,11 @@
add_clang_unittest(ASTTests
CommentLexer.cpp
CommentParser.cpp
+ DeclPrinterTest.cpp
+ SourceLocationTest.cpp
+ StmtPrinterTest.cpp
)
target_link_libraries(ASTTests
- clangAST
+ clangAST clangASTMatchers clangTooling
)
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index cab0fdddbc2f..2723a611e106 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
#include "llvm/ADT/STLExtras.h"
@@ -29,8 +30,9 @@ protected:
CommentLexerTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ Traits(Allocator) {
}
FileSystemOptions FileMgrOpts;
@@ -39,8 +41,21 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
llvm::BumpPtrAllocator Allocator;
+ CommandTraits Traits;
void lexString(const char *Source, std::vector<Token> &Toks);
+
+ StringRef getCommandName(const Token &Tok) {
+ return Traits.getCommandInfo(Tok.getCommandID())->Name;
+ }
+
+ StringRef getVerbatimBlockName(const Token &Tok) {
+ return Traits.getCommandInfo(Tok.getVerbatimBlockID())->Name;
+ }
+
+ StringRef getVerbatimLineName(const Token &Tok) {
+ return Traits.getCommandInfo(Tok.getVerbatimLineID())->Name;
+ }
};
void CommentLexerTest::lexString(const char *Source,
@@ -49,9 +64,7 @@ void CommentLexerTest::lexString(const char *Source,
FileID File = SourceMgr.createFileIDForMemBuffer(Buf);
SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
- comments::CommandTraits Traits;
- comments::Lexer L(Allocator, Traits, Begin, CommentOptions(),
- Source, Source + strlen(Source));
+ Lexer L(Allocator, Traits, Begin, Source, Source + strlen(Source));
while (1) {
Token Tok;
@@ -310,7 +323,35 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
}
}
+// A command marker followed by a non-letter that is not a part of an escape
+// sequence.
TEST_F(CommentLexerTest, DoxygenCommand5) {
+ const char *Source = "/// \\^ \\0";
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(6U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::text, Toks[1].getKind());
+ ASSERT_EQ(StringRef("\\"), Toks[1].getText());
+
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef("^ "), Toks[2].getText());
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef("\\"), Toks[3].getText());
+
+ ASSERT_EQ(tok::text, Toks[4].getKind());
+ ASSERT_EQ(StringRef("0"), Toks[4].getText());
+
+ ASSERT_EQ(tok::newline, Toks[5].getKind());
+}
+
+TEST_F(CommentLexerTest, DoxygenCommand6) {
const char *Source = "/// \\brief Aaa.";
std::vector<Token> Toks;
@@ -322,7 +363,7 @@ TEST_F(CommentLexerTest, DoxygenCommand5) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::command, Toks[1].getKind());
- ASSERT_EQ(StringRef("brief"), Toks[1].getCommandName());
+ ASSERT_EQ(StringRef("brief"), getCommandName(Toks[1]));
ASSERT_EQ(tok::text, Toks[2].getKind());
ASSERT_EQ(StringRef(" Aaa."), Toks[2].getText());
@@ -330,7 +371,39 @@ TEST_F(CommentLexerTest, DoxygenCommand5) {
ASSERT_EQ(tok::newline, Toks[3].getKind());
}
-TEST_F(CommentLexerTest, DoxygenCommand6) {
+TEST_F(CommentLexerTest, DoxygenCommand7) {
+ const char *Source = "/// \\em\\em \\em\t\\em\n";
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(8U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[1]));
+
+ ASSERT_EQ(tok::command, Toks[2].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[2]));
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[3].getText());
+
+ ASSERT_EQ(tok::command, Toks[4].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[4]));
+
+ ASSERT_EQ(tok::text, Toks[5].getKind());
+ ASSERT_EQ(StringRef("\t"), Toks[5].getText());
+
+ ASSERT_EQ(tok::command, Toks[6].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[6]));
+
+ ASSERT_EQ(tok::newline, Toks[7].getKind());
+}
+
+TEST_F(CommentLexerTest, DoxygenCommand8) {
const char *Source = "/// \\aaa\\bbb \\ccc\t\\ddd\n";
std::vector<Token> Toks;
@@ -341,28 +414,28 @@ TEST_F(CommentLexerTest, DoxygenCommand6) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
- ASSERT_EQ(StringRef("aaa"), Toks[1].getCommandName());
+ ASSERT_EQ(tok::unknown_command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName());
- ASSERT_EQ(tok::command, Toks[2].getKind());
- ASSERT_EQ(StringRef("bbb"), Toks[2].getCommandName());
+ ASSERT_EQ(tok::unknown_command, Toks[2].getKind());
+ ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName());
ASSERT_EQ(tok::text, Toks[3].getKind());
ASSERT_EQ(StringRef(" "), Toks[3].getText());
- ASSERT_EQ(tok::command, Toks[4].getKind());
- ASSERT_EQ(StringRef("ccc"), Toks[4].getCommandName());
+ ASSERT_EQ(tok::unknown_command, Toks[4].getKind());
+ ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName());
ASSERT_EQ(tok::text, Toks[5].getKind());
ASSERT_EQ(StringRef("\t"), Toks[5].getText());
- ASSERT_EQ(tok::command, Toks[6].getKind());
- ASSERT_EQ(StringRef("ddd"), Toks[6].getCommandName());
+ ASSERT_EQ(tok::unknown_command, Toks[6].getKind());
+ ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName());
ASSERT_EQ(tok::newline, Toks[7].getKind());
}
-TEST_F(CommentLexerTest, DoxygenCommand7) {
+TEST_F(CommentLexerTest, DoxygenCommand9) {
const char *Source = "// \\c\n";
std::vector<Token> Toks;
@@ -374,7 +447,7 @@ TEST_F(CommentLexerTest, DoxygenCommand7) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::command, Toks[1].getKind());
- ASSERT_EQ(StringRef("c"), Toks[1].getCommandName());
+ ASSERT_EQ(StringRef("c"), getCommandName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
@@ -397,10 +470,10 @@ TEST_F(CommentLexerTest, VerbatimBlock1) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_end, Toks[2].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[2].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[2]));
ASSERT_EQ(tok::newline, Toks[3].getKind());
ASSERT_EQ(tok::newline, Toks[4].getKind());
@@ -421,7 +494,7 @@ TEST_F(CommentLexerTest, VerbatimBlock2) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
@@ -440,7 +513,7 @@ TEST_F(CommentLexerTest, VerbatimBlock3) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
ASSERT_EQ(tok::newline, Toks[3].getKind());
@@ -464,13 +537,13 @@ TEST_F(CommentLexerTest, VerbatimBlock4) {
ASSERT_EQ(StringRef(" Meow "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind());
ASSERT_EQ(StringRef(" aaa "), Toks[2].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[3].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[3].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[3]));
ASSERT_EQ(tok::newline, Toks[4].getKind());
ASSERT_EQ(tok::newline, Toks[5].getKind());
@@ -495,7 +568,7 @@ TEST_F(CommentLexerTest, VerbatimBlock5) {
ASSERT_EQ(StringRef(" Meow "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind());
ASSERT_EQ(StringRef(" aaa "), Toks[2].getVerbatimBlockText());
@@ -523,7 +596,7 @@ TEST_F(CommentLexerTest, VerbatimBlock6) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
@@ -540,7 +613,7 @@ TEST_F(CommentLexerTest, VerbatimBlock6) {
ASSERT_EQ(tok::newline, Toks[7].getKind());
ASSERT_EQ(tok::verbatim_block_end, Toks[8].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[8].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[8]));
ASSERT_EQ(tok::newline, Toks[9].getKind());
}
@@ -564,7 +637,7 @@ TEST_F(CommentLexerTest, VerbatimBlock7) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind());
ASSERT_EQ(StringRef(" Aaa"), Toks[2].getVerbatimBlockText());
@@ -576,7 +649,7 @@ TEST_F(CommentLexerTest, VerbatimBlock7) {
ASSERT_EQ(StringRef(" Bbb"), Toks[4].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[5].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[5].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[5]));
ASSERT_EQ(tok::newline, Toks[6].getKind());
@@ -605,7 +678,7 @@ TEST_F(CommentLexerTest, VerbatimBlock8) {
ASSERT_EQ(StringRef(" Meow "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind());
ASSERT_EQ(StringRef(" aaa\\$\\@"), Toks[2].getVerbatimBlockText());
@@ -620,19 +693,19 @@ TEST_F(CommentLexerTest, VerbatimBlock8) {
ASSERT_EQ(StringRef("ddd "), Toks[5].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[6].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[6].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[6]));
ASSERT_EQ(tok::text, Toks[7].getKind());
ASSERT_EQ(StringRef(" Blah "), Toks[7].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[8].getKind());
- ASSERT_EQ(StringRef("verbatim"), Toks[8].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[8]));
ASSERT_EQ(tok::verbatim_block_line, Toks[9].getKind());
ASSERT_EQ(StringRef(" eee"), Toks[9].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[10].getKind());
- ASSERT_EQ(StringRef("endverbatim"), Toks[10].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[10]));
ASSERT_EQ(tok::text, Toks[11].getKind());
ASSERT_EQ(StringRef(" BlahBlah"), Toks[11].getText());
@@ -655,37 +728,37 @@ TEST_F(CommentLexerTest, VerbatimBlock9) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind());
- ASSERT_EQ(StringRef("f$"), Toks[1].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f$"), getVerbatimBlockName(Toks[1]));
ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind());
ASSERT_EQ(StringRef(" Aaa "), Toks[2].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[3].getKind());
- ASSERT_EQ(StringRef("f$"), Toks[3].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f$"), getVerbatimBlockName(Toks[3]));
ASSERT_EQ(tok::text, Toks[4].getKind());
ASSERT_EQ(StringRef(" "), Toks[4].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[5].getKind());
- ASSERT_EQ(StringRef("f["), Toks[5].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f["), getVerbatimBlockName(Toks[5]));
ASSERT_EQ(tok::verbatim_block_line, Toks[6].getKind());
ASSERT_EQ(StringRef(" Bbb "), Toks[6].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[7].getKind());
- ASSERT_EQ(StringRef("f]"), Toks[7].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f]"), getVerbatimBlockName(Toks[7]));
ASSERT_EQ(tok::text, Toks[8].getKind());
ASSERT_EQ(StringRef(" "), Toks[8].getText());
ASSERT_EQ(tok::verbatim_block_begin, Toks[9].getKind());
- ASSERT_EQ(StringRef("f{"), Toks[9].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f{"), getVerbatimBlockName(Toks[9]));
ASSERT_EQ(tok::verbatim_block_line, Toks[10].getKind());
ASSERT_EQ(StringRef(" Ccc "), Toks[10].getVerbatimBlockText());
ASSERT_EQ(tok::verbatim_block_end, Toks[11].getKind());
- ASSERT_EQ(StringRef("f}"), Toks[11].getVerbatimBlockName());
+ ASSERT_EQ(StringRef("f}"), getVerbatimBlockName(Toks[11]));
ASSERT_EQ(tok::newline, Toks[12].getKind());
}
@@ -708,7 +781,7 @@ TEST_F(CommentLexerTest, VerbatimLine1) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind());
- ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName());
+ ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
ASSERT_EQ(tok::newline, Toks[3].getKind());
@@ -733,7 +806,7 @@ TEST_F(CommentLexerTest, VerbatimLine2) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind());
- ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName());
+ ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1]));
ASSERT_EQ(tok::verbatim_line_text, Toks[2].getKind());
ASSERT_EQ(StringRef(" void *foo(const char *zzz = \"\\$\");"),
@@ -761,7 +834,7 @@ TEST_F(CommentLexerTest, VerbatimLine3) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind());
- ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName());
+ ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1]));
ASSERT_EQ(tok::verbatim_line_text, Toks[2].getKind());
ASSERT_EQ(StringRef(" void *foo(const char *zzz = \"\\$\");"),
@@ -822,7 +895,7 @@ TEST_F(CommentLexerTest, HTML2) {
TEST_F(CommentLexerTest, HTML3) {
const char *Source =
- "// < tag";
+ "// < img";
std::vector<Token> Toks;
@@ -837,15 +910,15 @@ TEST_F(CommentLexerTest, HTML3) {
ASSERT_EQ(StringRef("<"), Toks[1].getText());
ASSERT_EQ(tok::text, Toks[2].getKind());
- ASSERT_EQ(StringRef(" tag"), Toks[2].getText());
+ ASSERT_EQ(StringRef(" img"), Toks[2].getText());
ASSERT_EQ(tok::newline, Toks[3].getKind());
}
TEST_F(CommentLexerTest, HTML4) {
const char *Sources[] = {
- "// <tag",
- "// <tag "
+ "// <img",
+ "// <img "
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -859,7 +932,7 @@ TEST_F(CommentLexerTest, HTML4) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
@@ -867,7 +940,7 @@ TEST_F(CommentLexerTest, HTML4) {
TEST_F(CommentLexerTest, HTML5) {
const char *Source =
- "// <tag 42";
+ "// <img 42";
std::vector<Token> Toks;
@@ -879,7 +952,7 @@ TEST_F(CommentLexerTest, HTML5) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::text, Toks[2].getKind());
ASSERT_EQ(StringRef("42"), Toks[2].getText());
@@ -888,7 +961,7 @@ TEST_F(CommentLexerTest, HTML5) {
}
TEST_F(CommentLexerTest, HTML6) {
- const char *Source = "// <tag> Meow";
+ const char *Source = "// <img> Meow";
std::vector<Token> Toks;
@@ -900,7 +973,7 @@ TEST_F(CommentLexerTest, HTML6) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_greater, Toks[2].getKind());
@@ -911,7 +984,7 @@ TEST_F(CommentLexerTest, HTML6) {
}
TEST_F(CommentLexerTest, HTML7) {
- const char *Source = "// <tag=";
+ const char *Source = "// <img=";
std::vector<Token> Toks;
@@ -923,7 +996,7 @@ TEST_F(CommentLexerTest, HTML7) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::text, Toks[2].getKind());
ASSERT_EQ(StringRef("="), Toks[2].getText());
@@ -932,7 +1005,7 @@ TEST_F(CommentLexerTest, HTML7) {
}
TEST_F(CommentLexerTest, HTML8) {
- const char *Source = "// <tag attr=> Meow";
+ const char *Source = "// <img src=> Meow";
std::vector<Token> Toks;
@@ -944,10 +1017,10 @@ TEST_F(CommentLexerTest, HTML8) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -961,8 +1034,8 @@ TEST_F(CommentLexerTest, HTML8) {
TEST_F(CommentLexerTest, HTML9) {
const char *Sources[] = {
- "// <tag attr",
- "// <tag attr "
+ "// <img src",
+ "// <img src "
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -976,10 +1049,10 @@ TEST_F(CommentLexerTest, HTML9) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::newline, Toks[3].getKind());
}
@@ -987,8 +1060,8 @@ TEST_F(CommentLexerTest, HTML9) {
TEST_F(CommentLexerTest, HTML10) {
const char *Sources[] = {
- "// <tag attr=",
- "// <tag attr ="
+ "// <img src=",
+ "// <img src ="
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1002,10 +1075,10 @@ TEST_F(CommentLexerTest, HTML10) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -1015,10 +1088,10 @@ TEST_F(CommentLexerTest, HTML10) {
TEST_F(CommentLexerTest, HTML11) {
const char *Sources[] = {
- "// <tag attr=\"",
- "// <tag attr = \"",
- "// <tag attr=\'",
- "// <tag attr = \'"
+ "// <img src=\"",
+ "// <img src = \"",
+ "// <img src=\'",
+ "// <img src = \'"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1032,10 +1105,10 @@ TEST_F(CommentLexerTest, HTML11) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -1047,7 +1120,7 @@ TEST_F(CommentLexerTest, HTML11) {
}
TEST_F(CommentLexerTest, HTML12) {
- const char *Source = "// <tag attr=@";
+ const char *Source = "// <img src=@";
std::vector<Token> Toks;
@@ -1059,10 +1132,10 @@ TEST_F(CommentLexerTest, HTML12) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -1074,10 +1147,10 @@ TEST_F(CommentLexerTest, HTML12) {
TEST_F(CommentLexerTest, HTML13) {
const char *Sources[] = {
- "// <tag attr=\"val\\\"\\'val",
- "// <tag attr=\"val\\\"\\'val\"",
- "// <tag attr=\'val\\\"\\'val",
- "// <tag attr=\'val\\\"\\'val\'"
+ "// <img src=\"val\\\"\\'val",
+ "// <img src=\"val\\\"\\'val\"",
+ "// <img src=\'val\\\"\\'val",
+ "// <img src=\'val\\\"\\'val\'"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1091,10 +1164,10 @@ TEST_F(CommentLexerTest, HTML13) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -1107,8 +1180,8 @@ TEST_F(CommentLexerTest, HTML13) {
TEST_F(CommentLexerTest, HTML14) {
const char *Sources[] = {
- "// <tag attr=\"val\\\"\\'val\">",
- "// <tag attr=\'val\\\"\\'val\'>"
+ "// <img src=\"val\\\"\\'val\">",
+ "// <img src=\'val\\\"\\'val\'>"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1122,10 +1195,10 @@ TEST_F(CommentLexerTest, HTML14) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_ident, Toks[2].getKind());
- ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent());
+ ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent());
ASSERT_EQ(tok::html_equals, Toks[3].getKind());
@@ -1140,8 +1213,8 @@ TEST_F(CommentLexerTest, HTML14) {
TEST_F(CommentLexerTest, HTML15) {
const char *Sources[] = {
- "// <tag/>",
- "// <tag />"
+ "// <img/>",
+ "// <img />"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1155,7 +1228,7 @@ TEST_F(CommentLexerTest, HTML15) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::html_slash_greater, Toks[2].getKind());
@@ -1165,8 +1238,8 @@ TEST_F(CommentLexerTest, HTML15) {
TEST_F(CommentLexerTest, HTML16) {
const char *Sources[] = {
- "// <tag/ Aaa",
- "// <tag / Aaa"
+ "// <img/ Aaa",
+ "// <img / Aaa"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
@@ -1180,7 +1253,7 @@ TEST_F(CommentLexerTest, HTML16) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_start_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName());
ASSERT_EQ(tok::text, Toks[2].getKind());
ASSERT_EQ(StringRef("/"), Toks[2].getText());
@@ -1201,13 +1274,13 @@ TEST_F(CommentLexerTest, HTML17) {
ASSERT_EQ(3U, Toks.size());
- ASSERT_EQ(tok::text, Toks[0].getKind());
- ASSERT_EQ(StringRef(" "), Toks[0].getText());
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::html_end_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef(""), Toks[1].getHTMLTagEndName());
+ ASSERT_EQ(tok::text, Toks[1].getKind());
+ ASSERT_EQ(StringRef("</"), Toks[1].getText());
- ASSERT_EQ(tok::newline, Toks[2].getKind());
+ ASSERT_EQ(tok::newline, Toks[2].getKind());
}
TEST_F(CommentLexerTest, HTML18) {
@@ -1219,20 +1292,20 @@ TEST_F(CommentLexerTest, HTML18) {
ASSERT_EQ(4U, Toks.size());
- ASSERT_EQ(tok::text, Toks[0].getKind());
- ASSERT_EQ(StringRef(" "), Toks[0].getText());
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::html_end_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef(""), Toks[1].getHTMLTagEndName());
+ ASSERT_EQ(tok::text, Toks[1].getKind());
+ ASSERT_EQ(StringRef("</"), Toks[1].getText());
- ASSERT_EQ(tok::text, Toks[2].getKind());
- ASSERT_EQ(StringRef("@"), Toks[2].getText());
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef("@"), Toks[2].getText());
- ASSERT_EQ(tok::newline, Toks[3].getKind());
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
}
TEST_F(CommentLexerTest, HTML19) {
- const char *Source = "// </tag";
+ const char *Source = "// </img";
std::vector<Token> Toks;
@@ -1244,35 +1317,51 @@ TEST_F(CommentLexerTest, HTML19) {
ASSERT_EQ(StringRef(" "), Toks[0].getText());
ASSERT_EQ(tok::html_end_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagEndName());
+ ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagEndName());
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
-TEST_F(CommentLexerTest, HTML20) {
- const char *Sources[] = {
- "// </tag>",
- "// </ tag>",
- "// </ tag >"
- };
+TEST_F(CommentLexerTest, NotAKnownHTMLTag1) {
+ const char *Source = "// <tag>";
- for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
- std::vector<Token> Toks;
+ std::vector<Token> Toks;
- lexString(Sources[i], Toks);
+ lexString(Source, Toks);
- ASSERT_EQ(4U, Toks.size());
+ ASSERT_EQ(4U, Toks.size());
- ASSERT_EQ(tok::text, Toks[0].getKind());
- ASSERT_EQ(StringRef(" "), Toks[0].getText());
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::html_end_tag, Toks[1].getKind());
- ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagEndName());
+ ASSERT_EQ(tok::text, Toks[1].getKind());
+ ASSERT_EQ(StringRef("<tag"), Toks[1].getText());
- ASSERT_EQ(tok::html_greater, Toks[2].getKind());
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef(">"), Toks[2].getText());
- ASSERT_EQ(tok::newline, Toks[3].getKind());
- }
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
+}
+
+TEST_F(CommentLexerTest, NotAKnownHTMLTag2) {
+ const char *Source = "// </tag>";
+
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(4U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::text, Toks[1].getKind());
+ ASSERT_EQ(StringRef("</tag"), Toks[1].getText());
+
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef(">"), Toks[2].getText());
+
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
}
TEST_F(CommentLexerTest, HTMLCharacterReferences1) {
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index 7258a7ef576c..8fde2478e74c 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/AST/Comment.h"
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentParser.h"
@@ -36,8 +37,9 @@ protected:
CommentParserTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ Traits(Allocator) {
}
FileSystemOptions FileMgrOpts;
@@ -46,6 +48,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
llvm::BumpPtrAllocator Allocator;
+ CommandTraits Traits;
FullComment *parseString(const char *Source);
};
@@ -55,17 +58,15 @@ FullComment *CommentParserTest::parseString(const char *Source) {
FileID File = SourceMgr.createFileIDForMemBuffer(Buf);
SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
- comments::CommandTraits Traits;
- comments::Lexer L(Allocator, Traits, Begin, CommentOptions(),
- Source, Source + strlen(Source));
+ Lexer L(Allocator, Traits, Begin, Source, Source + strlen(Source));
- comments::Sema S(Allocator, SourceMgr, Diags, Traits);
- comments::Parser P(L, S, Allocator, SourceMgr, Diags, Traits);
- comments::FullComment *FC = P.parseFullComment();
+ Sema S(Allocator, SourceMgr, Diags, Traits, /*PP=*/ NULL);
+ Parser P(L, S, Allocator, SourceMgr, Diags, Traits);
+ FullComment *FC = P.parseFullComment();
if (DEBUG) {
llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n";
- FC->dump(SourceMgr);
+ FC->dump(llvm::errs(), &Traits, &SourceMgr);
}
Token Tok;
@@ -157,6 +158,7 @@ template <typename T>
}
::testing::AssertionResult HasBlockCommandAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
BlockCommandComment *&BCC,
StringRef Name,
@@ -165,7 +167,7 @@ template <typename T>
if (!AR)
return AR;
- StringRef ActualName = BCC->getCommandName();
+ StringRef ActualName = BCC->getCommandName(Traits);
if (ActualName != Name)
return ::testing::AssertionFailure()
<< "BlockCommandComment has name \"" << ActualName.str() << "\", "
@@ -178,6 +180,7 @@ template <typename T>
::testing::AssertionResult HasParamCommandAt(
const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
ParamCommandComment *&PCC,
StringRef CommandName,
@@ -189,7 +192,7 @@ template <typename T>
if (!AR)
return AR;
- StringRef ActualCommandName = PCC->getCommandName();
+ StringRef ActualCommandName = PCC->getCommandName(Traits);
if (ActualCommandName != CommandName)
return ::testing::AssertionFailure()
<< "ParamCommandComment has name \"" << ActualCommandName.str() << "\", "
@@ -211,7 +214,7 @@ template <typename T>
return ::testing::AssertionFailure()
<< "ParamCommandComment has no parameter name";
- StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamName() : "";
+ StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamNameAsWritten() : "";
if (ActualParamName != ParamName)
return ::testing::AssertionFailure()
<< "ParamCommandComment has parameter name \"" << ActualParamName.str()
@@ -225,6 +228,7 @@ template <typename T>
::testing::AssertionResult HasTParamCommandAt(
const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
TParamCommandComment *&TPCC,
StringRef CommandName,
@@ -234,7 +238,7 @@ template <typename T>
if (!AR)
return AR;
- StringRef ActualCommandName = TPCC->getCommandName();
+ StringRef ActualCommandName = TPCC->getCommandName(Traits);
if (ActualCommandName != CommandName)
return ::testing::AssertionFailure()
<< "TParamCommandComment has name \"" << ActualCommandName.str() << "\", "
@@ -244,7 +248,7 @@ template <typename T>
return ::testing::AssertionFailure()
<< "TParamCommandComment has no parameter name";
- StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamName() : "";
+ StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamNameAsWritten() : "";
if (ActualParamName != ParamName)
return ::testing::AssertionFailure()
<< "TParamCommandComment has parameter name \"" << ActualParamName.str()
@@ -257,6 +261,7 @@ template <typename T>
}
::testing::AssertionResult HasInlineCommandAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
InlineCommandComment *&ICC,
StringRef Name) {
@@ -264,7 +269,7 @@ template <typename T>
if (!AR)
return AR;
- StringRef ActualName = ICC->getCommandName();
+ StringRef ActualName = ICC->getCommandName(Traits);
if (ActualName != Name)
return ::testing::AssertionFailure()
<< "InlineCommandComment has name \"" << ActualName.str() << "\", "
@@ -276,11 +281,12 @@ template <typename T>
struct NoArgs {};
::testing::AssertionResult HasInlineCommandAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
InlineCommandComment *&ICC,
StringRef Name,
NoArgs) {
- ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name);
+ ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
if (!AR)
return AR;
@@ -293,11 +299,12 @@ struct NoArgs {};
}
::testing::AssertionResult HasInlineCommandAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
InlineCommandComment *&ICC,
StringRef Name,
StringRef Arg) {
- ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name);
+ ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
if (!AR)
return AR;
@@ -452,6 +459,7 @@ struct NoAttrs {};
}
::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
VerbatimBlockComment *&VBC,
StringRef Name,
@@ -460,7 +468,7 @@ struct NoAttrs {};
if (!AR)
return AR;
- StringRef ActualName = VBC->getCommandName();
+ StringRef ActualName = VBC->getCommandName(Traits);
if (ActualName != Name)
return ::testing::AssertionFailure()
<< "VerbatimBlockComment has name \"" << ActualName.str() << "\", "
@@ -480,12 +488,13 @@ struct NoLines {};
struct Lines {};
::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
VerbatimBlockComment *&VBC,
StringRef Name,
StringRef CloseName,
NoLines) {
- ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
+ ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
CloseName);
if (!AR)
return AR;
@@ -499,13 +508,14 @@ struct Lines {};
}
::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
VerbatimBlockComment *&VBC,
StringRef Name,
StringRef CloseName,
Lines,
StringRef Line0) {
- ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
+ ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
CloseName);
if (!AR)
return AR;
@@ -525,6 +535,7 @@ struct Lines {};
}
::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
VerbatimBlockComment *&VBC,
StringRef Name,
@@ -532,7 +543,7 @@ struct Lines {};
Lines,
StringRef Line0,
StringRef Line1) {
- ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
+ ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
CloseName);
if (!AR)
return AR;
@@ -558,6 +569,7 @@ struct Lines {};
}
::testing::AssertionResult HasVerbatimLineAt(const Comment *C,
+ const CommandTraits &Traits,
size_t Idx,
VerbatimLineComment *&VLC,
StringRef Name,
@@ -566,7 +578,7 @@ struct Lines {};
if (!AR)
return AR;
- StringRef ActualName = VLC->getCommandName();
+ StringRef ActualName = VLC->getCommandName(Traits);
if (ActualName != Name)
return ::testing::AssertionFailure()
<< "VerbatimLineComment has name \"" << ActualName.str() << "\", "
@@ -651,7 +663,7 @@ TEST_F(CommentParserTest, Paragraph2) {
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa"));
}
@@ -668,14 +680,14 @@ TEST_F(CommentParserTest, Paragraph3) {
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " "));
}
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
ASSERT_TRUE(GetChildAt(BCC, 0, PC));
ASSERT_TRUE(HasChildCount(PC, 0));
@@ -695,7 +707,7 @@ TEST_F(CommentParserTest, Paragraph4) {
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
ASSERT_TRUE(GetChildAt(BCC, 0, PC));
ASSERT_TRUE(HasChildCount(PC, 2));
@@ -705,7 +717,7 @@ TEST_F(CommentParserTest, Paragraph4) {
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc"));
}
@@ -721,7 +733,7 @@ TEST_F(CommentParserTest, ParamCommand1) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::In,
/* IsDirectionExplicit = */ false,
"aaa", PC));
@@ -740,7 +752,7 @@ TEST_F(CommentParserTest, ParamCommand2) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::In,
/* IsDirectionExplicit = */ false,
"", PC));
@@ -750,7 +762,7 @@ TEST_F(CommentParserTest, ParamCommand2) {
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "brief", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
ASSERT_TRUE(HasChildCount(PC, 0));
}
}
@@ -774,7 +786,7 @@ TEST_F(CommentParserTest, ParamCommand3) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::In,
/* IsDirectionExplicit = */ false,
"aaa", PC));
@@ -804,7 +816,7 @@ TEST_F(CommentParserTest, ParamCommand4) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::In,
/* IsDirectionExplicit = */ true,
"aaa", PC));
@@ -834,7 +846,7 @@ TEST_F(CommentParserTest, ParamCommand5) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::Out,
/* IsDirectionExplicit = */ true,
"aaa", PC));
@@ -865,7 +877,7 @@ TEST_F(CommentParserTest, ParamCommand6) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::InOut,
/* IsDirectionExplicit = */ true,
"aaa", PC));
@@ -886,7 +898,7 @@ TEST_F(CommentParserTest, ParamCommand7) {
{
ParamCommandComment *PCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
+ ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
ParamCommandComment::In,
/* IsDirectionExplicit = */ false,
"aaa", PC));
@@ -920,7 +932,7 @@ TEST_F(CommentParserTest, TParamCommand1) {
{
TParamCommandComment *TPCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasTParamCommandAt(FC, 1, TPCC, "tparam",
+ ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam",
"aaa", PC));
ASSERT_TRUE(HasChildCount(TPCC, 1));
ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb"));
@@ -938,14 +950,14 @@ TEST_F(CommentParserTest, TParamCommand2) {
{
TParamCommandComment *TPCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasTParamCommandAt(FC, 1, TPCC, "tparam", "", PC));
+ ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "", PC));
ASSERT_TRUE(HasChildCount(TPCC, 1));
ASSERT_TRUE(HasChildCount(PC, 0));
}
{
BlockCommandComment *BCC;
ParagraphComment *PC;
- ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "brief", PC));
+ ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
ASSERT_TRUE(HasChildCount(PC, 0));
}
}
@@ -964,7 +976,7 @@ TEST_F(CommentParserTest, InlineCommand1) {
ASSERT_TRUE(HasChildCount(PC, 2));
ASSERT_TRUE(HasTextAt(PC, 0, " "));
- ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs()));
+ ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
}
}
@@ -981,7 +993,7 @@ TEST_F(CommentParserTest, InlineCommand2) {
ASSERT_TRUE(HasChildCount(PC, 3));
ASSERT_TRUE(HasTextAt(PC, 0, " "));
- ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs()));
+ ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
ASSERT_TRUE(HasTextAt(PC, 2, " "));
}
}
@@ -999,7 +1011,7 @@ TEST_F(CommentParserTest, InlineCommand3) {
ASSERT_TRUE(HasChildCount(PC, 2));
ASSERT_TRUE(HasTextAt(PC, 0, " "));
- ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa"));
+ ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
}
}
@@ -1016,7 +1028,7 @@ TEST_F(CommentParserTest, InlineCommand4) {
ASSERT_TRUE(HasChildCount(PC, 3));
ASSERT_TRUE(HasTextAt(PC, 0, " "));
- ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa"));
+ ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
ASSERT_TRUE(HasTextAt(PC, 2, " bbb"));
}
}
@@ -1034,7 +1046,7 @@ TEST_F(CommentParserTest, InlineCommand5) {
ASSERT_TRUE(HasChildCount(PC, 3));
ASSERT_TRUE(HasTextAt(PC, 0, " "));
- ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "unknown", NoArgs()));
+ ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "unknown", NoArgs()));
ASSERT_TRUE(HasTextAt(PC, 2, " aaa"));
}
}
@@ -1188,7 +1200,8 @@ TEST_F(CommentParserTest, VerbatimBlock1) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VCC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VCC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VCC,
+ "verbatim", "endverbatim",
NoLines()));
}
}
@@ -1202,7 +1215,8 @@ TEST_F(CommentParserTest, VerbatimBlock2) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
+ "verbatim", "endverbatim",
Lines(), " Aaa "));
}
}
@@ -1216,7 +1230,7 @@ TEST_F(CommentParserTest, VerbatimBlock3) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, "verbatim", "",
Lines(), " Aaa"));
}
}
@@ -1231,7 +1245,8 @@ TEST_F(CommentParserTest, VerbatimBlock4) {
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
+ "verbatim", "endverbatim",
NoLines()));
}
}
@@ -1253,7 +1268,8 @@ TEST_F(CommentParserTest, VerbatimBlock5) {
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
+ "verbatim", "endverbatim",
Lines(), " Aaa"));
}
}
@@ -1277,7 +1293,8 @@ TEST_F(CommentParserTest, VerbatimBlock6) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
+ "verbatim", "endverbatim",
Lines(), " Aaa"));
}
}
@@ -1303,7 +1320,8 @@ TEST_F(CommentParserTest, VerbatimBlock7) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
+ "verbatim", "endverbatim",
Lines(), " Aaa", " Bbb"));
}
}
@@ -1330,7 +1348,8 @@ TEST_F(CommentParserTest, VerbatimBlock8) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimBlockComment *VBC;
- ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim"));
+ ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
+ "verbatim", "endverbatim"));
ASSERT_EQ(3U, VBC->getNumLines());
ASSERT_EQ(" Aaa", VBC->getText(0));
ASSERT_EQ("", VBC->getText(1));
@@ -1352,7 +1371,7 @@ TEST_F(CommentParserTest, VerbatimLine1) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimLineComment *VLC;
- ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", ""));
+ ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", ""));
}
}
}
@@ -1370,7 +1389,7 @@ TEST_F(CommentParserTest, VerbatimLine2) {
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
{
VerbatimLineComment *VLC;
- ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn",
+ ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn",
" void *foo(const char *zzz = \"\\$\");"));
}
}
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
new file mode 100644
index 000000000000..a2fc839b9c8e
--- /dev/null
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -0,0 +1,1248 @@
+//===- unittests/AST/DeclPrinterTest.cpp --- Declaration printer tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for Decl::print() and related methods.
+//
+// Search this file for WRONG to see test cases that are producing something
+// completely wrong, invalid C++ or just misleading.
+//
+// These tests have a coding convention:
+// * declaration to be printed is named 'A' unless it should have some special
+// name (e.g., 'operator+');
+// * additional helper declarations are 'Z', 'Y', 'X' and so on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+namespace {
+
+void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D) {
+ PrintingPolicy Policy = Context->getPrintingPolicy();
+ Policy.TerseOutput = true;
+ D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false);
+}
+
+class PrintMatch : public MatchFinder::MatchCallback {
+ SmallString<1024> Printed;
+ unsigned NumFoundDecls;
+
+public:
+ PrintMatch() : NumFoundDecls(0) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ const Decl *D = Result.Nodes.getDeclAs<Decl>("id");
+ if (!D || D->isImplicit())
+ return;
+ NumFoundDecls++;
+ if (NumFoundDecls > 1)
+ return;
+
+ llvm::raw_svector_ostream Out(Printed);
+ PrintDecl(Out, Result.Context, D);
+ }
+
+ StringRef getPrinted() const {
+ return Printed;
+ }
+
+ unsigned getNumFoundDecls() const {
+ return NumFoundDecls;
+ }
+};
+
+::testing::AssertionResult PrintedDeclMatches(
+ StringRef Code,
+ const std::vector<std::string> &Args,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted,
+ StringRef FileName) {
+ PrintMatch Printer;
+ MatchFinder Finder;
+ Finder.addMatcher(NodeMatch, &Printer);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+
+ if (Printer.getNumFoundDecls() == 0)
+ return testing::AssertionFailure()
+ << "Matcher didn't find any declarations";
+
+ if (Printer.getNumFoundDecls() > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one declaration "
+ "(found " << Printer.getNumFoundDecls() << ")";
+
+ if (Printer.getPrinted() != ExpectedPrinted)
+ return ::testing::AssertionFailure()
+ << "Expected \"" << ExpectedPrinted << "\", "
+ "got \"" << Printer.getPrinted() << "\"";
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code,
+ StringRef DeclName,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "-std=c++98");
+ return PrintedDeclMatches(Code,
+ Args,
+ namedDecl(hasName(DeclName)).bind("id"),
+ ExpectedPrinted,
+ "input.cc");
+}
+
+::testing::AssertionResult PrintedDeclCXX98Matches(
+ StringRef Code,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "-std=c++98");
+ return PrintedDeclMatches(Code,
+ Args,
+ NodeMatch,
+ ExpectedPrinted,
+ "input.cc");
+}
+
+::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code,
+ StringRef DeclName,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "-std=c++11");
+ return PrintedDeclMatches(Code,
+ Args,
+ namedDecl(hasName(DeclName)).bind("id"),
+ ExpectedPrinted,
+ "input.cc");
+}
+
+::testing::AssertionResult PrintedDeclCXX11Matches(
+ StringRef Code,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "-std=c++11");
+ return PrintedDeclMatches(Code,
+ Args,
+ NodeMatch,
+ ExpectedPrinted,
+ "input.cc");
+}
+
+::testing::AssertionResult PrintedDeclObjCMatches(
+ StringRef Code,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args(1, "");
+ return PrintedDeclMatches(Code,
+ Args,
+ NodeMatch,
+ ExpectedPrinted,
+ "input.m");
+}
+
+} // unnamed namespace
+
+TEST(DeclPrinter, TestNamespace1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace A { int B; }",
+ "A",
+ "namespace A {\n}"));
+ // Should be: with { ... }
+}
+
+TEST(DeclPrinter, TestNamespace2) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "inline namespace A { int B; }",
+ "A",
+ "inline namespace A {\n}"));
+ // Should be: with { ... }
+}
+
+TEST(DeclPrinter, TestNamespaceAlias1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace Z { }"
+ "namespace A = Z;",
+ "A",
+ "namespace A = Z"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestNamespaceAlias2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "namespace X { namespace Y {} }"
+ "namespace A = X::Y;",
+ "A",
+ "namespace A = X::Y"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class A { int a; };",
+ "A",
+ "class A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A { int a; };",
+ "A",
+ "struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "union A { int a; };",
+ "A",
+ "union A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : Z { int b; };",
+ "A",
+ "class A : Z {\n}"));
+ // Should be: with semicolon, with { ... }, without two spaces
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z { int a; };"
+ "struct A : Z { int b; };",
+ "A",
+ "struct A : Z {\n}"));
+ // Should be: with semicolon, with { ... }, without two spaces
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : public Z { int b; };",
+ "A",
+ "class A : public Z {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl7) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : protected Z { int b; };",
+ "A",
+ "class A : protected Z {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl8) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : private Z { int b; };",
+ "A",
+ "class A : private Z {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl9) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : virtual Z { int b; };",
+ "A",
+ "class A : virtual Z {\n}"));
+ // Should be: with semicolon, with { ... }, without two spaces
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl10) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class A : virtual public Z { int b; };",
+ "A",
+ "class A : virtual public Z {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestCXXRecordDecl11) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class Z { int a; };"
+ "class Y : virtual public Z { int b; };"
+ "class A : virtual public Z, private Y { int c; };",
+ "A",
+ "class A : virtual public Z, private Y {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestFunctionDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A();",
+ "A",
+ "void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A() {}",
+ "A",
+ "void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void Z();"
+ "void A() { Z(); }",
+ "A",
+ "void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "extern void A();",
+ "A",
+ "extern void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "static void A();",
+ "A",
+ "static void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "inline void A();",
+ "A",
+ "inline void A()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl7) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "constexpr int A(int a);",
+ "A",
+ "int A(int a)"));
+ // WRONG; Should be: "constexpr int A(int a);"
+}
+
+TEST(DeclPrinter, TestFunctionDecl8) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A(int a);",
+ "A",
+ "void A(int a)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl9) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A(...);",
+ "A",
+ "void A(...)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl10) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A(int a, ...);",
+ "A",
+ "void A(int a, ...)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl11) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "typedef long size_t;"
+ "typedef int *pInt;"
+ "void A(int a, pInt b, size_t c);",
+ "A",
+ "void A(int a, pInt b, size_t c)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl12) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void A(int a, int b = 0);",
+ "A",
+ "void A(int a, int b = 0)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl13) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void (*A(int a))(int b);",
+ "A",
+ "void (*A(int a))(int)"));
+ // Should be: with semicolon, with parameter name (?)
+}
+
+TEST(DeclPrinter, TestFunctionDecl14) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "void A(T t) { }"
+ "template<>"
+ "void A(int N) { }",
+ functionDecl(hasName("A"), isExplicitTemplateSpecialization()).bind("id"),
+ "void A(int N)"));
+ // WRONG; Should be: "template <> void A(int N);"));
+}
+
+
+TEST(DeclPrinter, TestCXXConstructorDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " A();"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A();"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " A(int a);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A(int a);"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " A(const A &a);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A(const A &a);"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " A(const A &a, int = 0);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A(const A &a, int = 0);"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct A {"
+ " A(const A &&a);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A(const A &&a);"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " explicit A(int a);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "explicit A(int a);"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl7) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct A {"
+ " constexpr A();"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "constexpr A();"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl8) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct A {"
+ " A() = default;"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A() = default;"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl9) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct A {"
+ " A() = delete;"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ " = delete"));
+ // WRONG; Should be: "A() = delete;"
+}
+
+TEST(DeclPrinter, TestCXXConstructorDecl10) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T>"
+ "struct A {"
+ " A(const A &a);"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ ""));
+ // WRONG; Should be: "A(const A &a);"
+}
+
+#if !defined(_MSC_VER)
+TEST(DeclPrinter, TestCXXConstructorDecl11) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T>"
+ "struct A : public T... {"
+ " A(T&&... ts) : T(ts)... {}"
+ "};",
+ constructorDecl(ofClass(hasName("A"))).bind("id"),
+ "A<T...>(T &&ts...) : T(ts)"));
+ // WRONG; Should be: "A(T&&... ts) : T(ts)..."
+}
+#endif
+
+TEST(DeclPrinter, TestCXXDestructorDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " ~A();"
+ "};",
+ destructorDecl(ofClass(hasName("A"))).bind("id"),
+ "void ~A()"));
+ // WRONG; Should be: "~A();"
+}
+
+TEST(DeclPrinter, TestCXXDestructorDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " virtual ~A();"
+ "};",
+ destructorDecl(ofClass(hasName("A"))).bind("id"),
+ "virtual void ~A()"));
+ // WRONG; Should be: "virtual ~A();"
+}
+
+TEST(DeclPrinter, TestCXXConversionDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " operator int();"
+ "};",
+ methodDecl(ofClass(hasName("A"))).bind("id"),
+ "int operator int()"));
+ // WRONG; Should be: "operator int();"
+}
+
+TEST(DeclPrinter, TestCXXConversionDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct A {"
+ " operator bool();"
+ "};",
+ methodDecl(ofClass(hasName("A"))).bind("id"),
+ "bool operator _Bool()"));
+ // WRONG; Should be: "operator bool();"
+}
+
+TEST(DeclPrinter, TestCXXConversionDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {};"
+ "struct A {"
+ " operator Z();"
+ "};",
+ methodDecl(ofClass(hasName("A"))).bind("id"),
+ "Z operator struct Z()"));
+ // WRONG; Should be: "operator Z();"
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "namespace std { typedef decltype(sizeof(int)) size_t; }"
+ "struct Z {"
+ " void *operator new(std::size_t);"
+ "};",
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ "void *operator new(std::size_t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "namespace std { typedef decltype(sizeof(int)) size_t; }"
+ "struct Z {"
+ " void *operator new[](std::size_t);"
+ "};",
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ "void *operator new[](std::size_t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void operator delete(void *);"
+ "};",
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ "void operator delete(void *) noexcept"));
+ // Should be: with semicolon, without noexcept?
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void operator delete(void *);"
+ "};",
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ "void operator delete(void *)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void operator delete[](void *);"
+ "};",
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ "void operator delete[](void *) noexcept"));
+ // Should be: with semicolon, without noexcept?
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_Operator1) {
+ const char *OperatorNames[] = {
+ "+", "-", "*", "/", "%", "^", "&", "|",
+ "=", "<", ">", "+=", "-=", "*=", "/=", "%=",
+ "^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==", "!=",
+ "<=", ">=", "&&", "||", ",", "->*",
+ "()", "[]"
+ };
+
+ for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) {
+ SmallString<128> Code;
+ Code.append("struct Z { void operator");
+ Code.append(OperatorNames[i]);
+ Code.append("(Z z); };");
+
+ SmallString<128> Expected;
+ Expected.append("void operator");
+ Expected.append(OperatorNames[i]);
+ Expected.append("(Z z)");
+ // Should be: with semicolon
+
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ Code,
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ Expected));
+ }
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_Operator2) {
+ const char *OperatorNames[] = {
+ "~", "!", "++", "--", "->"
+ };
+
+ for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) {
+ SmallString<128> Code;
+ Code.append("struct Z { void operator");
+ Code.append(OperatorNames[i]);
+ Code.append("(); };");
+
+ SmallString<128> Expected;
+ Expected.append("void operator");
+ Expected.append(OperatorNames[i]);
+ Expected.append("()");
+ // Should be: with semicolon
+
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ Code,
+ methodDecl(ofClass(hasName("Z"))).bind("id"),
+ Expected));
+ }
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a);"
+ "};",
+ "A",
+ "void A(int a)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " virtual void A(int a);"
+ "};",
+ "A",
+ "virtual void A(int a)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " virtual void A(int a);"
+ "};"
+ "struct ZZ : Z {"
+ " void A(int a);"
+ "};",
+ "ZZ::A",
+ "void A(int a)"));
+ // Should be: with semicolon
+ // TODO: should we print "virtual"?
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " inline void A(int a);"
+ "};",
+ "A",
+ "inline void A(int a)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " virtual void A(int a) = 0;"
+ "};",
+ "A",
+ "virtual void A(int a) = 0"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a) const;"
+ "};",
+ "A",
+ "void A(int a) const"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a) volatile;"
+ "};",
+ "A",
+ "void A(int a) volatile"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a) const volatile;"
+ "};",
+ "A",
+ "void A(int a) const volatile"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier1) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void A(int a) &;"
+ "};",
+ "A",
+ "void A(int a)"));
+ // WRONG; Should be: "void A(int a) &;"
+}
+
+TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void A(int a) &&;"
+ "};",
+ "A",
+ "void A(int a)"));
+ // WRONG; Should be: "void A(int a) &&;"
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a) throw();"
+ "};",
+ "A",
+ "void A(int a) throw()"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z {"
+ " void A(int a) throw(int);"
+ "};",
+ "A",
+ "void A(int a) throw(int)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "class ZZ {};"
+ "struct Z {"
+ " void A(int a) throw(ZZ, int);"
+ "};",
+ "A",
+ "void A(int a) throw(ZZ, int)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification4) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void A(int a) noexcept;"
+ "};",
+ "A",
+ "void A(int a) noexcept"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification5) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void A(int a) noexcept(true);"
+ "};",
+ "A",
+ "void A(int a) noexcept(trueA(int a) noexcept(true)"));
+ // WRONG; Should be: "void A(int a) noexcept(true);"
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification6) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "struct Z {"
+ " void A(int a) noexcept(1 < 2);"
+ "};",
+ "A",
+ "void A(int a) noexcept(1 < 2A(int a) noexcept(1 < 2)"));
+ // WRONG; Should be: "void A(int a) noexcept(1 < 2);"
+}
+
+TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification7) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<int N>"
+ "struct Z {"
+ " void A(int a) noexcept(N < 2);"
+ "};",
+ "A",
+ "void A(int a) noexcept(N < 2A(int a) noexcept(N < 2)"));
+ // WRONG; Should be: "void A(int a) noexcept(N < 2);"
+}
+
+TEST(DeclPrinter, TestVarDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "char *const (*(*A)[5])(int);",
+ "A",
+ "char *const (*(*A)[5])(int)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestVarDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "void (*A)() throw(int);",
+ "A",
+ "void (*A)() throw(int)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestVarDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "void (*A)() noexcept;",
+ "A",
+ "void (*A)() noexcept"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFieldDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "struct Z { T A; };",
+ "A",
+ "T A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFieldDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<int N>"
+ "struct Z { int A[N]; };",
+ "A",
+ "int A[N]"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "struct A { T a; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T = int>"
+ "struct A { T a; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T = int> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<class T>"
+ "struct A { T a; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <class T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T, typename U>"
+ "struct A { T a; U b; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T, typename U> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<int N>"
+ "struct A { int a[N]; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <int N> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<int N = 42>"
+ "struct A { int a[N]; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <int N = 42> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl7) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "typedef int MyInt;"
+ "template<MyInt N>"
+ "struct A { int a[N]; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <MyInt N> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl8) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<template<typename U> class T> struct A { };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <template <typename U> class T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl9) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T> struct Z { };"
+ "template<template<typename U> class T = Z> struct A { };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <template <typename U> class T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl10) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T>"
+ "struct A { int a; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <typename ... T> struct A {\n}"));
+ // Should be: with semicolon, with { ... }, without spaces before '...'
+}
+
+TEST(DeclPrinter, TestClassTemplateDecl11) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T>"
+ "struct A : public T... { int a; };",
+ classTemplateDecl(hasName("A")).bind("id"),
+ "template <typename ... T> struct A : public T... {\n}"));
+ // Should be: with semicolon, with { ... }, without spaces before '...'
+}
+
+TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T, typename U>"
+ "struct A { T a; U b; };"
+ "template<typename T>"
+ "struct A<T, int> { T a; };",
+ classTemplateSpecializationDecl().bind("id"),
+ "struct A {\n}"));
+ // WRONG; Should be: "template<typename T> struct A<T, int> { ... }"
+}
+
+TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "struct A { T a; };"
+ "template<typename T>"
+ "struct A<T *> { T a; };",
+ classTemplateSpecializationDecl().bind("id"),
+ "struct A {\n}"));
+ // WRONG; Should be: "template<typename T> struct A<T *> { ... }"
+}
+
+TEST(DeclPrinter, TestClassTemplateSpecializationDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "struct A { T a; };"
+ "template<>"
+ "struct A<int> { int a; };",
+ classTemplateSpecializationDecl().bind("id"),
+ "struct A {\n}"));
+ // WRONG; Should be: "template<> struct A<int> { ... }"
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "void A(T &t);",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T> void A(T &t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T>"
+ "void A(T &t) { }",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T> void A(T &t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl3) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T>"
+ "void A(T... a);",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename ... T> void A(T a...)"));
+ // WRONG; Should be: "template <typename ... T> void A(T... a)"
+ // (not "T a...")
+ // Should be: with semicolon.
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl4) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z { template<typename T> void A(T t); };",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T> void A(T t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "struct Z { template<typename T> void A(T t) {} };",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename T> void A(T t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestFunctionTemplateDecl6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T >struct Z {"
+ " template<typename U> void A(U t) {}"
+ "};",
+ functionTemplateDecl(hasName("A")).bind("id"),
+ "template <typename U> void A(U t)"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList1) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T> struct Z {};"
+ "struct X {};"
+ "Z<X> A;",
+ "A",
+ "Z<X> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList2) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T, typename U> struct Z {};"
+ "struct X {};"
+ "typedef int Y;"
+ "Z<X, Y> A;",
+ "A",
+ "Z<X, Y> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList3) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T> struct Z {};"
+ "template<typename T> struct X {};"
+ "Z<X<int> > A;",
+ "A",
+ "Z<X<int> > A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList4) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename T> struct Z {};"
+ "template<typename T> struct X {};"
+ "Z<X<int>> A;",
+ "A",
+ "Z<X<int> > A"));
+ // Should be: with semicolon, without extra space in "> >"
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList5) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T> struct Z {};"
+ "template<typename T> struct X { Z<T> A; };",
+ "A",
+ "Z<T> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList6) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<template<typename T> class U> struct Z {};"
+ "template<typename T> struct X {};"
+ "Z<X> A;",
+ "A",
+ "Z<X> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList7) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<template<typename T> class U> struct Z {};"
+ "template<template<typename T> class U> struct Y {"
+ " Z<U> A;"
+ "};",
+ "A",
+ "Z<U> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList8) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<typename T> struct Z {};"
+ "template<template<typename T> class U> struct Y {"
+ " Z<U<int> > A;"
+ "};",
+ "A",
+ "Z<U<int> > A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList9) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<unsigned I> struct Z {};"
+ "Z<0> A;",
+ "A",
+ "Z<0> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList10) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<unsigned I> struct Z {};"
+ "template<unsigned I> struct X { Z<I> A; };",
+ "A",
+ "Z<I> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList11) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<int I> struct Z {};"
+ "Z<42 * 10 - 420 / 1> A;",
+ "A",
+ "Z<42 * 10 - 420 / 1> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList12) {
+ ASSERT_TRUE(PrintedDeclCXX98Matches(
+ "template<const char *p> struct Z {};"
+ "extern const char X[] = \"aaa\";"
+ "Z<X> A;",
+ "A",
+ "Z<X> A"));
+ // Should be: with semicolon
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList13) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T> struct Z {};"
+ "template<typename... T> struct X {"
+ " Z<T...> A;"
+ "};",
+ "A",
+ "Z<T...> A"));
+ // Should be: with semicolon, without extra space in "> >"
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList14) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<typename... T> struct Z {};"
+ "template<typename T> struct Y {};"
+ "template<typename... T> struct X {"
+ " Z<Y<T>...> A;"
+ "};",
+ "A",
+ "Z<Y<T>...> A"));
+ // Should be: with semicolon, without extra space in "> >"
+}
+
+TEST(DeclPrinter, TestTemplateArgumentList15) {
+ ASSERT_TRUE(PrintedDeclCXX11Matches(
+ "template<unsigned I> struct Z {};"
+ "template<typename... T> struct X {"
+ " Z<sizeof...(T)> A;"
+ "};",
+ "A",
+ "Z<sizeof...(T)> A"));
+ // Should be: with semicolon, without extra space in "> >"
+}
+
+TEST(DeclPrinter, TestObjCMethod1) {
+ ASSERT_TRUE(PrintedDeclObjCMatches(
+ "__attribute__((objc_root_class)) @interface X\n"
+ "- (int)A:(id)anObject inRange:(long)range;\n"
+ "@end\n"
+ "@implementation X\n"
+ "- (int)A:(id)anObject inRange:(long)range { int printThis; return 0; }\n"
+ "@end\n",
+ namedDecl(hasName("A:inRange:"),
+ hasDescendant(namedDecl(hasName("printThis")))).bind("id"),
+ "- (int) A:(id)anObject inRange:(long)range"));
+}
+
diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile
index 31cd5de1b741..e07fc45467b3 100644
--- a/unittests/AST/Makefile
+++ b/unittests/AST/Makefile
@@ -9,7 +9,11 @@
CLANG_LEVEL = ../..
TESTNAME = AST
-LINK_COMPONENTS := support mc
-USEDLIBS = clangAST.a clangLex.a clangBasic.a
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewriteCore.a clangRewriteFrontend.a \
+ clangParse.a clangSema.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
new file mode 100644
index 000000000000..dec833d15d80
--- /dev/null
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -0,0 +1,289 @@
+//===- unittest/AST/SourceLocationTest.cpp - AST source loc unit tests ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for SourceLocation and SourceRange fields
+// in AST nodes.
+//
+// FIXME: In the long-term, when we test more than source locations, we may
+// want to have a unit test file for an AST node (or group of related nodes),
+// rather than a unit test file for source locations for all AST nodes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCodeWithArgs;
+using clang::tooling::FrontendActionFactory;
+
+enum Language { Lang_C, Lang_C89, Lang_CXX };
+
+/// \brief Base class for verifying some property of nodes found by a matcher.
+///
+/// FIXME: This class should be shared with other AST tests.
+template <typename NodeType>
+class MatchVerifier : public MatchFinder::MatchCallback {
+public:
+ template <typename MatcherType>
+ testing::AssertionResult match(const std::string &Code,
+ const MatcherType &AMatcher) {
+ return match(Code, AMatcher, Lang_CXX);
+ }
+
+ template <typename MatcherType>
+ testing::AssertionResult match(const std::string &Code,
+ const MatcherType &AMatcher, Language L);
+
+protected:
+ virtual void run(const MatchFinder::MatchResult &Result);
+ virtual void verify(const MatchFinder::MatchResult &Result,
+ const NodeType &Node) = 0;
+
+ void setFailure(const Twine &Result) {
+ Verified = false;
+ VerifyResult = Result.str();
+ }
+
+private:
+ bool Verified;
+ std::string VerifyResult;
+};
+
+/// \brief Runs a matcher over some code, and returns the result of the
+/// 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) {
+ MatchFinder Finder;
+ Finder.addMatcher(AMatcher.bind(""), this);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+
+ std::vector<std::string> Args;
+ StringRef FileName;
+ switch (L) {
+ case Lang_C:
+ Args.push_back("-std=c99");
+ FileName = "input.c";
+ break;
+ case Lang_C89:
+ Args.push_back("-std=c89");
+ FileName = "input.c";
+ break;
+ case Lang_CXX:
+ Args.push_back("-std=c++98");
+ FileName = "input.cc";
+ break;
+ }
+
+ // Default to failure in case callback is never called
+ setFailure("Could not find match");
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
+ return testing::AssertionFailure() << "Parsing error";
+ if (!Verified)
+ return testing::AssertionFailure() << VerifyResult;
+ return testing::AssertionSuccess();
+}
+
+template <typename NodeType>
+void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
+ const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
+ if (!Node) {
+ setFailure("Matched node has wrong type");
+ } else {
+ // Callback has been called, default to success
+ Verified = true;
+ verify(Result, *Node);
+ }
+}
+
+/// \brief Verify whether a node has the correct source location.
+///
+/// By default, Node.getSourceLocation() is checked. This can be changed
+/// by overriding getLocation().
+template <typename NodeType>
+class LocationVerifier : public MatchVerifier<NodeType> {
+public:
+ void expectLocation(unsigned Line, unsigned Column) {
+ ExpectLine = Line;
+ ExpectColumn = Column;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ SourceLocation Loc = getLocation(Node);
+ unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
+ unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
+ if (Line != ExpectLine || Column != ExpectColumn) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
+ << ">, found <";
+ Loc.print(Msg, *Result.SourceManager);
+ Msg << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+ virtual SourceLocation getLocation(const NodeType &Node) {
+ return Node.getLocation();
+ }
+
+private:
+ unsigned ExpectLine, ExpectColumn;
+};
+
+/// \brief Verify whether a node has the correct source range.
+///
+/// By default, Node.getSourceRange() is checked. This can be changed
+/// by overriding getRange().
+template <typename NodeType>
+class RangeVerifier : public MatchVerifier<NodeType> {
+public:
+ void expectRange(unsigned BeginLine, unsigned BeginColumn,
+ unsigned EndLine, unsigned EndColumn) {
+ ExpectBeginLine = BeginLine;
+ ExpectBeginColumn = BeginColumn;
+ ExpectEndLine = EndLine;
+ ExpectEndColumn = EndColumn;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ SourceRange R = getRange(Node);
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+ unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
+ unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
+ unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
+ unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
+ if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
+ EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
+ << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
+ Begin.print(Msg, *Result.SourceManager);
+ Msg << '-';
+ End.print(Msg, *Result.SourceManager);
+ Msg << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+ virtual SourceRange getRange(const NodeType &Node) {
+ return Node.getSourceRange();
+ }
+
+private:
+ unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
+};
+
+TEST(MatchVerifier, ParseError) {
+ LocationVerifier<VarDecl> Verifier;
+ Verifier.expectLocation(1, 1);
+ EXPECT_FALSE(Verifier.match("int i", varDecl()));
+}
+
+TEST(MatchVerifier, NoMatch) {
+ LocationVerifier<VarDecl> Verifier;
+ Verifier.expectLocation(1, 1);
+ EXPECT_FALSE(Verifier.match("int i;", recordDecl()));
+}
+
+TEST(MatchVerifier, WrongType) {
+ LocationVerifier<RecordDecl> Verifier;
+ Verifier.expectLocation(1, 1);
+ EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+TEST(LocationVerifier, WrongLocation) {
+ LocationVerifier<VarDecl> Verifier;
+ Verifier.expectLocation(1, 1);
+ EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+TEST(RangeVerifier, WrongRange) {
+ RangeVerifier<VarDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 1);
+ EXPECT_FALSE(Verifier.match("int i;", varDecl()));
+}
+
+class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> {
+protected:
+ virtual SourceRange getRange(const LabelStmt &Node) {
+ return Node.getDecl()->getSourceRange();
+ }
+};
+
+TEST(LabelDecl, Range) {
+ LabelDeclRangeVerifier Verifier;
+ Verifier.expectRange(1, 12, 1, 12);
+ EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
+}
+
+TEST(LabelStmt, Range) {
+ RangeVerifier<LabelStmt> Verifier;
+ Verifier.expectRange(1, 12, 1, 15);
+ EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
+}
+
+TEST(ParmVarDecl, KNRLocation) {
+ LocationVerifier<ParmVarDecl> Verifier;
+ Verifier.expectLocation(1, 8);
+ EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
+}
+
+TEST(ParmVarDecl, KNRRange) {
+ RangeVerifier<ParmVarDecl> Verifier;
+ Verifier.expectRange(1, 8, 1, 8);
+ EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
+}
+
+TEST(CXXNewExpr, ArrayRange) {
+ RangeVerifier<CXXNewExpr> Verifier;
+ Verifier.expectRange(1, 12, 1, 22);
+ EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", newExpr()));
+}
+
+TEST(CXXNewExpr, ParenRange) {
+ RangeVerifier<CXXNewExpr> Verifier;
+ Verifier.expectRange(1, 12, 1, 20);
+ EXPECT_TRUE(Verifier.match("void f() { new int(); }", newExpr()));
+}
+
+TEST(MemberExpr, ImplicitMemberRange) {
+ RangeVerifier<MemberExpr> Verifier;
+ Verifier.expectRange(2, 30, 2, 30);
+ EXPECT_TRUE(Verifier.match("struct S { operator int() const; };\n"
+ "int foo(const S& s) { return s; }",
+ memberExpr()));
+}
+
+TEST(VarDecl, VMTypeFixedVarDeclRange) {
+ RangeVerifier<VarDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 23);
+ EXPECT_TRUE(Verifier.match("int a[(int)(void*)1234];",
+ varDecl(), Lang_C89));
+}
+
+TEST(CXXConstructorDecl, NoRetFunTypeLocRange) {
+ RangeVerifier<CXXConstructorDecl> Verifier;
+ Verifier.expectRange(1, 11, 1, 13);
+ EXPECT_TRUE(Verifier.match("class C { C(); };", functionDecl()));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
new file mode 100644
index 000000000000..0fd1b2e6c3c8
--- /dev/null
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -0,0 +1,172 @@
+//===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for Stmt::printPretty() and related methods.
+//
+// Search this file for WRONG to see test cases that are producing something
+// completely wrong, invalid C++ or just misleading.
+//
+// These tests have a coding convention:
+// * statements to be printed should be contained within a function named 'A'
+// unless it should have some special name (e.g., 'operator+');
+// * additional helper declarations are 'Z', 'Y', 'X' and so on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+namespace {
+
+void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) {
+ PrintingPolicy Policy = Context->getPrintingPolicy();
+ S->printPretty(Out, /*Helper*/ 0, Policy);
+}
+
+class PrintMatch : public MatchFinder::MatchCallback {
+ SmallString<1024> Printed;
+ unsigned NumFoundStmts;
+
+public:
+ PrintMatch() : NumFoundStmts(0) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id");
+ if (!S)
+ return;
+ NumFoundStmts++;
+ if (NumFoundStmts > 1)
+ return;
+
+ llvm::raw_svector_ostream Out(Printed);
+ PrintStmt(Out, Result.Context, S);
+ }
+
+ StringRef getPrinted() const {
+ return Printed;
+ }
+
+ unsigned getNumFoundStmts() const {
+ return NumFoundStmts;
+ }
+};
+
+::testing::AssertionResult PrintedStmtMatches(
+ StringRef Code,
+ const std::vector<std::string> &Args,
+ const DeclarationMatcher &NodeMatch,
+ StringRef ExpectedPrinted) {
+
+ PrintMatch Printer;
+ MatchFinder Finder;
+ Finder.addMatcher(NodeMatch, &Printer);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+
+ if (Printer.getNumFoundStmts() == 0)
+ return testing::AssertionFailure()
+ << "Matcher didn't find any statements";
+
+ if (Printer.getNumFoundStmts() > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one statement "
+ "(found " << Printer.getNumFoundStmts() << ")";
+
+ if (Printer.getPrinted() != ExpectedPrinted)
+ return ::testing::AssertionFailure()
+ << "Expected \"" << ExpectedPrinted << "\", "
+ "got \"" << Printer.getPrinted() << "\"";
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult PrintedStmtCXX98Matches(
+ StringRef Code,
+ StringRef ContainingFunction,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args;
+ Args.push_back("-std=c++98");
+ Args.push_back("-Wno-unused-value");
+ return PrintedStmtMatches(Code,
+ Args,
+ functionDecl(hasName(ContainingFunction),
+ has(compoundStmt(has(stmt().bind("id"))))),
+ ExpectedPrinted);
+}
+
+::testing::AssertionResult PrintedStmtMSMatches(
+ StringRef Code,
+ StringRef ContainingFunction,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args;
+ Args.push_back("-std=c++98");
+ Args.push_back("-fms-extensions");
+ Args.push_back("-Wno-unused-value");
+ return PrintedStmtMatches(Code,
+ Args,
+ functionDecl(hasName(ContainingFunction),
+ has(compoundStmt(has(stmt().bind("id"))))),
+ ExpectedPrinted);
+}
+
+} // unnamed namespace
+
+TEST(StmtPrinter, TestIntegerLiteral) {
+ ASSERT_TRUE(PrintedStmtCXX98Matches(
+ "void A() {"
+ " 1, -1, 1U, 1u,"
+ " 1L, 1l, -1L, 1UL, 1ul,"
+ " 1LL, -1LL, 1ULL;"
+ "}",
+ "A",
+ "1 , -1 , 1U , 1U , "
+ "1L , 1L , -1L , 1UL , 1UL , "
+ "1LL , -1LL , 1ULL"));
+ // Should be: with semicolon
+}
+
+TEST(StmtPrinter, TestMSIntegerLiteral) {
+ ASSERT_TRUE(PrintedStmtMSMatches(
+ "void A() {"
+ " 1i8, -1i8, 1ui8, "
+ " 1i16, -1i16, 1ui16, "
+ " 1i32, -1i32, 1ui32, "
+ " 1i64, -1i64, 1ui64, "
+ " 1i128, -1i128, 1ui128, 1Ui128,"
+ " 0x10000000000000000i128;"
+ "}",
+ "A",
+ "1 , -1 , 1U , "
+ "1 , -1 , 1U , "
+ "1L , -1L , 1UL , "
+ "1LL , -1LL , 1ULL , "
+ "1 , -1 , 1U , 1U , "
+ "18446744073709551616i128"));
+ // Should be: with semicolon
+ // WRONG; all 128-bit literals should be printed as 128-bit.
+ // (This is because currently we do semantic analysis incorrectly.)
+}
+
+TEST(StmtPrinter, TestFloatingPointLiteral) {
+ ASSERT_TRUE(PrintedStmtCXX98Matches(
+ "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
+ "A",
+ "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
+ // Should be: with semicolon
+}
+
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index adf0e9479f08..e15940aea427 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -19,21 +19,21 @@ namespace ast_matchers {
#if GTEST_HAS_DEATH_TEST
TEST(HasNameDeathTest, DiesOnEmptyName) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher HasEmptyName = record(hasName(""));
+ DeclarationMatcher HasEmptyName = recordDecl(hasName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(HasNameDeathTest, DiesOnEmptyPattern) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher HasEmptyName = record(matchesName(""));
+ DeclarationMatcher HasEmptyName = recordDecl(matchesName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom(""));
+ DeclarationMatcher IsDerivedFromEmpty = recordDecl(isDerivedFrom(""));
EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty));
}, "");
}
@@ -46,7 +46,7 @@ TEST(Decl, MatchesDeclarations) {
}
TEST(NameableDeclaration, MatchesVariousDecls) {
- DeclarationMatcher NamedX = nameableDeclaration(hasName("X"));
+ DeclarationMatcher NamedX = namedDecl(hasName("X"));
EXPECT_TRUE(matches("typedef int X;", NamedX));
EXPECT_TRUE(matches("int X;", NamedX));
EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
@@ -59,7 +59,7 @@ TEST(NameableDeclaration, MatchesVariousDecls) {
}
TEST(NameableDeclaration, REMatchesVariousDecls) {
- DeclarationMatcher NamedX = nameableDeclaration(matchesName("::X"));
+ DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
EXPECT_TRUE(matches("typedef int Xa;", NamedX));
EXPECT_TRUE(matches("int Xb;", NamedX));
EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
@@ -70,11 +70,11 @@ TEST(NameableDeclaration, REMatchesVariousDecls) {
EXPECT_TRUE(notMatches("#define Xkl 1", NamedX));
- DeclarationMatcher StartsWithNo = nameableDeclaration(matchesName("::no"));
+ DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
EXPECT_TRUE(matches("int no_foo;", StartsWithNo));
EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
- DeclarationMatcher Abc = nameableDeclaration(matchesName("a.*b.*c"));
+ DeclarationMatcher Abc = namedDecl(matchesName("a.*b.*c"));
EXPECT_TRUE(matches("int abc;", Abc));
EXPECT_TRUE(matches("int aFOObBARc;", Abc));
EXPECT_TRUE(notMatches("int cab;", Abc));
@@ -82,7 +82,7 @@ TEST(NameableDeclaration, REMatchesVariousDecls) {
}
TEST(DeclarationMatcher, MatchClass) {
- DeclarationMatcher ClassMatcher(record());
+ DeclarationMatcher ClassMatcher(recordDecl());
#if !defined(_MSC_VER)
EXPECT_FALSE(matches("", ClassMatcher));
#else
@@ -90,7 +90,7 @@ TEST(DeclarationMatcher, MatchClass) {
EXPECT_TRUE(matches("", ClassMatcher));
#endif
- DeclarationMatcher ClassX = record(record(hasName("X")));
+ DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X")));
EXPECT_TRUE(matches("class X;", ClassX));
EXPECT_TRUE(matches("class X {};", ClassX));
EXPECT_TRUE(matches("template<class T> class X {};", ClassX));
@@ -98,17 +98,24 @@ TEST(DeclarationMatcher, MatchClass) {
}
TEST(DeclarationMatcher, ClassIsDerived) {
- DeclarationMatcher IsDerivedFromX = record(isDerivedFrom("X"));
+ DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X"));
EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X;", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X;", IsDerivedFromX));
EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX));
EXPECT_TRUE(notMatches("", IsDerivedFromX));
+ DeclarationMatcher IsAX = recordDecl(isSameOrDerivedFrom("X"));
+
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX));
+ EXPECT_TRUE(matches("class X {};", IsAX));
+ EXPECT_TRUE(matches("class X;", IsAX));
+ EXPECT_TRUE(notMatches("class Y;", IsAX));
+ EXPECT_TRUE(notMatches("", IsAX));
+
DeclarationMatcher ZIsDerivedFromX =
- record(hasName("Z"), isDerivedFrom("X"));
+ recordDecl(hasName("Z"), isDerivedFrom("X"));
EXPECT_TRUE(
matches("class X {}; class Y : public X {}; class Z : public Y {};",
ZIsDerivedFromX));
@@ -239,19 +246,17 @@ TEST(DeclarationMatcher, ClassIsDerived) {
"void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }";
EXPECT_TRUE(matches(
RecursiveTemplateOneParameter,
- variable(hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateOneParameter,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateOneParameter,
- variable(
- hasName("z_char"),
- hasInitializer(hasType(record(isDerivedFrom("Base1"),
- isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_char"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
const char *RecursiveTemplateTwoParameters =
"class Base1 {}; class Base2 {};"
@@ -266,47 +271,81 @@ TEST(DeclarationMatcher, ClassIsDerived) {
" Z<char, void> z_char; }";
EXPECT_TRUE(matches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_char"),
- hasInitializer(hasType(record(isDerivedFrom("Base1"),
- isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_char"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
"namespace ns { class X {}; class Y : public X {}; }",
- record(isDerivedFrom("::ns::X"))));
+ recordDecl(isDerivedFrom("::ns::X"))));
EXPECT_TRUE(notMatches(
"class X {}; class Y : public X {};",
- record(isDerivedFrom("::ns::X"))));
+ recordDecl(isDerivedFrom("::ns::X"))));
EXPECT_TRUE(matches(
"class X {}; class Y : public X {};",
- record(isDerivedFrom(record(hasName("X")).bind("test")))));
+ recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
+}
+
+TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct A {"
+ " template <typename T2> struct F {};"
+ "};"
+ "template <typename T> struct B : A<T>::template F<T> {};"
+ "B<int> b;",
+ recordDecl(hasName("B"), isDerivedFrom(recordDecl()))));
+}
+
+TEST(ClassTemplate, DoesNotMatchClass) {
+ DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
+ EXPECT_TRUE(notMatches("class X;", ClassX));
+ EXPECT_TRUE(notMatches("class X {};", ClassX));
+}
+
+TEST(ClassTemplate, MatchesClassTemplate) {
+ DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
+ EXPECT_TRUE(matches("template<typename T> class X {};", ClassX));
+ EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) {
+ EXPECT_TRUE(notMatches("template<typename T> class X { };"
+ "template<> class X<int> { int a; };",
+ classTemplateDecl(hasName("X"),
+ hasDescendant(fieldDecl(hasName("a"))))));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) {
+ EXPECT_TRUE(notMatches("template<typename T, typename U> class X { };"
+ "template<typename T> class X<T, int> { int a; };",
+ classTemplateDecl(hasName("X"),
+ hasDescendant(fieldDecl(hasName("a"))))));
}
TEST(AllOf, AllOverloadsWork) {
const char Program[] =
"struct T { }; int f(int, T*); void g(int x) { T t; f(x, &t); }";
EXPECT_TRUE(matches(Program,
- call(allOf(callee(function(hasName("f"))),
- hasArgument(0, declarationReference(to(variable())))))));
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl())))))));
EXPECT_TRUE(matches(Program,
- call(allOf(callee(function(hasName("f"))),
- hasArgument(0, declarationReference(to(variable()))),
- hasArgument(1, hasType(pointsTo(record(hasName("T")))))))));
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl()))),
+ hasArgument(1, hasType(pointsTo(
+ recordDecl(hasName("T")))))))));
}
TEST(DeclarationMatcher, MatchAnyOf) {
DeclarationMatcher YOrZDerivedFromX =
- record(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z"))));
+ recordDecl(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z"))));
EXPECT_TRUE(
matches("class X {}; class Z : public X {};", YOrZDerivedFromX));
EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX));
@@ -315,13 +354,13 @@ TEST(DeclarationMatcher, MatchAnyOf) {
EXPECT_TRUE(notMatches("class Z {};", YOrZDerivedFromX));
DeclarationMatcher XOrYOrZOrU =
- record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U")));
+ recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U")));
EXPECT_TRUE(matches("class X {};", XOrYOrZOrU));
EXPECT_TRUE(notMatches("class V {};", XOrYOrZOrU));
DeclarationMatcher XOrYOrZOrUOrV =
- record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"),
- hasName("V")));
+ recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"),
+ hasName("V")));
EXPECT_TRUE(matches("class X {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class Y {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class Z {};", XOrYOrZOrUOrV));
@@ -331,13 +370,12 @@ TEST(DeclarationMatcher, MatchAnyOf) {
}
TEST(DeclarationMatcher, MatchHas) {
- DeclarationMatcher HasClassX = record(has(record(hasName("X"))));
-
+ DeclarationMatcher HasClassX = recordDecl(has(recordDecl(hasName("X"))));
EXPECT_TRUE(matches("class Y { class X {}; };", HasClassX));
EXPECT_TRUE(matches("class X {};", HasClassX));
DeclarationMatcher YHasClassX =
- record(hasName("Y"), has(record(hasName("X"))));
+ recordDecl(hasName("Y"), has(recordDecl(hasName("X"))));
EXPECT_TRUE(matches("class Y { class X {}; };", YHasClassX));
EXPECT_TRUE(notMatches("class X {};", YHasClassX));
EXPECT_TRUE(
@@ -346,14 +384,14 @@ TEST(DeclarationMatcher, MatchHas) {
TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
DeclarationMatcher Recursive =
- record(
- has(record(
- has(record(hasName("X"))),
- has(record(hasName("Y"))),
+ recordDecl(
+ has(recordDecl(
+ has(recordDecl(hasName("X"))),
+ has(recordDecl(hasName("Y"))),
hasName("Z"))),
- has(record(
- has(record(hasName("A"))),
- has(record(hasName("B"))),
+ has(recordDecl(
+ has(recordDecl(hasName("A"))),
+ has(recordDecl(hasName("B"))),
hasName("C"))),
hasName("F"));
@@ -404,21 +442,21 @@ TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
DeclarationMatcher Recursive =
- record(
+ recordDecl(
anyOf(
- has(record(
+ has(recordDecl(
anyOf(
- has(record(
+ has(recordDecl(
hasName("X"))),
- has(record(
+ has(recordDecl(
hasName("Y"))),
hasName("Z")))),
- has(record(
+ has(recordDecl(
anyOf(
hasName("C"),
- has(record(
+ has(recordDecl(
hasName("A"))),
- has(record(
+ has(recordDecl(
hasName("B")))))),
hasName("F")));
@@ -435,9 +473,8 @@ TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
TEST(DeclarationMatcher, MatchNot) {
DeclarationMatcher NotClassX =
- record(
+ recordDecl(
isDerivedFrom("Y"),
- unless(hasName("Y")),
unless(hasName("X")));
EXPECT_TRUE(notMatches("", NotClassX));
EXPECT_TRUE(notMatches("class Y {};", NotClassX));
@@ -448,11 +485,11 @@ TEST(DeclarationMatcher, MatchNot) {
NotClassX));
DeclarationMatcher ClassXHasNotClassY =
- record(
+ recordDecl(
hasName("X"),
- has(record(hasName("Z"))),
+ has(recordDecl(hasName("Z"))),
unless(
- has(record(hasName("Y")))));
+ has(recordDecl(hasName("Y")))));
EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
ClassXHasNotClassY));
@@ -460,8 +497,8 @@ TEST(DeclarationMatcher, MatchNot) {
TEST(DeclarationMatcher, HasDescendant) {
DeclarationMatcher ZDescendantClassX =
- record(
- hasDescendant(record(hasName("X"))),
+ recordDecl(
+ hasDescendant(recordDecl(hasName("X"))),
hasName("Z"));
EXPECT_TRUE(matches("class Z { class X {}; };", ZDescendantClassX));
EXPECT_TRUE(
@@ -475,8 +512,8 @@ TEST(DeclarationMatcher, HasDescendant) {
EXPECT_TRUE(notMatches("class Z {};", ZDescendantClassX));
DeclarationMatcher ZDescendantClassXHasClassY =
- record(
- hasDescendant(record(has(record(hasName("Y"))),
+ recordDecl(
+ hasDescendant(recordDecl(has(recordDecl(hasName("Y"))),
hasName("X"))),
hasName("Z"));
EXPECT_TRUE(matches("class Z { class X { class Y {}; }; };",
@@ -498,9 +535,9 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXHasClassY));
DeclarationMatcher ZDescendantClassXDescendantClassY =
- record(
- hasDescendant(record(hasDescendant(record(hasName("Y"))),
- hasName("X"))),
+ recordDecl(
+ hasDescendant(recordDecl(hasDescendant(recordDecl(hasName("Y"))),
+ hasName("X"))),
hasName("Z"));
EXPECT_TRUE(
matches("class Z { class A { class X { class B { class Y {}; }; }; }; };",
@@ -518,6 +555,118 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXDescendantClassY));
}
+// Implements a run method that returns whether BoundNodes contains a
+// Decl bound to Id that can be dynamically cast to T.
+// Optionally checks that the check succeeded a specific number of times.
+template <typename T>
+class VerifyIdIsBoundTo : public BoundNodesCallback {
+public:
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Does not check for a certain number of matches.
+ explicit VerifyIdIsBoundTo(llvm::StringRef Id)
+ : Id(Id), ExpectedCount(-1), Count(0) {}
+
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Checks that there were exactly \c ExpectedCount matches.
+ VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
+ : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
+
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Checks that there was exactly one match with the name \c ExpectedName.
+ // Note that \c T must be a NamedDecl for this to work.
+ VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
+ : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
+
+ ~VerifyIdIsBoundTo() {
+ if (ExpectedCount != -1)
+ EXPECT_EQ(ExpectedCount, Count);
+ if (!ExpectedName.empty())
+ EXPECT_EQ(ExpectedName, Name);
+ }
+
+ virtual bool run(const BoundNodes *Nodes) {
+ if (Nodes->getNodeAs<T>(Id)) {
+ ++Count;
+ if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
+ Name = Named->getNameAsString();
+ } else if (const NestedNameSpecifier *NNS =
+ Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
+ llvm::raw_string_ostream OS(Name);
+ NNS->print(OS, PrintingPolicy(LangOptions()));
+ }
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ return run(Nodes);
+ }
+
+private:
+ const std::string Id;
+ const int ExpectedCount;
+ int Count;
+ const std::string ExpectedName;
+ std::string Name;
+};
+
+TEST(HasDescendant, MatchesDescendantTypes) {
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ decl(hasDescendant(loc(builtinType())))));
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(builtinType()))));
+
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(loc(builtinType())))));
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(qualType(builtinType())))));
+
+ EXPECT_TRUE(notMatches("void f() { float f = 2.0f; }",
+ stmt(hasDescendant(isInteger()))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { int a; float c; int d; int e; }",
+ functionDecl(forEachDescendant(
+ varDecl(hasDescendant(isInteger())).bind("x"))),
+ new VerifyIdIsBoundTo<Decl>("x", 3)));
+}
+
+TEST(HasDescendant, MatchesDescendantsOfTypes) {
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ qualType(hasDescendant(builtinType()))));
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ qualType(hasDescendant(
+ pointerType(pointee(builtinType()))))));
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ typeLoc(hasDescendant(builtinTypeLoc()))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { int*** i; }",
+ qualType(asString("int ***"), forEachDescendant(pointerType().bind("x"))),
+ new VerifyIdIsBoundTo<Type>("x", 2)));
+}
+
+TEST(Has, MatchesChildrenOfTypes) {
+ EXPECT_TRUE(matches("int i;",
+ varDecl(hasName("i"), has(isInteger()))));
+ EXPECT_TRUE(notMatches("int** i;",
+ varDecl(hasName("i"), has(isInteger()))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "int (*f)(float, int);",
+ qualType(functionType(), forEach(qualType(isInteger()).bind("x"))),
+ new VerifyIdIsBoundTo<QualType>("x", 2)));
+}
+
+TEST(Has, MatchesChildTypes) {
+ EXPECT_TRUE(matches(
+ "int* i;",
+ varDecl(hasName("i"), hasType(qualType(has(builtinType()))))));
+ EXPECT_TRUE(notMatches(
+ "int* i;",
+ varDecl(hasName("i"), hasType(qualType(has(pointerType()))))));
+}
+
TEST(Enum, DoesNotMatchClasses) {
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
}
@@ -527,7 +676,7 @@ TEST(Enum, MatchesEnums) {
}
TEST(EnumConstant, Matches) {
- DeclarationMatcher Matcher = enumConstant(hasName("A"));
+ DeclarationMatcher Matcher = enumConstantDecl(hasName("A"));
EXPECT_TRUE(matches("enum X{ A };", Matcher));
EXPECT_TRUE(notMatches("enum X{ B };", Matcher));
EXPECT_TRUE(notMatches("enum X {};", Matcher));
@@ -535,9 +684,8 @@ TEST(EnumConstant, Matches) {
TEST(StatementMatcher, Has) {
StatementMatcher HasVariableI =
- expression(
- hasType(pointsTo(record(hasName("X")))),
- has(declarationReference(to(variable(hasName("i"))))));
+ expr(hasType(pointsTo(recordDecl(hasName("X")))),
+ has(declRefExpr(to(varDecl(hasName("i"))))));
EXPECT_TRUE(matches(
"class X; X *x(int); void c() { int i; x(i); }", HasVariableI));
@@ -547,9 +695,8 @@ TEST(StatementMatcher, Has) {
TEST(StatementMatcher, HasDescendant) {
StatementMatcher HasDescendantVariableI =
- expression(
- hasType(pointsTo(record(hasName("X")))),
- hasDescendant(declarationReference(to(variable(hasName("i"))))));
+ expr(hasType(pointsTo(recordDecl(hasName("X")))),
+ hasDescendant(declRefExpr(to(varDecl(hasName("i"))))));
EXPECT_TRUE(matches(
"class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }",
@@ -560,160 +707,127 @@ TEST(StatementMatcher, HasDescendant) {
}
TEST(TypeMatcher, MatchesClassType) {
- TypeMatcher TypeA = hasDeclaration(record(hasName("A")));
+ TypeMatcher TypeA = hasDeclaration(recordDecl(hasName("A")));
EXPECT_TRUE(matches("class A { public: A *a; };", TypeA));
EXPECT_TRUE(notMatches("class A {};", TypeA));
- TypeMatcher TypeDerivedFromA = hasDeclaration(record(isDerivedFrom("A")));
+ TypeMatcher TypeDerivedFromA = hasDeclaration(recordDecl(isDerivedFrom("A")));
EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };",
TypeDerivedFromA));
EXPECT_TRUE(notMatches("class A {};", TypeA));
TypeMatcher TypeAHasClassB = hasDeclaration(
- record(hasName("A"), has(record(hasName("B")))));
+ recordDecl(hasName("A"), has(recordDecl(hasName("B")))));
EXPECT_TRUE(
matches("class A { public: A *a; class B {}; };", TypeAHasClassB));
}
-// Returns from Run whether 'bound_nodes' contain a Decl bound to 'Id', which
-// can be dynamically casted to T.
-// Optionally checks that the check succeeded a specific number of times.
-template <typename T>
-class VerifyIdIsBoundToDecl : public BoundNodesCallback {
-public:
- // Create an object that checks that a node of type 'T' was bound to 'Id'.
- // Does not check for a certain number of matches.
- explicit VerifyIdIsBoundToDecl(const std::string& Id)
- : Id(Id), ExpectedCount(-1), Count(0) {}
-
- // Create an object that checks that a node of type 'T' was bound to 'Id'.
- // Checks that there were exactly 'ExpectedCount' matches.
- explicit VerifyIdIsBoundToDecl(const std::string& Id, int ExpectedCount)
- : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
-
- ~VerifyIdIsBoundToDecl() {
- if (ExpectedCount != -1) {
- EXPECT_EQ(ExpectedCount, Count);
- }
- }
-
- virtual bool run(const BoundNodes *Nodes) {
- if (Nodes->getDeclAs<T>(Id) != NULL) {
- ++Count;
- return true;
- }
- return false;
- }
-
-private:
- const std::string Id;
- const int ExpectedCount;
- int Count;
-};
-template <typename T>
-class VerifyIdIsBoundToStmt : public BoundNodesCallback {
-public:
- explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {}
- virtual bool run(const BoundNodes *Nodes) {
- const T *Node = Nodes->getStmtAs<T>(Id);
- return Node != NULL;
- }
-private:
- const std::string Id;
-};
-
TEST(Matcher, BindMatchedNodes) {
- DeclarationMatcher ClassX = has(record(hasName("::X")).bind("x"));
+ DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x"));
EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
- ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x")));
+ ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("x")));
EXPECT_TRUE(matchAndVerifyResultFalse("class X {};",
- ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id")));
+ ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("other-id")));
TypeMatcher TypeAHasClassB = hasDeclaration(
- record(hasName("A"), has(record(hasName("B")).bind("b"))));
+ recordDecl(hasName("A"), has(recordDecl(hasName("B")).bind("b"))));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
TypeAHasClassB,
- new VerifyIdIsBoundToDecl<Decl>("b")));
+ new VerifyIdIsBoundTo<Decl>("b")));
- StatementMatcher MethodX = call(callee(method(hasName("x")))).bind("x");
+ StatementMatcher MethodX =
+ callExpr(callee(methodDecl(hasName("x")))).bind("x");
EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
MethodX,
- new VerifyIdIsBoundToStmt<CXXMemberCallExpr>("x")));
+ new VerifyIdIsBoundTo<CXXMemberCallExpr>("x")));
}
TEST(Matcher, BindTheSameNameInAlternatives) {
StatementMatcher matcher = anyOf(
binaryOperator(hasOperatorName("+"),
- hasLHS(expression().bind("x")),
+ hasLHS(expr().bind("x")),
hasRHS(integerLiteral(equals(0)))),
binaryOperator(hasOperatorName("+"),
hasLHS(integerLiteral(equals(0))),
- hasRHS(expression().bind("x"))));
+ hasRHS(expr().bind("x"))));
EXPECT_TRUE(matchAndVerifyResultTrue(
// The first branch of the matcher binds x to 0 but then fails.
// The second branch binds x to f() and succeeds.
"int f() { return 0 + f(); }",
matcher,
- new VerifyIdIsBoundToStmt<CallExpr>("x")));
+ new VerifyIdIsBoundTo<CallExpr>("x")));
+}
+
+TEST(Matcher, BindsIDForMemoizedResults) {
+ // Using the same matcher in two match expressions will make memoization
+ // kick in.
+ DeclarationMatcher ClassX = recordDecl(hasName("X")).bind("x");
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B { class X {}; }; };",
+ DeclarationMatcher(anyOf(
+ recordDecl(hasName("A"), hasDescendant(ClassX)),
+ recordDecl(hasName("B"), hasDescendant(ClassX)))),
+ new VerifyIdIsBoundTo<Decl>("x", 2)));
}
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
- TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
- matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX))));
EXPECT_TRUE(
notMatches("class X {}; void y(X *x) { x; }",
- expression(hasType(ClassX))));
+ expr(hasType(ClassX))));
EXPECT_TRUE(
matches("class X {}; void y(X *x) { x; }",
- expression(hasType(pointsTo(ClassX)))));
+ expr(hasType(pointsTo(ClassX)))));
}
TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) {
- TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
- matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
- notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+ notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
matches("class X {}; void y() { X *x; }",
- variable(hasType(pointsTo(ClassX)))));
+ varDecl(hasType(pointsTo(ClassX)))));
}
TEST(HasType, TakesDeclMatcherAndMatchesExpr) {
- DeclarationMatcher ClassX = record(hasName("X"));
+ DeclarationMatcher ClassX = recordDecl(hasName("X"));
EXPECT_TRUE(
- matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX))));
EXPECT_TRUE(
notMatches("class X {}; void y(X *x) { x; }",
- expression(hasType(ClassX))));
+ expr(hasType(ClassX))));
}
TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
- DeclarationMatcher ClassX = record(hasName("X"));
+ DeclarationMatcher ClassX = recordDecl(hasName("X"));
EXPECT_TRUE(
- matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
- notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+ notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX))));
}
TEST(Matcher, Call) {
// FIXME: Do we want to overload Call() to directly take
// Matcher<Decl>, too?
- StatementMatcher MethodX = call(hasDeclaration(method(hasName("x"))));
+ StatementMatcher MethodX = callExpr(hasDeclaration(methodDecl(hasName("x"))));
EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX));
- StatementMatcher MethodOnY = memberCall(on(hasType(record(hasName("Y")))));
+ StatementMatcher MethodOnY =
+ memberCallExpr(on(hasType(recordDecl(hasName("Y")))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -732,7 +846,7 @@ TEST(Matcher, Call) {
MethodOnY));
StatementMatcher MethodOnYPointer =
- memberCall(on(hasType(pointsTo(record(hasName("Y"))))));
+ memberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y"))))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
@@ -751,20 +865,50 @@ TEST(Matcher, Call) {
MethodOnYPointer));
}
+TEST(Matcher, Lambda) {
+ EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };",
+ lambdaExpr()));
+}
+
+TEST(Matcher, ForRange) {
+ EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };"
+ "void f() { for (auto &a : as); }",
+ forRangeStmt()));
+ EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }",
+ forRangeStmt()));
+}
+
+TEST(Matcher, UserDefinedLiteral) {
+ EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {"
+ " return i + 1;"
+ "}"
+ "char c = 'a'_inc;",
+ userDefinedLiteral()));
+}
+
+TEST(Matcher, FlowControl) {
+ EXPECT_TRUE(matches("void f() { while(true) { break; } }", breakStmt()));
+ EXPECT_TRUE(matches("void f() { while(true) { continue; } }",
+ continueStmt()));
+ EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt()));
+ EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", labelStmt()));
+ EXPECT_TRUE(matches("void f() { return; }", returnStmt()));
+}
+
TEST(HasType, MatchesAsString) {
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }",
- memberCall(on(hasType(asString("class Y *"))))));
+ memberCallExpr(on(hasType(asString("class Y *"))))));
EXPECT_TRUE(matches("class X { void x(int x) {} };",
- method(hasParameter(0, hasType(asString("int"))))));
+ methodDecl(hasParameter(0, hasType(asString("int"))))));
EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };",
- field(hasType(asString("ns::A")))));
+ fieldDecl(hasType(asString("ns::A")))));
EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };",
- field(hasType(asString("struct <anonymous>::A")))));
+ fieldDecl(hasType(asString("struct <anonymous>::A")))));
}
TEST(Matcher, OverloadedOperatorCall) {
- StatementMatcher OpCall = overloadedOperatorCall();
+ StatementMatcher OpCall = operatorCallExpr();
// Unary operator
EXPECT_TRUE(matches("class Y { }; "
"bool operator!(Y x) { return false; }; "
@@ -791,12 +935,12 @@ TEST(Matcher, OverloadedOperatorCall) {
TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
StatementMatcher OpCallAndAnd =
- overloadedOperatorCall(hasOverloadedOperatorName("&&"));
+ operatorCallExpr(hasOverloadedOperatorName("&&"));
EXPECT_TRUE(matches("class Y { }; "
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;", OpCallAndAnd));
StatementMatcher OpCallLessLess =
- overloadedOperatorCall(hasOverloadedOperatorName("<<"));
+ operatorCallExpr(hasOverloadedOperatorName("<<"));
EXPECT_TRUE(notMatches("class Y { }; "
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;",
@@ -805,7 +949,7 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
TEST(Matcher, ThisPointerType) {
StatementMatcher MethodOnY =
- memberCall(thisPointerType(record(hasName("Y"))));
+ memberCallExpr(thisPointerType(recordDecl(hasName("Y"))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -835,9 +979,9 @@ TEST(Matcher, ThisPointerType) {
TEST(Matcher, VariableUsage) {
StatementMatcher Reference =
- declarationReference(to(
- variable(hasInitializer(
- memberCall(thisPointerType(record(hasName("Y"))))))));
+ declRefExpr(to(
+ varDecl(hasInitializer(
+ memberCallExpr(thisPointerType(recordDecl(hasName("Y"))))))));
EXPECT_TRUE(matches(
"class Y {"
@@ -862,12 +1006,12 @@ TEST(Matcher, VariableUsage) {
TEST(Matcher, FindsVarDeclInFuncitonParameter) {
EXPECT_TRUE(matches(
"void f(int i) {}",
- variable(hasName("i"))));
+ varDecl(hasName("i"))));
}
TEST(Matcher, CalledVariable) {
- StatementMatcher CallOnVariableY = expression(
- memberCall(on(declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallOnVariableY =
+ memberCallExpr(on(declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches(
"class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY));
@@ -904,81 +1048,81 @@ TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) {
hasArgumentOfType(asString("float")))));
EXPECT_TRUE(matches(
"struct A {}; void x() { A a; int b = sizeof(a); }",
- sizeOfExpr(hasArgumentOfType(hasDeclaration(record(hasName("A")))))));
+ sizeOfExpr(hasArgumentOfType(hasDeclaration(recordDecl(hasName("A")))))));
EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr(
- hasArgumentOfType(hasDeclaration(record(hasName("string")))))));
+ hasArgumentOfType(hasDeclaration(recordDecl(hasName("string")))))));
}
TEST(MemberExpression, DoesNotMatchClasses) {
- EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression()));
+ EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr()));
}
TEST(MemberExpression, MatchesMemberFunctionCall) {
- EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpression()));
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr()));
}
TEST(MemberExpression, MatchesVariable) {
EXPECT_TRUE(
- matches("class Y { void x() { this->y; } int y; };", memberExpression()));
+ matches("class Y { void x() { this->y; } int y; };", memberExpr()));
EXPECT_TRUE(
- matches("class Y { void x() { y; } int y; };", memberExpression()));
+ matches("class Y { void x() { y; } int y; };", memberExpr()));
EXPECT_TRUE(
- matches("class Y { void x() { Y y; y.y; } int y; };",
- memberExpression()));
+ matches("class Y { void x() { Y y; y.y; } int y; };", memberExpr()));
}
TEST(MemberExpression, MatchesStaticVariable) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
- memberExpression()));
+ memberExpr()));
EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
- memberExpression()));
+ memberExpr()));
EXPECT_TRUE(notMatches("class Y { void x() { Y::y; } static int y; };",
- memberExpression()));
+ memberExpr()));
}
TEST(IsInteger, MatchesIntegers) {
- EXPECT_TRUE(matches("int i = 0;", variable(hasType(isInteger()))));
- EXPECT_TRUE(matches("long long i = 0; void f(long long) { }; void g() {f(i);}",
- call(hasArgument(0, declarationReference(
- to(variable(hasType(isInteger()))))))));
+ EXPECT_TRUE(matches("int i = 0;", varDecl(hasType(isInteger()))));
+ EXPECT_TRUE(matches(
+ "long long i = 0; void f(long long) { }; void g() {f(i);}",
+ callExpr(hasArgument(0, declRefExpr(
+ to(varDecl(hasType(isInteger()))))))));
}
TEST(IsInteger, ReportsNoFalsePositives) {
- EXPECT_TRUE(notMatches("int *i;", variable(hasType(isInteger()))));
+ EXPECT_TRUE(notMatches("int *i;", varDecl(hasType(isInteger()))));
EXPECT_TRUE(notMatches("struct T {}; T t; void f(T *) { }; void g() {f(&t);}",
- call(hasArgument(0, declarationReference(
- to(variable(hasType(isInteger()))))))));
+ callExpr(hasArgument(0, declRefExpr(
+ to(varDecl(hasType(isInteger()))))))));
}
TEST(IsArrow, MatchesMemberVariablesViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(matches("class Y { void x() { y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(IsArrow, MatchesMemberCallsViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(matches("class Y { void x() { x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(Callee, MatchesDeclarations) {
- StatementMatcher CallMethodX = call(callee(method(hasName("x"))));
+ StatementMatcher CallMethodX = callExpr(callee(methodDecl(hasName("x"))));
EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX));
EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX));
@@ -986,13 +1130,13 @@ TEST(Callee, MatchesDeclarations) {
TEST(Callee, MatchesMemberExpressions) {
EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
- call(callee(memberExpression()))));
+ callExpr(callee(memberExpr()))));
EXPECT_TRUE(
- notMatches("class Y { void x() { this->x(); } };", call(callee(call()))));
+ notMatches("class Y { void x() { this->x(); } };", callExpr(callee(callExpr()))));
}
TEST(Function, MatchesFunctionDeclarations) {
- StatementMatcher CallFunctionF = call(callee(function(hasName("f"))));
+ StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
@@ -1017,30 +1161,51 @@ TEST(Function, MatchesFunctionDeclarations) {
CallFunctionF));
}
+TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) {
+ EXPECT_TRUE(
+ matches("template <typename T> void f(T t) {}",
+ functionTemplateDecl(hasName("f"))));
+}
+
+TEST(FunctionTemplate, DoesNotMatchFunctionDeclarations) {
+ EXPECT_TRUE(
+ notMatches("void f(double d); void f(int t) {}",
+ functionTemplateDecl(hasName("f"))));
+}
+
+TEST(FunctionTemplate, DoesNotMatchFunctionTemplateSpecializations) {
+ EXPECT_TRUE(
+ notMatches("void g(); template <typename T> void f(T t) {}"
+ "template <> void f(int t) { g(); }",
+ functionTemplateDecl(hasName("f"),
+ hasDescendant(declRefExpr(to(
+ functionDecl(hasName("g"))))))));
+}
+
TEST(Matcher, Argument) {
- StatementMatcher CallArgumentY = expression(call(
- hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallArgumentY = callExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches("void x(int) { int y; x(y); }", CallArgumentY));
EXPECT_TRUE(
matches("class X { void x(int) { int y; x(y); } };", CallArgumentY));
EXPECT_TRUE(notMatches("void x(int) { int z; x(z); }", CallArgumentY));
- StatementMatcher WrongIndex = expression(call(
- hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = callExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex));
}
TEST(Matcher, AnyArgument) {
- StatementMatcher CallArgumentY = expression(call(
- hasAnyArgument(declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallArgumentY = callExpr(
+ hasAnyArgument(declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }", CallArgumentY));
EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY));
EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
}
TEST(Matcher, ArgumentCount) {
- StatementMatcher Call1Arg = expression(call(argumentCountIs(1)));
+ StatementMatcher Call1Arg = callExpr(argumentCountIs(1));
EXPECT_TRUE(matches("void x(int) { x(0); }", Call1Arg));
EXPECT_TRUE(matches("class X { void x(int) { x(0); } };", Call1Arg));
@@ -1048,8 +1213,8 @@ TEST(Matcher, ArgumentCount) {
}
TEST(Matcher, References) {
- DeclarationMatcher ReferenceClassX = variable(
- hasType(references(record(hasName("X")))));
+ DeclarationMatcher ReferenceClassX = varDecl(
+ hasType(references(recordDecl(hasName("X")))));
EXPECT_TRUE(matches("class X {}; void y(X y) { X &x = y; }",
ReferenceClassX));
EXPECT_TRUE(
@@ -1062,81 +1227,86 @@ TEST(Matcher, References) {
TEST(HasParameter, CallsInnerMatcher) {
EXPECT_TRUE(matches("class X { void x(int) {} };",
- method(hasParameter(0, variable()))));
+ methodDecl(hasParameter(0, varDecl()))));
EXPECT_TRUE(notMatches("class X { void x(int) {} };",
- method(hasParameter(0, hasName("x")))));
+ methodDecl(hasParameter(0, hasName("x")))));
}
TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) {
EXPECT_TRUE(notMatches("class X { void x(int) {} };",
- method(hasParameter(42, variable()))));
+ methodDecl(hasParameter(42, varDecl()))));
}
TEST(HasType, MatchesParameterVariableTypesStrictly) {
EXPECT_TRUE(matches("class X { void x(X x) {} };",
- method(hasParameter(0, hasType(record(hasName("X")))))));
+ methodDecl(hasParameter(0, hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };",
- method(hasParameter(0, hasType(record(hasName("X")))))));
+ methodDecl(hasParameter(0, hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches("class X { void x(const X *x) {} };",
- method(hasParameter(0, hasType(pointsTo(record(hasName("X"))))))));
+ methodDecl(hasParameter(0,
+ hasType(pointsTo(recordDecl(hasName("X"))))))));
EXPECT_TRUE(matches("class X { void x(const X &x) {} };",
- method(hasParameter(0, hasType(references(record(hasName("X"))))))));
+ methodDecl(hasParameter(0,
+ hasType(references(recordDecl(hasName("X"))))))));
}
TEST(HasAnyParameter, MatchesIndependentlyOfPosition) {
EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
}
TEST(Returns, MatchesReturnTypes) {
EXPECT_TRUE(matches("class Y { int f() { return 1; } };",
- function(returns(asString("int")))));
+ functionDecl(returns(asString("int")))));
EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };",
- function(returns(asString("float")))));
+ functionDecl(returns(asString("float")))));
EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };",
- function(returns(hasDeclaration(record(hasName("Y")))))));
+ functionDecl(returns(hasDeclaration(
+ recordDecl(hasName("Y")))))));
}
TEST(IsExternC, MatchesExternCFunctionDeclarations) {
- EXPECT_TRUE(matches("extern \"C\" void f() {}", function(isExternC())));
- EXPECT_TRUE(matches("extern \"C\" { void f() {} }", function(isExternC())));
- EXPECT_TRUE(notMatches("void f() {}", function(isExternC())));
+ EXPECT_TRUE(matches("extern \"C\" void f() {}", functionDecl(isExternC())));
+ EXPECT_TRUE(matches("extern \"C\" { void f() {} }",
+ functionDecl(isExternC())));
+ EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
}
TEST(HasAnyParameter, DoesNotMatchThisPointer) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };",
- method(hasAnyParameter(hasType(pointsTo(record(hasName("X"))))))));
+ methodDecl(hasAnyParameter(hasType(pointsTo(
+ recordDecl(hasName("X"))))))));
}
TEST(HasName, MatchesParameterVariableDeclartions) {
EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };",
- method(hasAnyParameter(hasName("x")))));
+ methodDecl(hasAnyParameter(hasName("x")))));
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
- method(hasAnyParameter(hasName("x")))));
+ methodDecl(hasAnyParameter(hasName("x")))));
}
TEST(Matcher, MatchesClassTemplateSpecialization) {
EXPECT_TRUE(matches("template<typename T> struct A {};"
"template<> struct A<int> {};",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
EXPECT_TRUE(matches("template<typename T> struct A {}; A<int> a;",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
EXPECT_TRUE(notMatches("template<typename T> struct A {};",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
}
TEST(Matcher, MatchesTypeTemplateArgument) {
EXPECT_TRUE(matches(
"template<typename T> struct B {};"
"B<int> b;",
- classTemplateSpecialization(hasAnyTemplateArgument(refersToType(
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
asString("int"))))));
}
@@ -1145,25 +1315,31 @@ TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) {
"struct B { int next; };"
"template<int(B::*next_ptr)> struct A {};"
"A<&B::next> a;",
- classTemplateSpecialization(hasAnyTemplateArgument(
- refersToDeclaration(field(hasName("next")))))));
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(fieldDecl(hasName("next")))))));
+
+ EXPECT_TRUE(notMatches(
+ "template <typename T> struct A {};"
+ "A<int> a;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(decl())))));
}
TEST(Matcher, MatchesSpecificArgument) {
EXPECT_TRUE(matches(
"template<typename T, typename U> class A {};"
"A<bool, int> a;",
- classTemplateSpecialization(hasTemplateArgument(
+ classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
EXPECT_TRUE(notMatches(
"template<typename T, typename U> class A {};"
"A<int, bool> a;",
- classTemplateSpecialization(hasTemplateArgument(
+ classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
}
TEST(Matcher, ConstructorCall) {
- StatementMatcher Constructor = expression(constructorCall());
+ StatementMatcher Constructor = constructExpr();
EXPECT_TRUE(
matches("class X { public: X(); }; void x() { X x; }", Constructor));
@@ -1177,8 +1353,8 @@ TEST(Matcher, ConstructorCall) {
}
TEST(Matcher, ConstructorArgument) {
- StatementMatcher Constructor = expression(constructorCall(
- hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher Constructor = constructExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { int y; X x(y); }",
@@ -1193,16 +1369,15 @@ TEST(Matcher, ConstructorArgument) {
notMatches("class X { public: X(int); }; void x() { int z; X x(z); }",
Constructor));
- StatementMatcher WrongIndex = expression(constructorCall(
- hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = constructExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
notMatches("class X { public: X(int); }; void x() { int y; X x(y); }",
WrongIndex));
}
TEST(Matcher, ConstructorArgumentCount) {
- StatementMatcher Constructor1Arg =
- expression(constructorCall(argumentCountIs(1)));
+ StatementMatcher Constructor1Arg = constructExpr(argumentCountIs(1));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { X x(0); }",
@@ -1218,8 +1393,15 @@ TEST(Matcher, ConstructorArgumentCount) {
Constructor1Arg));
}
+TEST(Matcher,ThisExpr) {
+ EXPECT_TRUE(
+ matches("struct X { int a; int f () { return a; } };", thisExpr()));
+ EXPECT_TRUE(
+ notMatches("struct X { int f () { int a; return a; } };", thisExpr()));
+}
+
TEST(Matcher, BindTemporaryExpression) {
- StatementMatcher TempExpression = expression(bindTemporaryExpression());
+ StatementMatcher TempExpression = bindTemporaryExpr();
std::string ClassString = "class string { public: string(); ~string(); }; ";
@@ -1249,44 +1431,80 @@ TEST(Matcher, BindTemporaryExpression) {
TempExpression));
}
+TEST(MaterializeTemporaryExpr, MatchesTemporary) {
+ std::string ClassString =
+ "class string { public: string(); int length(); }; ";
+
+ EXPECT_TRUE(
+ matches(ClassString +
+ "string GetStringByValue();"
+ "void FunctionTakesString(string s);"
+ "void run() { FunctionTakesString(GetStringByValue()); }",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string* GetStringPointer(); "
+ "void FunctionTakesStringPtr(string* s);"
+ "void run() {"
+ " string* s = GetStringPointer();"
+ " FunctionTakesStringPtr(GetStringPointer());"
+ " FunctionTakesStringPtr(s);"
+ "}",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string GetStringByValue();"
+ "void run() { int k = GetStringByValue().length(); }",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string GetStringByValue();"
+ "void run() { GetStringByValue(); }",
+ materializeTemporaryExpr()));
+}
+
TEST(ConstructorDeclaration, SimpleCase) {
EXPECT_TRUE(matches("class Foo { Foo(int i); };",
- constructor(ofClass(hasName("Foo")))));
+ constructorDecl(ofClass(hasName("Foo")))));
EXPECT_TRUE(notMatches("class Foo { Foo(int i); };",
- constructor(ofClass(hasName("Bar")))));
+ constructorDecl(ofClass(hasName("Bar")))));
}
TEST(ConstructorDeclaration, IsImplicit) {
// This one doesn't match because the constructor is not added by the
// compiler (it is not needed).
EXPECT_TRUE(notMatches("class Foo { };",
- constructor(isImplicit())));
+ constructorDecl(isImplicit())));
// The compiler added the implicit default constructor.
EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();",
- constructor(isImplicit())));
+ constructorDecl(isImplicit())));
EXPECT_TRUE(matches("class Foo { Foo(){} };",
- constructor(unless(isImplicit()))));
+ constructorDecl(unless(isImplicit()))));
}
TEST(DestructorDeclaration, MatchesVirtualDestructor) {
EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };",
- destructor(ofClass(hasName("Foo")))));
+ destructorDecl(ofClass(hasName("Foo")))));
}
TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) {
- EXPECT_TRUE(notMatches("class Foo {};", destructor(ofClass(hasName("Foo")))));
+ EXPECT_TRUE(notMatches("class Foo {};",
+ destructorDecl(ofClass(hasName("Foo")))));
}
TEST(HasAnyConstructorInitializer, SimpleCase) {
EXPECT_TRUE(notMatches(
"class Foo { Foo() { } };",
- constructor(hasAnyConstructorInitializer(anything()))));
+ constructorDecl(hasAnyConstructorInitializer(anything()))));
EXPECT_TRUE(matches(
"class Foo {"
" Foo() : foo_() { }"
" int foo_;"
"};",
- constructor(hasAnyConstructorInitializer(anything()))));
+ constructorDecl(hasAnyConstructorInitializer(anything()))));
}
TEST(HasAnyConstructorInitializer, ForField) {
@@ -1297,12 +1515,12 @@ TEST(HasAnyConstructorInitializer, ForField) {
" Baz foo_;"
" Baz bar_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
- forField(hasType(record(hasName("Baz"))))))));
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
+ forField(hasType(recordDecl(hasName("Baz"))))))));
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
forField(hasName("foo_"))))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
- forField(hasType(record(hasName("Bar"))))))));
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
+ forField(hasType(recordDecl(hasName("Bar"))))))));
}
TEST(HasAnyConstructorInitializer, WithInitializer) {
@@ -1311,9 +1529,9 @@ TEST(HasAnyConstructorInitializer, WithInitializer) {
" Foo() : foo_(0) { }"
" int foo_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
withInitializer(integerLiteral(equals(0)))))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
withInitializer(integerLiteral(equals(1)))))));
}
@@ -1325,16 +1543,16 @@ TEST(HasAnyConstructorInitializer, IsWritten) {
" Bar foo_;"
" Bar bar_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("foo_")), isWritten())))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("bar_")), isWritten())))));
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("bar_")), unless(isWritten()))))));
}
TEST(Matcher, NewExpression) {
- StatementMatcher New = expression(newExpression());
+ StatementMatcher New = newExpr();
EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New));
EXPECT_TRUE(
@@ -1345,9 +1563,8 @@ TEST(Matcher, NewExpression) {
}
TEST(Matcher, NewExpressionArgument) {
- StatementMatcher New = expression(constructorCall(
- hasArgument(
- 0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher New = constructExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { int y; new X(y); }",
@@ -1359,16 +1576,15 @@ TEST(Matcher, NewExpressionArgument) {
notMatches("class X { public: X(int); }; void x() { int z; new X(z); }",
New));
- StatementMatcher WrongIndex = expression(constructorCall(
- hasArgument(
- 42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = constructExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
notMatches("class X { public: X(int); }; void x() { int y; new X(y); }",
WrongIndex));
}
TEST(Matcher, NewExpressionArgumentCount) {
- StatementMatcher New = constructorCall(argumentCountIs(1));
+ StatementMatcher New = constructExpr(argumentCountIs(1));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { new X(0); }", New));
@@ -1379,11 +1595,11 @@ TEST(Matcher, NewExpressionArgumentCount) {
TEST(Matcher, DeleteExpression) {
EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }",
- deleteExpression()));
+ deleteExpr()));
}
TEST(Matcher, DefaultArgument) {
- StatementMatcher Arg = defaultArgument();
+ StatementMatcher Arg = defaultArgExpr();
EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg));
EXPECT_TRUE(
@@ -1392,7 +1608,7 @@ TEST(Matcher, DefaultArgument) {
}
TEST(Matcher, StringLiterals) {
- StatementMatcher Literal = expression(stringLiteral());
+ StatementMatcher Literal = stringLiteral();
EXPECT_TRUE(matches("const char *s = \"string\";", Literal));
// wide string
EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", Literal));
@@ -1403,7 +1619,7 @@ TEST(Matcher, StringLiterals) {
}
TEST(Matcher, CharacterLiterals) {
- StatementMatcher CharLiteral = expression(characterLiteral());
+ StatementMatcher CharLiteral = characterLiteral();
EXPECT_TRUE(matches("const char c = 'c';", CharLiteral));
// wide character
EXPECT_TRUE(matches("const char c = L'c';", CharLiteral));
@@ -1413,7 +1629,7 @@ TEST(Matcher, CharacterLiterals) {
}
TEST(Matcher, IntegerLiterals) {
- StatementMatcher HasIntLiteral = expression(integerLiteral());
+ StatementMatcher HasIntLiteral = integerLiteral();
EXPECT_TRUE(matches("int i = 10;", HasIntLiteral));
EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral));
EXPECT_TRUE(matches("int i = 10L;", HasIntLiteral));
@@ -1428,6 +1644,14 @@ TEST(Matcher, IntegerLiterals) {
EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
}
+TEST(Matcher, NullPtrLiteral) {
+ EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr()));
+}
+
+TEST(Matcher, AsmStatement) {
+ EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
+}
+
TEST(Matcher, Conditions) {
StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true))));
@@ -1654,87 +1878,91 @@ TEST(ArraySubscriptMatchers, ArrayIndex) {
TEST(ArraySubscriptMatchers, MatchesArrayBase) {
EXPECT_TRUE(matches(
"int i[2]; void f() { i[1] = 2; }",
- arraySubscriptExpr(hasBase(implicitCast(
- hasSourceExpression(declarationReference()))))));
+ arraySubscriptExpr(hasBase(implicitCastExpr(
+ hasSourceExpression(declRefExpr()))))));
}
TEST(Matcher, HasNameSupportsNamespaces) {
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("a::b::C"))));
+ recordDecl(hasName("a::b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("::a::b::C"))));
+ recordDecl(hasName("::a::b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("b::C"))));
+ recordDecl(hasName("b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("C"))));
+ recordDecl(hasName("C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("c::b::C"))));
+ recordDecl(hasName("c::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a::c::C"))));
+ recordDecl(hasName("a::c::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a::b::A"))));
+ recordDecl(hasName("a::b::A"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("::C"))));
+ recordDecl(hasName("::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("::b::C"))));
+ recordDecl(hasName("::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("z::a::b::C"))));
+ recordDecl(hasName("z::a::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a+b::C"))));
+ recordDecl(hasName("a+b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }",
- record(hasName("C"))));
+ recordDecl(hasName("C"))));
}
TEST(Matcher, HasNameSupportsOuterClasses) {
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("A::B::C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("A::B::C"))));
EXPECT_TRUE(
matches("class A { class B { class C; }; };",
- record(hasName("::A::B::C"))));
+ recordDecl(hasName("::A::B::C"))));
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("B::C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("B::C"))));
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("c::B::C"))));
+ recordDecl(hasName("c::B::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A::c::C"))));
+ recordDecl(hasName("A::c::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A::B::A"))));
+ recordDecl(hasName("A::B::A"))));
EXPECT_TRUE(
- notMatches("class A { class B { class C; }; };", record(hasName("::C"))));
+ notMatches("class A { class B { class C; }; };",
+ recordDecl(hasName("::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("::B::C"))));
+ recordDecl(hasName("::B::C"))));
EXPECT_TRUE(notMatches("class A { class B { class C; }; };",
- record(hasName("z::A::B::C"))));
+ recordDecl(hasName("z::A::B::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A+B::C"))));
+ recordDecl(hasName("A+B::C"))));
}
TEST(Matcher, IsDefinition) {
DeclarationMatcher DefinitionOfClassA =
- record(hasName("A"), isDefinition());
+ recordDecl(hasName("A"), isDefinition());
EXPECT_TRUE(matches("class A {};", DefinitionOfClassA));
EXPECT_TRUE(notMatches("class A;", DefinitionOfClassA));
DeclarationMatcher DefinitionOfVariableA =
- variable(hasName("a"), isDefinition());
+ varDecl(hasName("a"), isDefinition());
EXPECT_TRUE(matches("int a;", DefinitionOfVariableA));
EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA));
DeclarationMatcher DefinitionOfMethodA =
- method(hasName("a"), isDefinition());
+ methodDecl(hasName("a"), isDefinition());
EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA));
EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA));
}
TEST(Matcher, OfClass) {
- StatementMatcher Constructor = constructorCall(hasDeclaration(method(
+ StatementMatcher Constructor = constructExpr(hasDeclaration(methodDecl(
ofClass(hasName("X")))));
EXPECT_TRUE(
@@ -1751,7 +1979,8 @@ TEST(Matcher, VisitsTemplateInstantiations) {
EXPECT_TRUE(matches(
"class A { public: void x(); };"
"template <typename T> class B { public: void y() { T t; t.x(); } };"
- "void f() { B<A> b; b.y(); }", call(callee(method(hasName("x"))))));
+ "void f() { B<A> b; b.y(); }",
+ callExpr(callee(methodDecl(hasName("x"))))));
EXPECT_TRUE(matches(
"class A { public: void x(); };"
@@ -1761,8 +1990,9 @@ TEST(Matcher, VisitsTemplateInstantiations) {
"};"
"void f() {"
" C::B<A> b; b.y();"
- "}", record(hasName("C"),
- hasDescendant(call(callee(method(hasName("x"))))))));
+ "}",
+ recordDecl(hasName("C"),
+ hasDescendant(callExpr(callee(methodDecl(hasName("x"))))))));
}
TEST(Matcher, HandlesNullQualTypes) {
@@ -1781,7 +2011,7 @@ TEST(Matcher, HandlesNullQualTypes) {
"void g() {"
" f(0);"
"}",
- expression(hasType(TypeMatcher(
+ expr(hasType(TypeMatcher(
anyOf(
TypeMatcher(hasDeclaration(anything())),
pointsTo(AnyType),
@@ -1798,16 +2028,16 @@ AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
}
TEST(AstMatcherPMacro, Works) {
- DeclarationMatcher HasClassB = just(has(record(hasName("B")).bind("b")));
+ DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
}
AST_POLYMORPHIC_MATCHER_P(
@@ -1815,27 +2045,27 @@ AST_POLYMORPHIC_MATCHER_P(
TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
(llvm::is_same<NodeType, Stmt>::value),
assert_node_type_is_accessible);
- internal::TypedBaseMatcher<Decl> ChildMatcher(AMatcher);
return Finder->matchesChildOf(
- Node, ChildMatcher, Builder,
+ Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
ASTMatchFinder::BK_First);
}
TEST(AstPolymorphicMatcherPMacro, Works) {
- DeclarationMatcher HasClassB = polymorphicHas(record(hasName("B")).bind("b"));
+ DeclarationMatcher HasClassB =
+ polymorphicHas(recordDecl(hasName("B")).bind("b"));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
StatementMatcher StatementHasClassB =
- polymorphicHas(record(hasName("B")));
+ polymorphicHas(recordDecl(hasName("B")));
EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
}
@@ -1843,6 +2073,9 @@ TEST(AstPolymorphicMatcherPMacro, Works) {
TEST(For, FindsForLoops) {
EXPECT_TRUE(matches("void f() { for(;;); }", forStmt()));
EXPECT_TRUE(matches("void f() { if(true) for(;;); }", forStmt()));
+ EXPECT_TRUE(notMatches("int as[] = { 1, 2, 3 };"
+ "void f() { for (auto &a : as); }",
+ forStmt()));
}
TEST(For, ForLoopInternals) {
@@ -1854,7 +2087,7 @@ TEST(For, ForLoopInternals) {
TEST(For, NegativeForLoopInternals) {
EXPECT_TRUE(notMatches("void f(){ for (int i = 0; ; ++i); }",
- forStmt(hasCondition(expression()))));
+ forStmt(hasCondition(expr()))));
EXPECT_TRUE(notMatches("void f() {int i; for (; i < 4; ++i) {} }",
forStmt(hasLoopInit(anything()))));
}
@@ -1865,29 +2098,29 @@ TEST(For, ReportsNoFalsePositives) {
}
TEST(CompoundStatement, HandlesSimpleCases) {
- EXPECT_TRUE(notMatches("void f();", compoundStatement()));
- EXPECT_TRUE(matches("void f() {}", compoundStatement()));
- EXPECT_TRUE(matches("void f() {{}}", compoundStatement()));
+ EXPECT_TRUE(notMatches("void f();", compoundStmt()));
+ EXPECT_TRUE(matches("void f() {}", compoundStmt()));
+ EXPECT_TRUE(matches("void f() {{}}", compoundStmt()));
}
TEST(CompoundStatement, DoesNotMatchEmptyStruct) {
// It's not a compound statement just because there's "{}" in the source
// text. This is an AST search, not grep.
EXPECT_TRUE(notMatches("namespace n { struct S {}; }",
- compoundStatement()));
+ compoundStmt()));
EXPECT_TRUE(matches("namespace n { struct S { void f() {{}} }; }",
- compoundStatement()));
+ compoundStmt()));
}
TEST(HasBody, FindsBodyOfForWhileDoLoops) {
EXPECT_TRUE(matches("void f() { for(;;) {} }",
- forStmt(hasBody(compoundStatement()))));
+ forStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(notMatches("void f() { for(;;); }",
- forStmt(hasBody(compoundStatement()))));
+ forStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(matches("void f() { while(true) {} }",
- whileStmt(hasBody(compoundStatement()))));
+ whileStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(matches("void f() { do {} while(true); }",
- doStmt(hasBody(compoundStatement()))));
+ doStmt(hasBody(compoundStmt()))));
}
TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
@@ -1895,67 +2128,67 @@ TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
// definition, and the function body itself must be a compound
// statement.
EXPECT_TRUE(matches("void f() { for (;;); }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, IsNotRecursive) {
// It's really "has any immediate substatement".
EXPECT_TRUE(notMatches("void f() { if (true) for (;;); }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) {
EXPECT_TRUE(matches("void f() { if (true) { for (;;); } }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) {
EXPECT_TRUE(matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) {
EXPECT_TRUE(matches("void f() { }",
- compoundStatement(statementCountIs(0))));
+ compoundStmt(statementCountIs(0))));
EXPECT_TRUE(notMatches("void f() {}",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
}
TEST(StatementCountIs, AppearsToMatchOnlyOneCount) {
EXPECT_TRUE(matches("void f() { 1; }",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
EXPECT_TRUE(notMatches("void f() { 1; }",
- compoundStatement(statementCountIs(0))));
+ compoundStmt(statementCountIs(0))));
EXPECT_TRUE(notMatches("void f() { 1; }",
- compoundStatement(statementCountIs(2))));
+ compoundStmt(statementCountIs(2))));
}
TEST(StatementCountIs, WorksWithMultipleStatements) {
EXPECT_TRUE(matches("void f() { 1; 2; 3; }",
- compoundStatement(statementCountIs(3))));
+ compoundStmt(statementCountIs(3))));
}
TEST(StatementCountIs, WorksWithNestedCompoundStatements) {
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(2))));
+ compoundStmt(statementCountIs(2))));
EXPECT_TRUE(notMatches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(3))));
+ compoundStmt(statementCountIs(3))));
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(4))));
+ compoundStmt(statementCountIs(4))));
}
TEST(Member, WorksInSimplestCase) {
EXPECT_TRUE(matches("struct { int first; } s; int i(s.first);",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
}
TEST(Member, DoesNotMatchTheBaseExpression) {
// Don't pick out the wrong part of the member expression, this should
// be checking the member (name) only.
EXPECT_TRUE(notMatches("struct { int i; } first; int i(first.i);",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
}
TEST(Member, MatchesInMemberFunctionCall) {
@@ -1963,211 +2196,246 @@ TEST(Member, MatchesInMemberFunctionCall) {
" struct { void first() {}; } s;"
" s.first();"
"};",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
+}
+
+TEST(Member, MatchesMember) {
+ EXPECT_TRUE(matches(
+ "struct A { int i; }; void f() { A a; a.i = 2; }",
+ memberExpr(hasDeclaration(fieldDecl(hasType(isInteger()))))));
+ EXPECT_TRUE(notMatches(
+ "struct A { float f; }; void f() { A a; a.f = 2.0f; }",
+ memberExpr(hasDeclaration(fieldDecl(hasType(isInteger()))))));
+}
+
+TEST(Member, MatchesMemberAllocationFunction) {
+ // Fails in C++11 mode
+ EXPECT_TRUE(matchesConditionally(
+ "namespace std { typedef typeof(sizeof(int)) size_t; }"
+ "class X { void *operator new(std::size_t); };",
+ methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98"));
+
+ EXPECT_TRUE(matches("class X { void operator delete(void*); };",
+ methodDecl(ofClass(hasName("X")))));
+
+ // Fails in C++11 mode
+ EXPECT_TRUE(matchesConditionally(
+ "namespace std { typedef typeof(sizeof(int)) size_t; }"
+ "class X { void operator delete[](void*, std::size_t); };",
+ methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98"));
}
TEST(HasObjectExpression, DoesNotMatchMember) {
EXPECT_TRUE(notMatches(
"class X {}; struct Z { X m; }; void f(Z z) { z.m; }",
- memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+ memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))));
}
TEST(HasObjectExpression, MatchesBaseOfVariable) {
EXPECT_TRUE(matches(
"struct X { int m; }; void f(X x) { x.m; }",
- memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+ memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches(
"struct X { int m; }; void f(X* x) { x->m; }",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("X"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("X"))))))));
}
TEST(HasObjectExpression,
MatchesObjectExpressionOfImplicitlyFormedMemberExpression) {
EXPECT_TRUE(matches(
"class X {}; struct S { X m; void f() { this->m; } };",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("S"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("S"))))))));
EXPECT_TRUE(matches(
"class X {}; struct S { X m; void f() { m; } };",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("S"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("S"))))))));
}
TEST(Field, DoesNotMatchNonFieldMembers) {
- EXPECT_TRUE(notMatches("class X { void m(); };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { class m {}; };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { enum { m }; };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { enum m {}; };", field(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { void m(); };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { class m {}; };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum { m }; };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum m {}; };", fieldDecl(hasName("m"))));
}
TEST(Field, MatchesField) {
- EXPECT_TRUE(matches("class X { int m; };", field(hasName("m"))));
+ EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m"))));
}
TEST(IsConstQualified, MatchesConstInt) {
EXPECT_TRUE(matches("const int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, MatchesConstPointer) {
EXPECT_TRUE(matches("int i = 42; int* const p(&i);",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, MatchesThroughTypedef) {
EXPECT_TRUE(matches("typedef const int const_int; const_int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
EXPECT_TRUE(matches("typedef int* int_ptr; const int_ptr p(0);",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, DoesNotMatchInappropriately) {
EXPECT_TRUE(notMatches("typedef int nonconst_int; nonconst_int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
EXPECT_TRUE(notMatches("int const* p;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(CastExpression, MatchesExplicitCasts) {
- EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",
- expression(castExpr())));
- EXPECT_TRUE(matches("void *p = (void *)(&p);", expression(castExpr())));
- EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);",
- expression(castExpr())));
- EXPECT_TRUE(matches("char c = char(0);", expression(castExpr())));
+ EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",castExpr()));
+ EXPECT_TRUE(matches("void *p = (void *)(&p);", castExpr()));
+ EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", castExpr()));
+ EXPECT_TRUE(matches("char c = char(0);", castExpr()));
}
TEST(CastExpression, MatchesImplicitCasts) {
// This test creates an implicit cast from int to char.
- EXPECT_TRUE(matches("char c = 0;", expression(castExpr())));
+ EXPECT_TRUE(matches("char c = 0;", castExpr()));
// This test creates an implicit cast from lvalue to rvalue.
- EXPECT_TRUE(matches("char c = 0, d = c;", expression(castExpr())));
+ EXPECT_TRUE(matches("char c = 0, d = c;", castExpr()));
}
TEST(CastExpression, DoesNotMatchNonCasts) {
- EXPECT_TRUE(notMatches("char c = '0';", expression(castExpr())));
- EXPECT_TRUE(notMatches("char c, &q = c;", expression(castExpr())));
- EXPECT_TRUE(notMatches("int i = (0);", expression(castExpr())));
- EXPECT_TRUE(notMatches("int i = 0;", expression(castExpr())));
+ EXPECT_TRUE(notMatches("char c = '0';", castExpr()));
+ EXPECT_TRUE(notMatches("char c, &q = c;", castExpr()));
+ EXPECT_TRUE(notMatches("int i = (0);", castExpr()));
+ EXPECT_TRUE(notMatches("int i = 0;", castExpr()));
}
TEST(ReinterpretCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
}
TEST(ReinterpretCast, DoesNotMatchOtherCasts) {
- EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
- expression(reinterpretCast())));
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);", reinterpretCastExpr()));
EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
}
TEST(FunctionalCast, MatchesSimpleCase) {
std::string foo_class = "class Foo { public: Foo(char*); };";
EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
- expression(functionalCast())));
+ functionalCastExpr()));
}
TEST(FunctionalCast, DoesNotMatchOtherCasts) {
std::string FooClass = "class Foo { public: Foo(char*); };";
EXPECT_TRUE(
notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
- expression(functionalCast())));
+ functionalCastExpr()));
EXPECT_TRUE(
notMatches(FooClass + "void r() { Foo f = \"hello world\"; }",
- expression(functionalCast())));
+ functionalCastExpr()));
}
TEST(DynamicCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(dynamicCast())));
+ dynamicCastExpr()));
}
TEST(StaticCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));",
- expression(staticCast())));
+ staticCastExpr()));
}
TEST(StaticCast, DoesNotMatchOtherCasts) {
- EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
- expression(staticCast())));
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);", staticCastExpr()));
EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
- expression(staticCast())));
+ staticCastExpr()));
EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);",
- expression(staticCast())));
+ staticCastExpr()));
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(staticCast())));
+ staticCastExpr()));
+}
+
+TEST(CStyleCast, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("int i = (int) 2.2f;", cStyleCastExpr()));
+}
+
+TEST(CStyleCast, DoesNotMatchOtherCasts) {
+ EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);"
+ "char q, *r = const_cast<char*>(&q);"
+ "void* s = reinterpret_cast<char*>(&s);"
+ "struct B { virtual ~B() {} }; struct D : B {};"
+ "B b;"
+ "D* t = dynamic_cast<D*>(&b);",
+ cStyleCastExpr()));
}
TEST(HasDestinationType, MatchesSimpleCase) {
EXPECT_TRUE(matches("char* p = static_cast<char*>(0);",
- expression(
- staticCast(hasDestinationType(
- pointsTo(TypeMatcher(anything())))))));
+ staticCastExpr(hasDestinationType(
+ pointsTo(TypeMatcher(anything()))))));
}
TEST(HasImplicitDestinationType, MatchesSimpleCase) {
// This test creates an implicit const cast.
EXPECT_TRUE(matches("int x; const int i = x;",
- expression(implicitCast(
- hasImplicitDestinationType(isInteger())))));
+ implicitCastExpr(
+ hasImplicitDestinationType(isInteger()))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(matches("int arr[3]; int *p = arr;",
- expression(implicitCast(hasImplicitDestinationType(
- pointsTo(TypeMatcher(anything())))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ pointsTo(TypeMatcher(anything()))))));
}
TEST(HasImplicitDestinationType, DoesNotMatchIncorrectly) {
// This test creates an implicit cast from int to char.
EXPECT_TRUE(notMatches("char c = 0;",
- expression(implicitCast(hasImplicitDestinationType(
- unless(anything()))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ unless(anything())))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(notMatches("int arr[3]; int *p = arr;",
- expression(implicitCast(hasImplicitDestinationType(
- unless(anything()))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ unless(anything())))));
}
TEST(ImplicitCast, MatchesSimpleCase) {
// This test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
// This test creates an implicit cast from int to char.
EXPECT_TRUE(matches("char c = 0;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(matches("int arr[6]; int *p = arr;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
}
TEST(ImplicitCast, DoesNotMatchIncorrectly) {
- // This test verifies that implicitCast() matches exactly when implicit casts
+ // This test verifies that implicitCastExpr() matches exactly when implicit casts
// are present, and that it ignores explicit and paren casts.
// These two test cases have no casts.
EXPECT_TRUE(notMatches("int x = 0;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = 0, &y = x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = 0; double d = (double) x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("const int *p; int *q = const_cast<int *>(p);",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = (0);",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
}
TEST(IgnoringImpCasts, MatchesImpCasts) {
@@ -2175,11 +2443,11 @@ TEST(IgnoringImpCasts, MatchesImpCasts) {
// present and its inner matcher alone does not match.
// Note that this test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(ignoringImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
// This test creates an implict cast from int to char.
EXPECT_TRUE(matches("char x = 0;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
integerLiteral(equals(0)))))));
}
@@ -2188,82 +2456,82 @@ TEST(IgnoringImpCasts, DoesNotMatchIncorrectly) {
// matcher does not match.
// Note that the first test creates an implicit const cast.
EXPECT_TRUE(notMatches("int x; const int y = x;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
unless(anything()))))));
EXPECT_TRUE(notMatches("int x; int y = x;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
unless(anything()))))));
// These tests verify that ignoringImplictCasts does not look through explicit
// casts or parentheses.
EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("int i = (0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float i = (float)0;",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float i = float(0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
}
TEST(IgnoringImpCasts, MatchesWithoutImpCasts) {
// This test verifies that expressions that do not have implicit casts
// still match the inner matcher.
EXPECT_TRUE(matches("int x = 0; int &y = x;",
- variable(hasInitializer(ignoringImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
}
TEST(IgnoringParenCasts, MatchesParenCasts) {
// This test checks that ignoringParenCasts matches when parentheses and/or
// casts are present and its inner matcher alone does not match.
EXPECT_TRUE(matches("int x = (0);",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("int x = (((((0)))));",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
// This test creates an implict cast from int to char in addition to the
// parentheses.
EXPECT_TRUE(matches("char x = (0);",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("char x = (char)0;",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
integerLiteral(equals(0)))))));
}
TEST(IgnoringParenCasts, MatchesWithoutParenCasts) {
// This test verifies that expressions that do not have any casts still match.
EXPECT_TRUE(matches("int x = 0;",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenCasts, DoesNotMatchIncorrectly) {
// These tests verify that ignoringImpCasts does not match if the inner
// matcher does not match.
EXPECT_TRUE(notMatches("int x = ((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
// This test creates an implicit cast from int to char in addition to the
// parentheses.
EXPECT_TRUE(notMatches("char x = ((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
EXPECT_TRUE(notMatches("char *x = static_cast<char *>((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
}
@@ -2273,23 +2541,23 @@ TEST(IgnoringParenAndImpCasts, MatchesParenImpCasts) {
// does not match.
// Note that this test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(ignoringParenImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
// This test creates an implicit cast from int to char.
EXPECT_TRUE(matches("const char x = (0);",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenAndImpCasts, MatchesWithoutParenImpCasts) {
// This test verifies that expressions that do not have parentheses or
// implicit casts still match.
EXPECT_TRUE(matches("int x = 0; int &y = x;",
- variable(hasInitializer(ignoringParenImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
EXPECT_TRUE(matches("int x = 0;",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) {
@@ -2297,56 +2565,56 @@ TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) {
// the inner matcher does not match.
// This test creates an implicit cast.
EXPECT_TRUE(notMatches("char c = ((3));",
- variable(hasInitializer(ignoringParenImpCasts(
+ varDecl(hasInitializer(ignoringParenImpCasts(
unless(anything()))))));
// These tests verify that ignoringParenAndImplictCasts does not look
// through explicit casts.
EXPECT_TRUE(notMatches("float y = (float(0));",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float y = (float)0;",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
}
TEST(HasSourceExpression, MatchesImplicitCasts) {
EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };"
"void r() {string a_string; URL url = a_string; }",
- expression(implicitCast(
- hasSourceExpression(constructorCall())))));
+ implicitCastExpr(
+ hasSourceExpression(constructExpr()))));
}
TEST(HasSourceExpression, MatchesExplicitCasts) {
EXPECT_TRUE(matches("float x = static_cast<float>(42);",
- expression(explicitCast(
- hasSourceExpression(hasDescendant(
- expression(integerLiteral())))))));
+ explicitCastExpr(
+ hasSourceExpression(hasDescendant(
+ expr(integerLiteral()))))));
}
TEST(Statement, DoesNotMatchDeclarations) {
- EXPECT_TRUE(notMatches("class X {};", statement()));
+ EXPECT_TRUE(notMatches("class X {};", stmt()));
}
TEST(Statement, MatchesCompoundStatments) {
- EXPECT_TRUE(matches("void x() {}", statement()));
+ EXPECT_TRUE(matches("void x() {}", stmt()));
}
TEST(DeclarationStatement, DoesNotMatchCompoundStatements) {
- EXPECT_TRUE(notMatches("void x() {}", declarationStatement()));
+ EXPECT_TRUE(notMatches("void x() {}", declStmt()));
}
TEST(DeclarationStatement, MatchesVariableDeclarationStatements) {
- EXPECT_TRUE(matches("void x() { int a; }", declarationStatement()));
+ EXPECT_TRUE(matches("void x() { int a; }", declStmt()));
}
TEST(InitListExpression, MatchesInitListExpression) {
EXPECT_TRUE(matches("int a[] = { 1, 2 };",
initListExpr(hasType(asString("int [2]")))));
EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };",
- initListExpr(hasType(record(hasName("B"))))));
+ initListExpr(hasType(recordDecl(hasName("B"))))));
}
TEST(UsingDeclaration, MatchesUsingDeclarations) {
@@ -2362,24 +2630,24 @@ TEST(UsingDeclaration, MatchesShadowUsingDelcarations) {
TEST(UsingDeclaration, MatchesSpecificTarget) {
EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;",
usingDecl(hasAnyUsingShadowDecl(
- hasTargetDecl(function())))));
+ hasTargetDecl(functionDecl())))));
EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;",
usingDecl(hasAnyUsingShadowDecl(
- hasTargetDecl(function())))));
+ hasTargetDecl(functionDecl())))));
}
TEST(UsingDeclaration, ThroughUsingDeclaration) {
EXPECT_TRUE(matches(
"namespace a { void f(); } using a::f; void g() { f(); }",
- declarationReference(throughUsingDecl(anything()))));
+ declRefExpr(throughUsingDecl(anything()))));
EXPECT_TRUE(notMatches(
"namespace a { void f(); } using a::f; void g() { a::f(); }",
- declarationReference(throughUsingDecl(anything()))));
+ declRefExpr(throughUsingDecl(anything()))));
}
TEST(SingleDecl, IsSingleDecl) {
StatementMatcher SingleDeclStmt =
- declarationStatement(hasSingleDecl(variable(hasInitializer(anything()))));
+ declStmt(hasSingleDecl(varDecl(hasInitializer(anything()))));
EXPECT_TRUE(matches("void f() {int a = 4;}", SingleDeclStmt));
EXPECT_TRUE(notMatches("void f() {int a;}", SingleDeclStmt));
EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}",
@@ -2387,28 +2655,26 @@ TEST(SingleDecl, IsSingleDecl) {
}
TEST(DeclStmt, ContainsDeclaration) {
- DeclarationMatcher MatchesInit = variable(hasInitializer(anything()));
+ DeclarationMatcher MatchesInit = varDecl(hasInitializer(anything()));
EXPECT_TRUE(matches("void f() {int a = 4;}",
- declarationStatement(containsDeclaration(0,
- MatchesInit))));
+ declStmt(containsDeclaration(0, MatchesInit))));
EXPECT_TRUE(matches("void f() {int a = 4, b = 3;}",
- declarationStatement(containsDeclaration(0, MatchesInit),
- containsDeclaration(1,
- MatchesInit))));
+ declStmt(containsDeclaration(0, MatchesInit),
+ containsDeclaration(1, MatchesInit))));
unsigned WrongIndex = 42;
EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}",
- declarationStatement(containsDeclaration(WrongIndex,
+ declStmt(containsDeclaration(WrongIndex,
MatchesInit))));
}
TEST(DeclCount, DeclCountIsCorrect) {
EXPECT_TRUE(matches("void f() {int i,j;}",
- declarationStatement(declCountIs(2))));
+ declStmt(declCountIs(2))));
EXPECT_TRUE(notMatches("void f() {int i,j; int k;}",
- declarationStatement(declCountIs(3))));
+ declStmt(declCountIs(3))));
EXPECT_TRUE(notMatches("void f() {int i,j, k, l;}",
- declarationStatement(declCountIs(3))));
+ declStmt(declCountIs(3))));
}
TEST(While, MatchesWhileLoops) {
@@ -2433,61 +2699,91 @@ TEST(SwitchCase, MatchesCase) {
EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase()));
}
+TEST(SwitchCase, MatchesSwitch) {
+ EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchStmt()));
+ EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchStmt()));
+ EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchStmt()));
+ EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
+}
+
+TEST(ExceptionHandling, SimpleCases) {
+ EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt()));
+ EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt()));
+ EXPECT_TRUE(notMatches("void foo() try { } catch(int X) { }", throwExpr()));
+ EXPECT_TRUE(matches("void foo() try { throw; } catch(int X) { }",
+ throwExpr()));
+ EXPECT_TRUE(matches("void foo() try { throw 5;} catch(int X) { }",
+ throwExpr()));
+}
+
TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
EXPECT_TRUE(notMatches(
"void x() { if(true) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
EXPECT_TRUE(notMatches(
"void x() { int x; if((x = 42)) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
}
TEST(HasConditionVariableStatement, MatchesConditionVariables) {
EXPECT_TRUE(matches(
"void x() { if(int* a = 0) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
}
TEST(ForEach, BindsOneNode) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
- record(hasName("C"), forEach(field(hasName("x")).bind("x"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+ recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))),
+ new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
}
TEST(ForEach, BindsMultipleNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };",
- record(hasName("C"), forEach(field().bind("f"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 3)));
+ recordDecl(hasName("C"), forEach(fieldDecl().bind("f"))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 3)));
}
TEST(ForEach, BindsRecursiveCombinations) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { int x; int y; }; class E { int y; int z; }; };",
- record(hasName("C"), forEach(record(forEach(field().bind("f"))))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+ recordDecl(hasName("C"),
+ forEach(recordDecl(forEach(fieldDecl().bind("f"))))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
}
TEST(ForEachDescendant, BindsOneNode) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
- record(hasName("C"), forEachDescendant(field(hasName("x")).bind("x"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+ recordDecl(hasName("C"),
+ forEachDescendant(fieldDecl(hasName("x")).bind("x"))),
+ new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
}
TEST(ForEachDescendant, BindsMultipleNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { int x; int y; }; "
" class E { class F { int y; int z; }; }; };",
- record(hasName("C"), forEachDescendant(field().bind("f"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+ recordDecl(hasName("C"), forEachDescendant(fieldDecl().bind("f"))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
}
TEST(ForEachDescendant, BindsRecursiveCombinations) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { "
" class E { class F { class G { int y; int z; }; }; }; }; };",
- record(hasName("C"), forEachDescendant(record(
- forEachDescendant(field().bind("f"))))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 8)));
+ recordDecl(hasName("C"), forEachDescendant(recordDecl(
+ forEachDescendant(fieldDecl().bind("f"))))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 8)));
+}
+
+TEST(ForEachDescendant, BindsCorrectNodes) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f(); int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FieldDecl>("decl", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f() {} int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));
}
@@ -2497,18 +2793,18 @@ TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> class X {}; class A {}; X<A> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
EXPECT_TRUE(matches(
"template <typename T> class X { T t; }; class A {}; X<A> x;",
- record(isTemplateInstantiation(), hasDescendant(
- field(hasType(record(hasName("A"))))))));
+ recordDecl(isTemplateInstantiation(), hasDescendant(
+ fieldDecl(hasType(recordDecl(hasName("A"))))))));
}
TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> void f(T t) {} class A {}; void g() { f(A()); }",
- function(hasParameter(0, hasType(record(hasName("A")))),
+ functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))),
isTemplateInstantiation())));
}
@@ -2516,8 +2812,8 @@ TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> class X { T t; }; class A {};"
"template class X<A>;",
- record(isTemplateInstantiation(), hasDescendant(
- field(hasType(record(hasName("A"))))))));
+ recordDecl(isTemplateInstantiation(), hasDescendant(
+ fieldDecl(hasType(recordDecl(hasName("A"))))))));
}
TEST(IsTemplateInstantiation,
@@ -2525,7 +2821,7 @@ TEST(IsTemplateInstantiation,
EXPECT_TRUE(matches(
"template <typename T> class X {};"
"template <typename T> class X<T*> {}; class A {}; X<A*> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation,
@@ -2536,7 +2832,7 @@ TEST(IsTemplateInstantiation,
" template <typename U> class Y { U u; };"
" Y<A> y;"
"};",
- record(hasName("::X::Y"), isTemplateInstantiation())));
+ recordDecl(hasName("::X::Y"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) {
@@ -2549,20 +2845,557 @@ TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) {
" template <typename U> class Y { U u; };"
" Y<T> y;"
"}; X<A> x;",
- record(hasName("::X<A>::Y"), unless(isTemplateInstantiation()))));
+ recordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation()))));
}
TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) {
EXPECT_TRUE(notMatches(
"template <typename T> class X {}; class A {};"
"template <> class X<A> {}; X<A> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
EXPECT_TRUE(notMatches(
"class A {}; class Y { A a; };",
- record(isTemplateInstantiation())));
+ recordDecl(isTemplateInstantiation())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchPrimaryTemplate) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {};",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t);",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchExplicitTemplateInstantiations) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {};"
+ "template class X<int>; extern template class X<long>;",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t) {}"
+ "template void f(int t); extern template void f(long t);",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchImplicitTemplateInstantiations) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {}; X<int> x;",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t); void g() { f(10); }",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ MatchesExplicitTemplateSpecializations) {
+ EXPECT_TRUE(matches(
+ "template <typename T> class X {};"
+ "template<> class X<int> {};",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(matches(
+ "template <typename T> void f(T t) {}"
+ "template<> void f(int t) {}",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(HasAncenstor, MatchesDeclarationAncestors) {
+ EXPECT_TRUE(matches(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("A"))))));
+}
+
+TEST(HasAncenstor, FailsIfNoAncestorMatches) {
+ EXPECT_TRUE(notMatches(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("X"))))));
+}
+
+TEST(HasAncestor, MatchesDeclarationsThatGetVisitedLater) {
+ EXPECT_TRUE(matches(
+ "class A { class B { void f() { C c; } class C {}; }; };",
+ varDecl(hasName("c"), hasType(recordDecl(hasName("C"),
+ hasAncestor(recordDecl(hasName("A"))))))));
+}
+
+TEST(HasAncenstor, MatchesStatementAncestors) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { while (false) { 42; } } }",
+ integerLiteral(equals(42), hasAncestor(ifStmt()))));
+}
+
+TEST(HasAncestor, DrillsThroughDifferentHierarchies) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { int x = 42; } }",
+ integerLiteral(equals(42), hasAncestor(functionDecl(hasName("f"))))));
+}
+
+TEST(HasAncestor, BindsRecursiveCombinations) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { class D { class E { class F { int y; }; }; }; };",
+ fieldDecl(hasAncestor(recordDecl(hasAncestor(recordDecl().bind("r"))))),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("r", 1)));
+}
+
+TEST(HasAncestor, BindsCombinationsWithHasDescendant) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { class D { class E { class F { int y; }; }; }; };",
+ fieldDecl(hasAncestor(
+ decl(
+ hasDescendant(recordDecl(isDefinition(),
+ hasAncestor(recordDecl())))
+ ).bind("d")
+ )),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("d", "E")));
+}
+
+TEST(HasAncestor, MatchesInTemplateInstantiations) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct A { struct B { struct C { T t; }; }; }; "
+ "A<int>::B::C a;",
+ fieldDecl(hasType(asString("int")),
+ hasAncestor(recordDecl(hasName("A"))))));
+}
+
+TEST(HasAncestor, MatchesInImplicitCode) {
+ EXPECT_TRUE(matches(
+ "struct X {}; struct A { A() {} X x; };",
+ constructorDecl(
+ hasAnyConstructorInitializer(withInitializer(expr(
+ hasAncestor(recordDecl(hasName("A")))))))));
+}
+
+TEST(HasParent, MatchesOnlyParent) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void f() { for (;;) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void f() { if (true) for (;;) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+}
+
+TEST(TypeMatching, MatchesTypes) {
+ EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
+}
+
+TEST(TypeMatching, MatchesArrayTypes) {
+ EXPECT_TRUE(matches("int a[] = {2,3};", arrayType()));
+ EXPECT_TRUE(matches("int a[42];", arrayType()));
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", arrayType()));
+
+ EXPECT_TRUE(notMatches("struct A {}; A a[7];",
+ arrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "typedef const int T; T x[] = { 1, 2 };",
+ qualType(isConstQualified(), arrayType())));
+
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(isConstQualified(), builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())),
+ unless(isConstQualified()))));
+
+ EXPECT_TRUE(matches("int a[2];",
+ constantArrayType(hasElementType(builtinType()))));
+ EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger())));
+}
+
+TEST(TypeMatching, MatchesComplexTypes) {
+ EXPECT_TRUE(matches("_Complex float f;", complexType()));
+ EXPECT_TRUE(matches(
+ "_Complex float f;",
+ complexType(hasElementType(builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "_Complex float f;",
+ complexType(hasElementType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesConstantArrayTypes) {
+ EXPECT_TRUE(matches("int a[2];", constantArrayType()));
+ EXPECT_TRUE(notMatches(
+ "void f() { int a[] = { 2, 3 }; int b[a[0]]; }",
+ constantArrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches("int a[42];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(matches("int b[2*21];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42))));
+}
+
+TEST(TypeMatching, MatchesDependentSizedArrayTypes) {
+ EXPECT_TRUE(matches(
+ "template <typename T, int Size> class array { T data[Size]; };",
+ dependentSizedArrayType()));
+ EXPECT_TRUE(notMatches(
+ "int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedArrayType()));
+}
+
+TEST(TypeMatching, MatchesIncompleteArrayType) {
+ EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
+ EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
+
+ EXPECT_TRUE(notMatches("int a[42]; void f() { int b[a[0]]; }",
+ incompleteArrayType()));
+}
+
+TEST(TypeMatching, MatchesVariableArrayType) {
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType()));
+ EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType()));
+
+ EXPECT_TRUE(matches(
+ "void f(int b) { int a[b]; }",
+ variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+ varDecl(hasName("b")))))))));
+}
+
+TEST(TypeMatching, MatchesAtomicTypes) {
+ EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
+
+ EXPECT_TRUE(matches("_Atomic(int) i;",
+ atomicType(hasValueType(isInteger()))));
+ EXPECT_TRUE(notMatches("_Atomic(float) f;",
+ atomicType(hasValueType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesAutoTypes) {
+ EXPECT_TRUE(matches("auto i = 2;", autoType()));
+ EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
+ autoType()));
+
+ EXPECT_TRUE(matches("auto a = 1;",
+ autoType(hasDeducedType(isInteger()))));
+ EXPECT_TRUE(notMatches("auto b = 2.0;",
+ autoType(hasDeducedType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesFunctionTypes) {
+ EXPECT_TRUE(matches("int (*f)(int);", functionType()));
+ EXPECT_TRUE(matches("void f(int i) {}", functionType()));
+}
+
+TEST(TypeMatching, PointerTypes) {
+ // FIXME: Reactive when these tests can be more specific (not matching
+ // implicit code on certain platforms), likely when we have hasDescendant for
+ // Types/TypeLocs.
+ //EXPECT_TRUE(matchAndVerifyResultTrue(
+ // "int* a;",
+ // pointerTypeLoc(pointeeLoc(typeLoc().bind("loc"))),
+ // new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ //EXPECT_TRUE(matchAndVerifyResultTrue(
+ // "int* a;",
+ // pointerTypeLoc().bind("loc"),
+ // new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ pointerTypeLoc(pointeeLoc(loc(qualType())))));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ loc(pointerType(pointee(pointerType())))));
+ EXPECT_TRUE(matches(
+ "int* b; int* * const a = &b;",
+ loc(qualType(isConstQualified(), pointerType()))));
+
+ std::string Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(referenceType()))));
+
+ Fragment = "int *ptr;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(referenceType()))));
+
+ Fragment = "int a; int &ref = a;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(referenceType()))));
+}
+
+TEST(TypeMatching, PointeeTypes) {
+ EXPECT_TRUE(matches("int b; int &a = b;",
+ referenceType(pointee(builtinType()))));
+ EXPECT_TRUE(matches("int *a;", pointerType(pointee(builtinType()))));
+
+ EXPECT_TRUE(matches("int *a;",
+ pointerTypeLoc(pointeeLoc(loc(builtinType())))));
+
+ EXPECT_TRUE(matches(
+ "int const *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "int *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+}
+
+TEST(TypeMatching, MatchesPointersToConstTypes) {
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ loc(pointerType())));
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ pointerTypeLoc()));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerTypeLoc(pointeeLoc(builtinTypeLoc()))));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerType(pointee(builtinType()))));
+}
+
+TEST(TypeMatching, MatchesTypedefTypes) {
+ EXPECT_TRUE(matches("typedef int X; X a;", varDecl(hasName("a"),
+ hasType(typedefType()))));
+
+ EXPECT_TRUE(matches("typedef int X; X a;",
+ varDecl(hasName("a"),
+ hasType(typedefType(hasDecl(decl()))))));
+}
+
+TEST(NNS, MatchesNestedNameSpecifiers) {
+ EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}",
+ nestedNameSpecifier()));
+
+ EXPECT_TRUE(matches(
+ "struct A { static void f() {} }; void g() { A::f(); }",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(notMatches(
+ "struct A { static void f() {} }; void g(A* a) { a->f(); }",
+ nestedNameSpecifier()));
+}
+
+TEST(NullStatement, SimpleCases) {
+ EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
+ EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
+}
+
+TEST(NNS, MatchesTypes) {
+ NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+ specifiesType(hasDeclaration(recordDecl(hasName("A")))));
+ EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher));
+ EXPECT_TRUE(matches("struct A { struct B { struct C {}; }; }; A::B::C c;",
+ Matcher));
+ EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher));
+}
+
+TEST(NNS, MatchesNamespaceDecls) {
+ NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+ specifiesNamespace(hasName("ns")));
+ EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher));
+ EXPECT_TRUE(notMatches("namespace xx { struct A {}; } xx::A a;", Matcher));
+ EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher));
+}
+
+TEST(NNS, BindsNestedNameSpecifiers) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "namespace ns { struct E { struct B {}; }; } ns::E::B b;",
+ nestedNameSpecifier(specifiesType(asString("struct ns::E"))).bind("nns"),
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("nns", "ns::struct E::")));
+}
+
+TEST(NNS, BindsNestedNameSpecifierLocs) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "namespace ns { struct B {}; } ns::B b;",
+ loc(nestedNameSpecifier()).bind("loc"),
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("loc", 1)));
+}
+
+TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
+ EXPECT_TRUE(matches(
+ "struct A { struct B { struct C {}; }; }; A::B::C c;",
+ nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
+ EXPECT_TRUE(matches(
+ "struct A { struct B { struct C {}; }; }; A::B::C c;",
+ nestedNameSpecifierLoc(hasPrefix(
+ specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
+}
+
+TEST(NNS, DescendantsOfNestedNameSpecifiers) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ hasDescendant(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+ EXPECT_TRUE(notMatches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ has(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A")),
+ has(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+
+ // Not really useful because a NestedNameSpecifier can af at most one child,
+ // but to complete the interface.
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ forEach(nestedNameSpecifier().bind("x"))),
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 1)));
+}
+
+TEST(NNS, NestedNameSpecifiersAsDescendants) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ decl(hasDescendant(nestedNameSpecifier(specifiesType(
+ asString("struct a::A")))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ functionDecl(hasName("f"),
+ forEachDescendant(nestedNameSpecifier().bind("x"))),
+ // Nested names: a, a::A and a::A::B.
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 3)));
+}
+
+TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ hasDescendant(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+ EXPECT_TRUE(notMatches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ has(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))),
+ has(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ forEach(nestedNameSpecifierLoc().bind("x"))),
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 1)));
+}
+
+TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ decl(hasDescendant(loc(nestedNameSpecifier(specifiesType(
+ asString("struct a::A"))))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ functionDecl(hasName("f"),
+ forEachDescendant(nestedNameSpecifierLoc().bind("x"))),
+ // Nested names: a, a::A and a::A::B.
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
+}
+
+template <typename T>
+class VerifyRecursiveMatch : public BoundNodesCallback {
+public:
+ explicit VerifyRecursiveMatch(StringRef Id,
+ const internal::Matcher<T> &InnerMatcher)
+ : Id(Id), InnerMatcher(InnerMatcher) {}
+
+ virtual bool run(const BoundNodes *Nodes) {
+ return false;
+ }
+
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ const T *Node = Nodes->getNodeAs<T>(Id);
+ bool Found = false;
+ MatchFinder Finder;
+ Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found));
+ Finder.findAll(*Node, *Context);
+ return Found;
+ }
+private:
+ std::string Id;
+ internal::Matcher<T> InnerMatcher;
+};
+
+TEST(MatchFinder, CanMatchDeclarationsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
+ EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
+}
+
+TEST(MatchFinder, CanMatchStatementsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
+ EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+}
+
+class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
+public:
+ VerifyStartOfTranslationUnit() : Called(false) {}
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ EXPECT_TRUE(Called);
+ }
+ virtual void onStartOfTranslationUnit() {
+ Called = true;
+ }
+ bool Called;
+};
+
+TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
+ MatchFinder Finder;
+ VerifyStartOfTranslationUnit VerifyCallback;
+ Finder.addMatcher(decl(), &VerifyCallback);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+ EXPECT_TRUE(VerifyCallback.Called);
}
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 64816f5d6046..3b23ada8da77 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -18,13 +18,14 @@ namespace clang {
namespace ast_matchers {
using clang::tooling::newFrontendActionFactory;
-using clang::tooling::runToolOnCode;
+using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
class BoundNodesCallback {
public:
virtual ~BoundNodesCallback() {}
virtual bool run(const BoundNodes *BoundNodes) = 0;
+ virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
};
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
@@ -37,7 +38,7 @@ public:
virtual void run(const MatchFinder::MatchResult &Result) {
if (FindResultReviewer != NULL) {
- *Verified = FindResultReviewer->run(&Result.Nodes);
+ *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
*Verified = true;
}
@@ -51,12 +52,15 @@ private:
template <typename T>
testing::AssertionResult matchesConditionally(const std::string &Code,
const T &AMatcher,
- bool ExpectMatch) {
+ bool ExpectMatch,
+ llvm::StringRef CompileArg) {
bool Found = false;
MatchFinder Finder;
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- if (!runToolOnCode(Factory->create(), Code)) {
+ // 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 && ExpectMatch) {
@@ -71,13 +75,13 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
template <typename T>
testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, true);
+ return matchesConditionally(Code, AMatcher, true, "-std=c++11");
}
template <typename T>
testing::AssertionResult notMatches(const std::string &Code,
const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, false);
+ return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
template <typename T>
@@ -91,7 +95,9 @@ matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
Finder.addMatcher(
AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- if (!runToolOnCode(Factory->create(), Code)) {
+ // Some tests use typeof, which is a gnu extension.
+ std::vector<std::string> Args(1, "-std=gnu++98");
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (!VerifiedResult && ExpectResult) {
diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile
index d3e4aa37ce74..9ca1006b1413 100644
--- a/unittests/ASTMatchers/Makefile
+++ b/unittests/ASTMatchers/Makefile
@@ -13,7 +13,8 @@ TESTNAME = ASTMatchers
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
- clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \
+ clangRewriteCore.a clangRewriteFrontend.a \
+ clangParse.a clangSema.a clangAnalysis.a \
clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index de3b72318ccf..6f404b541cc1 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
@@ -32,10 +35,11 @@ protected:
SourceManagerTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions) {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -44,7 +48,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -64,9 +68,9 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
@@ -179,9 +183,9 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
@@ -276,9 +280,9 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index bfc3494320e6..4b6f8753e90b 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -14,7 +14,8 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
- clangARCMigrate.a clangRewrite.a clangEdit.a \
+ clangARCMigrate.a clangRewriteCore.a \
+ clangRewriteFrontend.a clangEdit.a \
clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 10c936199d6b..03c8cd5418a4 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -1,6 +1,7 @@
add_clang_unittest(LexTests
LexerTest.cpp
PreprocessingRecordTest.cpp
+ PPCallbacksTest.cpp
)
target_link_libraries(LexTests
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index e43ad86ff597..e95cd023ab9e 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Config/config.h"
#include "gtest/gtest.h"
@@ -31,10 +34,12 @@ protected:
LexerTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions)
+ {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -43,7 +48,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -69,9 +74,9 @@ TEST_F(LexerTest, LexAPI) {
(void)SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ Target.getPtr());
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
new file mode 100644
index 000000000000..6e7efa980c9e
--- /dev/null
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -0,0 +1,246 @@
+//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/PathV2.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace clang;
+
+namespace {
+
+// Stub out module loading.
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+// Stub to collect data from InclusionDirective callbacks.
+class InclusionDirectiveCallbacks : public PPCallbacks {
+public:
+ void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ CharSourceRange FilenameRange,
+ const FileEntry *File,
+ StringRef SearchPath,
+ StringRef RelativePath,
+ const Module *Imported) {
+ this->HashLoc = HashLoc;
+ this->IncludeTok = IncludeTok;
+ this->FileName = FileName.str();
+ this->IsAngled = IsAngled;
+ this->FilenameRange = FilenameRange;
+ this->File = File;
+ this->SearchPath = SearchPath.str();
+ this->RelativePath = RelativePath.str();
+ this->Imported = Imported;
+ }
+
+ SourceLocation HashLoc;
+ Token IncludeTok;
+ SmallString<16> FileName;
+ bool IsAngled;
+ CharSourceRange FilenameRange;
+ const FileEntry* File;
+ SmallString<16> SearchPath;
+ SmallString<16> RelativePath;
+ const Module* Imported;
+};
+
+// PPCallbacks test fixture.
+class PPCallbacksTest : public ::testing::Test {
+protected:
+ PPCallbacksTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ DiagOpts(new DiagnosticOptions()),
+ Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts = new TargetOptions();
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+
+ // Register a header path as a known file and add its location
+ // to search path.
+ void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
+ bool IsSystemHeader) {
+ // Tell FileMgr about header.
+ FileMgr.getVirtualFile(HeaderPath, 0, 0);
+
+ // Add header's parent path to search path.
+ StringRef SearchPath = path::parent_path(HeaderPath);
+ const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
+ DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ HeaderInfo.AddSearchPath(DL, IsSystemHeader);
+ }
+
+ // Get the raw source string of the range.
+ StringRef GetSourceString(CharSourceRange Range) {
+ const char* B = SourceMgr.getCharacterData(Range.getBegin());
+ const char* E = SourceMgr.getCharacterData(Range.getEnd());
+
+ return StringRef(B, E - B);
+ }
+
+ // Run lexer over SourceText and collect FilenameRange from
+ // the InclusionDirective callback.
+ CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
+ const char* HeaderPath, bool SystemHeader) {
+ MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
+ (void)SourceMgr.createMainFileIDForMemBuffer(Buf);
+
+ VoidModuleLoader ModLoader;
+
+ IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
+ HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr());
+ AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
+
+ IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
+ Preprocessor PP(PPOpts, Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
+ PP.addPPCallbacks(Callbacks); // Takes ownership.
+
+ // Lex source text.
+ PP.EnterMainSourceFile();
+
+ while (true) {
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.is(tok::eof))
+ break;
+ }
+
+ // Callbacks have been executed at this point -- return filename range.
+ return Callbacks->FilenameRange;
+ }
+};
+
+TEST_F(PPCallbacksTest, QuotedFilename) {
+ const char* Source =
+ "#include \"quoted.h\"\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, AngledFilename) {
+ const char* Source =
+ "#include <angled.h>\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", true);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, QuotedInMacro) {
+ const char* Source =
+ "#define MACRO_QUOTED \"quoted.h\"\n"
+ "#include MACRO_QUOTED\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, AngledInMacro) {
+ const char* Source =
+ "#define MACRO_ANGLED <angled.h>\n"
+ "#include MACRO_ANGLED\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", true);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, StringizedMacroArgument) {
+ const char* Source =
+ "#define MACRO_STRINGIZED(x) #x\n"
+ "#include MACRO_STRINGIZED(quoted.h)\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
+ const char* Source =
+ "#define MACRO_ANGLED <angled.h>\n"
+ "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
+ "#include MACRO_CONCAT(MACRO, ANGLED)\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", false);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, TrigraphFilename) {
+ const char* Source =
+ "#include \"tri\?\?-graph.h\"\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
+
+ ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, TrigraphInMacro) {
+ const char* Source =
+ "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
+ "#include MACRO_TRIGRAPH\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
+
+ ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
+}
+
+} // anonoymous namespace
diff --git a/unittests/Lex/PreprocessingRecordTest.cpp b/unittests/Lex/PreprocessingRecordTest.cpp
index 5b5d933d1b1d..815081aa7e13 100644
--- a/unittests/Lex/PreprocessingRecordTest.cpp
+++ b/unittests/Lex/PreprocessingRecordTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/Config/config.h"
@@ -32,10 +35,12 @@ protected:
PreprocessingRecordTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions)
+ {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -44,7 +49,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -80,9 +85,9 @@ TEST_F(PreprocessingRecordTest, PPRecAPI) {
SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ Target.getPtr());
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 4eaf33956f3b..bd7317fe4ae8 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -18,5 +18,5 @@ add_clang_unittest(ToolingTests
target_link_libraries(ToolingTests
clangAST
clangTooling
- clangRewrite
+ clangRewriteCore
)
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 591d48dbbd61..5ed4240c1ee0 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -11,8 +11,10 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/FileMatchTrie.h"
+#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/PathV2.h"
#include "gtest/gtest.h"
namespace clang {
@@ -55,13 +57,16 @@ TEST(JSONCompilationDatabase, GetAllFiles) {
getAllFiles("[]", ErrorMessage)) << ErrorMessage;
std::vector<std::string> expected_files;
- expected_files.push_back("file1");
- expected_files.push_back("file2");
+ SmallString<16> PathStorage;
+ llvm::sys::path::native("//net/dir/file1", PathStorage);
+ expected_files.push_back(PathStorage.str());
+ llvm::sys::path::native("//net/dir/file2", PathStorage);
+ expected_files.push_back(PathStorage.str());
EXPECT_EQ(expected_files, getAllFiles(
- "[{\"directory\":\"dir\","
+ "[{\"directory\":\"//net/dir\","
"\"command\":\"command\","
"\"file\":\"file1\"},"
- " {\"directory\":\"dir\","
+ " {\"directory\":\"//net/dir\","
"\"command\":\"command\","
"\"file\":\"file2\"}]",
ErrorMessage)) << ErrorMessage;
@@ -81,6 +86,82 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
return Commands[0];
}
+struct FakeComparator : public PathComparator {
+ virtual ~FakeComparator() {}
+ virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ return FileA.equals_lower(FileB);
+ }
+};
+
+class FileMatchTrieTest : public ::testing::Test {
+protected:
+ FileMatchTrieTest() : Trie(new FakeComparator()) {}
+
+ StringRef find(StringRef Path) {
+ llvm::raw_string_ostream ES(Error);
+ return Trie.findEquivalent(Path, ES);
+ }
+
+ FileMatchTrie Trie;
+ std::string Error;
+};
+
+TEST_F(FileMatchTrieTest, InsertingRelativePath) {
+ Trie.insert("//net/path/file.cc");
+ Trie.insert("file.cc");
+ EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, MatchingRelativePath) {
+ EXPECT_EQ("", find("file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, ReturnsBestResults) {
+ Trie.insert("//net/d/c/b.cc");
+ Trie.insert("//net/d/b/b.cc");
+ EXPECT_EQ("//net/d/b/b.cc", find("//net/d/b/b.cc"));
+}
+
+TEST_F(FileMatchTrieTest, HandlesSymlinks) {
+ Trie.insert("//net/AA/file.cc");
+ EXPECT_EQ("//net/AA/file.cc", find("//net/aa/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, ReportsSymlinkAmbiguity) {
+ Trie.insert("//net/Aa/file.cc");
+ Trie.insert("//net/aA/file.cc");
+ EXPECT_TRUE(find("//net/aa/file.cc").empty());
+ EXPECT_EQ("Path is ambiguous", Error);
+}
+
+TEST_F(FileMatchTrieTest, LongerMatchingSuffixPreferred) {
+ Trie.insert("//net/src/Aa/file.cc");
+ Trie.insert("//net/src/aA/file.cc");
+ Trie.insert("//net/SRC/aa/file.cc");
+ EXPECT_EQ("//net/SRC/aa/file.cc", find("//net/src/aa/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, EmptyTrie) {
+ EXPECT_TRUE(find("//net/some/path").empty());
+}
+
+TEST_F(FileMatchTrieTest, NoResult) {
+ Trie.insert("//net/somepath/otherfile.cc");
+ Trie.insert("//net/otherpath/somefile.cc");
+ EXPECT_EQ("", find("//net/somepath/somefile.cc"));
+}
+
+TEST_F(FileMatchTrieTest, RootElementDifferent) {
+ Trie.insert("//net/path/file.cc");
+ Trie.insert("//net/otherpath/file.cc");
+ EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, CannotResolveRelativePath) {
+ EXPECT_EQ("", find("relative-path.cc"));
+ EXPECT_EQ("Cannot resolve relative paths", Error);
+}
+
TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
std::string ErrorMessage;
CompileCommand NotFound = findCompileArgsInJsonDatabase(
@@ -90,9 +171,9 @@ TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
}
TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
- StringRef Directory("/some/directory");
- StringRef FileName("/path/to/a-file.cpp");
- StringRef Command("/path/to/compiler and some arguments");
+ StringRef Directory("//net/some/directory");
+ StringRef FileName("//net/path/to/a-file.cpp");
+ StringRef Command("//net/path/to/compiler and some arguments");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
FileName,
@@ -102,7 +183,8 @@ TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
ErrorMessage);
EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
- EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("//net/path/to/compiler",
+ FoundCommand.CommandLine[0]) << ErrorMessage;
EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
@@ -118,9 +200,9 @@ TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
}
TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
- StringRef Directory("/some/directory");
- StringRef FileName("/path/to/a-file.cpp");
- StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
+ StringRef Directory("//net/some/directory");
+ StringRef FileName("//net/path/to/a-file.cpp");
+ StringRef Command("\\\"//net/path to compiler\\\" \\\"and an argument\\\"");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
FileName,
@@ -129,13 +211,14 @@ TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
"\"file\":\"" + FileName + "\"}]").str(),
ErrorMessage);
ASSERT_EQ(2u, FoundCommand.CommandLine.size());
- EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("//net/path to compiler",
+ FoundCommand.CommandLine[0]) << ErrorMessage;
EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
}
TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
- StringRef Directory("/some directory / with spaces");
- StringRef FileName("/path/to/a-file.cpp");
+ StringRef Directory("//net/some directory / with spaces");
+ StringRef FileName("//net/path/to/a-file.cpp");
StringRef Command("a command");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
@@ -148,7 +231,7 @@ TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
}
TEST(findCompileArgsInJsonDatabase, FindsEntry) {
- StringRef Directory("directory");
+ StringRef Directory("//net/directory");
StringRef FileName("file");
StringRef Command("command");
std::string JsonDatabase = "[";
@@ -162,19 +245,19 @@ TEST(findCompileArgsInJsonDatabase, FindsEntry) {
JsonDatabase += "]";
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
- "file4", JsonDatabase, ErrorMessage);
- EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+ "//net/directory4/file4", JsonDatabase, ErrorMessage);
+ EXPECT_EQ("//net/directory4", FoundCommand.Directory) << ErrorMessage;
ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
}
static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
std::string JsonDatabase =
- ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
+ ("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
Command + "\"}]").str();
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
- "test", JsonDatabase, ErrorMessage);
+ "//net/root/test", JsonDatabase, ErrorMessage);
EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
return FoundCommand.CommandLine;
}
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
index 5d2224d40e15..5ed99fcc430b 100644
--- a/unittests/Tooling/Makefile
+++ b/unittests/Tooling/Makefile
@@ -12,7 +12,8 @@ TESTNAME = Tooling
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
- clangParse.a clangRewrite.a clangSema.a clangAnalysis.a clangEdit.a \
+ clangParse.a clangRewriteCore.a clangRewriteFrontend.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/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 4b539067b136..a68a869bf55d 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -385,6 +385,66 @@ TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
"int main() { Simple s; Simple t(s); }\n"));
}
+/// \brief A visitor that optionally includes implicit code and matches
+/// CXXConstructExpr.
+///
+/// The name recorded for the match is the name of the class whose constructor
+/// is invoked by the CXXConstructExpr, not the name of the class whose
+/// constructor the CXXConstructExpr is contained in.
+class ConstructExprVisitor
+ : public ExpectedLocationVisitor<ConstructExprVisitor> {
+public:
+ ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+ bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+ void setShouldVisitImplicitCode(bool NewValue) {
+ ShouldVisitImplicitCode = NewValue;
+ }
+
+ bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
+ if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
+ if (const CXXRecordDecl* Class = Ctor->getParent()) {
+ Match(Class->getName(), Expr->getLocation());
+ }
+ }
+ return true;
+ }
+
+ private:
+ bool ShouldVisitImplicitCode;
+};
+
+TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(true);
+ Visitor.ExpectMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that visits implicit code visits that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
+// The same as CanVisitImplicitMemberInitializations, but checking that the
+// visits are omitted when the visitor does not include implicit code.
+TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(false);
+ Visitor.DisallowMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that skips implicit code skips that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
TEST(RecursiveASTVisitor, VisitsExtension) {
DeclRefExprVisitor Visitor;
Visitor.ExpectMatch("s", 1, 24);
@@ -392,4 +452,12 @@ TEST(RecursiveASTVisitor, VisitsExtension) {
"int s = __extension__ (s);\n"));
}
+TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("struct S", 1, 26);
+ EXPECT_TRUE(Visitor.runOver(
+ "int f() { return (struct S { int a; }){.a = 0}.a; }",
+ TypeLocVisitor::Lang_C));
+}
+
} // end namespace clang
diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp
index 00eb193d74c0..4e30cfde26ab 100644
--- a/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -10,8 +10,8 @@
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/RefactoringCallbacks.h"
-#include "gtest/gtest.h"
#include "RewriterTestContext.h"
+#include "gtest/gtest.h"
namespace clang {
namespace tooling {
@@ -40,28 +40,28 @@ TEST(RefactoringCallbacksTest, ReplacesStmtsWithString) {
std::string Code = "void f() { int i = 1; }";
std::string Expected = "void f() { ; }";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, ReplacesStmtsInCalledMacros) {
std::string Code = "#define A void f() { int i = 1; }\nA";
std::string Expected = "#define A void f() { ; }\nA";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, IgnoresStmtsInUncalledMacros) {
std::string Code = "#define A void f() { int i = 1; }";
std::string Expected = "#define A void f() { int i = 1; }";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, ReplacesInteger) {
std::string Code = "void f() { int i = 1; }";
std::string Expected = "void f() { int i = 2; }";
ReplaceStmtWithText Callback("id", "2");
- expectRewritten(Code, Expected, id("id", expression(integerLiteral())),
+ expectRewritten(Code, Expected, id("id", expr(integerLiteral())),
Callback);
}
@@ -72,7 +72,7 @@ TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
expectRewritten(Code, Expected,
id("always-false", conditionalOperator(
hasCondition(boolLiteral(equals(false))),
- hasFalseExpression(id("should-be", expression())))),
+ hasFalseExpression(id("should-be", expr())))),
Callback);
}
@@ -82,8 +82,8 @@ TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
ReplaceIfStmtWithItsBody Callback("id", true);
expectRewritten(Code, Expected,
id("id", ifStmt(
- hasCondition(implicitCast(hasSourceExpression(
- declarationReference(to(variable(hasName("a"))))))))),
+ hasCondition(implicitCastExpr(hasSourceExpression(
+ declRefExpr(to(varDecl(hasName("a"))))))))),
Callback);
}
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index 8d9695590af0..ff278bfd52d5 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -15,14 +15,14 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index f68be6b4576a..d790ac103514 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -15,12 +15,12 @@
#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,8 +35,10 @@ namespace clang {
class RewriterTestContext {
public:
RewriterTestContext()
- : Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>()),
- DiagnosticPrinter(llvm::outs(), DiagnosticOptions()),
+ : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ &*DiagOpts),
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
Files((FileSystemOptions())),
Sources(Diagnostics, Files),
Rewrite(Sources, Options) {
@@ -109,6 +111,7 @@ class RewriterTestContext {
return Files.getBufferForFile(Path, NULL)->getBuffer();
}
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diagnostics;
TextDiagnosticPrinter DiagnosticPrinter;
FileManager Files;
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index d439d81d89ef..8333c24a6880 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -6,14 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines a utility class for RecursiveASTVisitor related tests.
-//
+///
+/// \file
+/// \brief Defines utility templates for RecursiveASTVisitor related tests.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TEST_VISITOR_H
#define LLVM_CLANG_TEST_VISITOR_H
+#include <vector>
+
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -29,7 +32,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 by default.
+/// Visits template instantiations (but not implicit code) by default.
template <typename T>
class TestVisitor : public RecursiveASTVisitor<T> {
public:
@@ -37,9 +40,16 @@ public:
virtual ~TestVisitor() { }
+ enum Language { Lang_C, Lang_CXX };
+
/// \brief Runs the current AST visitor over the given code.
- bool runOver(StringRef Code) {
- return tooling::runToolOnCode(CreateTestAction(), 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;
+ }
+ return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
}
bool shouldVisitTemplateInstantiations() const {
@@ -81,63 +91,126 @@ protected:
ASTContext *Context;
};
-
-/// \brief A RecursiveASTVisitor for testing the RecursiveASTVisitor itself.
+/// \brief A RecursiveASTVisitor to check that certain matches are (or are
+/// not) observed during visitation.
///
-/// Allows simple creation of test visitors running matches on only a small
+/// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
+/// and allows simple creation of test visitors running matches on only a small
/// subset of the Visit* methods.
template <typename T, template <typename> class Visitor = TestVisitor>
class ExpectedLocationVisitor : public Visitor<T> {
public:
- ExpectedLocationVisitor()
- : ExpectedLine(0), ExpectedColumn(0), Found(false) {}
-
- virtual ~ExpectedLocationVisitor() {
- EXPECT_TRUE(Found)
- << "Expected \"" << ExpectedMatch << "\" at " << ExpectedLine
- << ":" << ExpectedColumn << PartialMatches;
+ /// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'.
+ ///
+ /// Any number of matches can be disallowed.
+ void DisallowMatch(Twine Match, unsigned Line, unsigned Column) {
+ DisallowedMatches.push_back(MatchCandidate(Match, Line, Column));
}
/// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
+ ///
+ /// Any number of expected matches can be set by calling this repeatedly.
+ /// Each is expected to be matched exactly once.
void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
- ExpectedMatch = Match.str();
- ExpectedLine = Line;
- ExpectedColumn = Column;
+ ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+ }
+
+ /// \brief Checks that all expected matches have been found.
+ virtual ~ExpectedLocationVisitor() {
+ for (typename std::vector<ExpectedMatch>::const_iterator
+ It = ExpectedMatches.begin(), End = ExpectedMatches.end();
+ It != End; ++It) {
+ It->ExpectFound();
+ }
}
protected:
- /// \brief Convenience method to simplify writing test visitors.
- ///
- /// Sets 'Found' to true if 'Name' and 'Location' match the expected
- /// values. If only a partial match is found, record the information
- /// to produce nice error output when a test fails.
+ /// \brief Checks an actual match against expected and disallowed matches.
///
/// Implementations are required to call this with appropriate values
/// for 'Name' during visitation.
void Match(StringRef Name, SourceLocation Location) {
- FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
- if (Name == ExpectedMatch &&
- FullLocation.isValid() &&
- FullLocation.getSpellingLineNumber() == ExpectedLine &&
- FullLocation.getSpellingColumnNumber() == ExpectedColumn) {
- EXPECT_TRUE(!Found);
- Found = true;
- } else if (Name == ExpectedMatch ||
- (FullLocation.isValid() &&
- FullLocation.getSpellingLineNumber() == ExpectedLine &&
- FullLocation.getSpellingColumnNumber() == ExpectedColumn)) {
- // If we did not match, record information about partial matches.
- llvm::raw_string_ostream Stream(PartialMatches);
- Stream << ", partial match: \"" << Name << "\" at ";
- Location.print(Stream, this->Context->getSourceManager());
+ const FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
+
+ for (typename std::vector<MatchCandidate>::const_iterator
+ It = DisallowedMatches.begin(), End = DisallowedMatches.end();
+ It != End; ++It) {
+ EXPECT_FALSE(It->Matches(Name, FullLocation))
+ << "Matched disallowed " << *It;
+ }
+
+ for (typename std::vector<ExpectedMatch>::iterator
+ It = ExpectedMatches.begin(), End = ExpectedMatches.end();
+ It != End; ++It) {
+ It->UpdateFor(Name, FullLocation, this->Context->getSourceManager());
}
}
- std::string ExpectedMatch;
- unsigned ExpectedLine;
- unsigned ExpectedColumn;
- std::string PartialMatches;
- bool Found;
+ private:
+ struct MatchCandidate {
+ std::string ExpectedName;
+ unsigned LineNumber;
+ unsigned ColumnNumber;
+
+ MatchCandidate(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
+ : ExpectedName(Name.str()), LineNumber(LineNumber),
+ ColumnNumber(ColumnNumber) {
+ }
+
+ bool Matches(StringRef Name, FullSourceLoc const &Location) const {
+ return MatchesName(Name) && MatchesLocation(Location);
+ }
+
+ bool PartiallyMatches(StringRef Name, FullSourceLoc const &Location) const {
+ return MatchesName(Name) || MatchesLocation(Location);
+ }
+
+ bool MatchesName(StringRef Name) const {
+ return Name == ExpectedName;
+ }
+
+ bool MatchesLocation(FullSourceLoc const &Location) const {
+ return Location.isValid() &&
+ Location.getSpellingLineNumber() == LineNumber &&
+ Location.getSpellingColumnNumber() == ColumnNumber;
+ }
+
+ friend std::ostream &operator<<(std::ostream &Stream,
+ MatchCandidate const &Match) {
+ return Stream << Match.ExpectedName
+ << " at " << Match.LineNumber << ":" << Match.ColumnNumber;
+ }
+ };
+
+ struct ExpectedMatch {
+ ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
+ : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+
+ void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
+ if (Candidate.Matches(Name, Location)) {
+ EXPECT_TRUE(!Found);
+ Found = true;
+ } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+ llvm::raw_string_ostream Stream(PartialMatches);
+ Stream << ", partial match: \"" << Name << "\" at ";
+ Location.print(Stream, SM);
+ }
+ }
+
+ void ExpectFound() const {
+ EXPECT_TRUE(Found)
+ << "Expected \"" << Candidate.ExpectedName
+ << "\" at " << Candidate.LineNumber
+ << ":" << Candidate.ColumnNumber << PartialMatches;
+ }
+
+ MatchCandidate Candidate;
+ std::string PartialMatches;
+ bool Found;
+ };
+
+ std::vector<MatchCandidate> DisallowedMatches;
+ std::vector<ExpectedMatch> ExpectedMatches;
};
}
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index fb3af2678c5f..d40c613dd059 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -130,5 +130,37 @@ TEST(ToolInvocation, TestMapVirtualFile) {
EXPECT_TRUE(Invocation.run());
}
+struct VerifyEndCallback : public EndOfSourceFileCallback {
+ VerifyEndCallback() : Called(0), Matched(false) {}
+ virtual void run() {
+ ++Called;
+ }
+ ASTConsumer *newASTConsumer() {
+ return new FindTopLevelDeclConsumer(&Matched);
+ }
+ unsigned Called;
+ bool Matched;
+};
+
+#if !defined(_WIN32)
+TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
+ VerifyEndCallback EndCallback;
+
+ 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() {}");
+
+ Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
+
+ EXPECT_TRUE(EndCallback.Matched);
+ EXPECT_EQ(2u, EndCallback.Called);
+}
+#endif
+
} // end namespace tooling
} // end namespace clang
diff --git a/utils/ClangDataFormat.py b/utils/ClangDataFormat.py
new file mode 100644
index 000000000000..ec44d2a31b0f
--- /dev/null
+++ b/utils/ClangDataFormat.py
@@ -0,0 +1,113 @@
+"""lldb data formatters for clang classes.
+
+Usage
+--
+import this file in your ~/.lldbinit by adding this line:
+
+command script import /path/to/ClangDataFormat.py
+
+After that, instead of getting this:
+
+(lldb) p Tok.Loc
+(clang::SourceLocation) $0 = {
+ (unsigned int) ID = 123582
+}
+
+you'll get:
+
+(lldb) p Tok.Loc
+(clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file)
+"""
+
+import lldb
+
+def __lldb_init_module(debugger, internal_dict):
+ debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
+
+def SourceLocation_summary(srcloc, internal_dict):
+ return SourceLocation(srcloc).summary()
+
+class SourceLocation(object):
+ def __init__(self, srcloc):
+ self.srcloc = srcloc
+
+ def offset(self):
+ return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
+
+ def isMacro(self):
+ return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
+
+ def getPrint(self, srcmgr_path):
+ print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
+ return print_str.GetSummary()
+
+ def summary(self):
+ desc = "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
+ srcmgr_path = findObjectExpressionPath("clang::SourceManager", lldb.frame)
+ if srcmgr_path:
+ desc = self.getPrint(srcmgr_path) + " " + desc
+ return desc
+
+# Key is a (function address, type name) tuple, value is the expression path for
+# an object with such a type name from inside that function.
+FramePathMapCache = {}
+
+def findObjectExpressionPath(typename, frame):
+ func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
+ key = (func_addr, typename)
+ try:
+ return FramePathMapCache[key]
+ except KeyError:
+ #print "CACHE MISS"
+ path = None
+ obj = findObject(typename, frame)
+ if obj:
+ path = getExpressionPath(obj)
+ FramePathMapCache[key] = path
+ return path
+
+def findObject(typename, frame):
+ def getTypename(value):
+ # FIXME: lldb should provide something like getBaseType
+ ty = value.GetType()
+ if ty.IsPointerType() or ty.IsReferenceType():
+ return ty.GetPointeeType().GetName()
+ return ty.GetName()
+
+ def searchForType(value, searched):
+ tyname = getTypename(value)
+ #print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
+ if tyname == typename:
+ return value
+ ty = value.GetType()
+ if not (ty.IsPointerType() or
+ ty.IsReferenceType() or
+ # FIXME: lldb should provide something like getCanonicalType
+ tyname.startswith("llvm::IntrusiveRefCntPtr<") or
+ tyname.startswith("llvm::OwningPtr<")):
+ return None
+ # FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
+ # and not the canonical one unfortunately.
+ if tyname in searched:
+ return None
+ searched.add(tyname)
+ for i in range(value.GetNumChildren()):
+ child = value.GetChildAtIndex(i, 0, False)
+ found = searchForType(child, searched)
+ if found:
+ return found
+
+ searched = set()
+ value_list = frame.GetVariables(True, True, True, True)
+ for val in value_list:
+ found = searchForType(val, searched)
+ if found:
+ return found if not found.TypeIsPointerType() else found.Dereference()
+
+def getValueFromExpression(val, expr):
+ return lldb.frame.EvaluateExpression(getExpressionPath(val) + expr)
+
+def getExpressionPath(val):
+ stream = lldb.SBStream()
+ val.GetExpressionPath(stream)
+ return stream.GetData()
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 0d879214d4a2..534ac9af7760 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,10 +1,10 @@
-set(LLVM_REQUIRES_EH 1)
-set(LLVM_REQUIRES_RTTI 1)
set(LLVM_LINK_COMPONENTS Support)
add_tablegen(clang-tblgen CLANG
ClangASTNodesEmitter.cpp
ClangAttrEmitter.cpp
+ ClangCommentCommandInfoEmitter.cpp
+ ClangCommentHTMLTagsEmitter.cpp
ClangDiagnosticsEmitter.cpp
ClangSACheckersEmitter.cpp
NeonEmitter.cpp
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index ef1ad3e1d2d9..521f6046cfa2 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -33,7 +33,7 @@ getValueAsListOfStrings(Record &R, StringRef FieldName) {
i != e;
++i) {
assert(*i && "Got a null element in a ListInit");
- if (StringInit *S = dynamic_cast<StringInit *>(*i))
+ if (StringInit *S = dyn_cast<StringInit>(*i))
Strings.push_back(S->getValue());
else
assert(false && "Got a non-string, non-code element in a ListInit");
@@ -743,8 +743,6 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << " static bool classof(const Attr *A) { return A->getKind() == "
<< "attr::" << R.getName() << "; }\n";
- OS << " static bool classof(const " << R.getName()
- << "Attr *) { return true; }\n";
bool LateParsed = R.getValueAsBit("LateParsed");
OS << " virtual bool isLateParsed() const { return "
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
new file mode 100644
index 000000000000..36fbcd40b2f4
--- /dev/null
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -0,0 +1,72 @@
+//===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits command lists and efficient matchers command
+// names that are used in documentation comments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "namespace {\n"
+ "const CommandInfo Commands[] = {\n";
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
+ for (size_t i = 0, e = Tags.size(); i != e; ++i) {
+ Record &Tag = *Tags[i];
+ OS << " { "
+ << "\"" << Tag.getValueAsString("Name") << "\", "
+ << "\"" << Tag.getValueAsString("EndCommandName") << "\", "
+ << i << ", "
+ << Tag.getValueAsInt("NumArgs") << ", "
+ << Tag.getValueAsBit("IsInlineCommand") << ", "
+ << Tag.getValueAsBit("IsBlockCommand") << ", "
+ << Tag.getValueAsBit("IsBriefCommand") << ", "
+ << Tag.getValueAsBit("IsReturnsCommand") << ", "
+ << Tag.getValueAsBit("IsParamCommand") << ", "
+ << Tag.getValueAsBit("IsTParamCommand") << ", "
+ << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
+ << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
+ << Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
+ << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
+ << Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
+ << Tag.getValueAsBit("IsDeclarationCommand") << ", "
+ << /* IsUnknownCommand = */ "0"
+ << " }";
+ if (i + 1 != e)
+ OS << ",";
+ OS << "\n";
+ }
+ OS << "};\n"
+ "} // unnamed namespace\n\n";
+
+ std::vector<StringMatcher::StringPair> Matches;
+ for (size_t i = 0, e = Tags.size(); i != e; ++i) {
+ Record &Tag = *Tags[i];
+ std::string Name = Tag.getValueAsString("Name");
+ std::string Return;
+ raw_string_ostream(Return) << "return &Commands[" << i << "];";
+ Matches.push_back(StringMatcher::StringPair(Name, Return));
+ }
+
+ OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n"
+ << " StringRef Name) {\n";
+ StringMatcher("Name", Matches, OS).Emit();
+ OS << " return NULL;\n"
+ << "}\n\n";
+}
+} // end namespace clang
+
diff --git a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
new file mode 100644
index 000000000000..0ae23b293e65
--- /dev/null
+++ b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
@@ -0,0 +1,69 @@
+//===--- ClangCommentHTMLTagsEmitter.cpp - Generate HTML tag list for Clang -=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits efficient matchers for HTML tags that are used
+// in documentation comments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
+ std::vector<StringMatcher::StringPair> Matches;
+ for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I) {
+ Record &Tag = **I;
+ std::string Spelling = Tag.getValueAsString("Spelling");
+ Matches.push_back(StringMatcher::StringPair(Spelling, "return true;"));
+ }
+
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "bool isHTMLTagName(StringRef Name) {\n";
+ StringMatcher("Name", Matches, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+}
+
+void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
+ raw_ostream &OS) {
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
+ std::vector<StringMatcher::StringPair> MatchesEndTagOptional;
+ std::vector<StringMatcher::StringPair> MatchesEndTagForbidden;
+ for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I) {
+ Record &Tag = **I;
+ std::string Spelling = Tag.getValueAsString("Spelling");
+ StringMatcher::StringPair Match(Spelling, "return true;");
+ if (Tag.getValueAsBit("EndTagOptional"))
+ MatchesEndTagOptional.push_back(Match);
+ if (Tag.getValueAsBit("EndTagForbidden"))
+ MatchesEndTagForbidden.push_back(Match);
+ }
+
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "bool isHTMLEndTagOptional(StringRef Name) {\n";
+ StringMatcher("Name", MatchesEndTagOptional, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+
+ OS << "bool isHTMLEndTagForbidden(StringRef Name) {\n";
+ StringMatcher("Name", MatchesEndTagForbidden, OS).Emit();
+ OS << " return false;\n"
+ << "}\n\n";
+}
+} // end namespace clang
+
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 8615d2db8cda..b1472a87cc10 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
@@ -75,7 +76,7 @@ getCategoryFromDiagGroup(const Record *Group,
static std::string getDiagnosticCategory(const Record *R,
DiagGroupParentMap &DiagGroupParents) {
// If the diagnostic is in a group, and that group has a category, use it.
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
// Check the diagnostic's diag group for a category.
std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
DiagGroupParents);
@@ -136,7 +137,7 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
std::map<std::string, GroupInfo> &DiagsInGroup) {
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record *R = Diags[i];
- DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
+ DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
if (DI == 0) continue;
assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
"Note can't be in a DiagGroup");
@@ -280,7 +281,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
Record *R = Diags[i];
if (isExtension(R) && isOffByDefault(R)) {
DiagsSet.insert(R);
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
markGroup(GroupRec);
@@ -299,7 +300,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
// Check if the group is implicitly in -Wpedantic. If so,
// the diagnostic should not be directly included in the -Wpedantic
// diagnostic group.
- if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
if (groupInPedantic(Group->getDef()))
continue;
@@ -391,11 +392,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
// Check if this is an error that is accidentally in a warning
// group.
if (isError(R)) {
- if (DefInit *Group = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
const std::string &GroupName = GroupRec->getValueAsString("GroupName");
- throw "Error " + R.getName() + " cannot be in a warning group [" +
- GroupName + "]";
+ PrintFatalError(R.getLoc(), "Error " + R.getName() +
+ " cannot be in a warning group [" + GroupName + "]");
}
}
@@ -413,7 +414,7 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
// Warning associated with the diagnostic. This is stored as an index into
// the alphabetically sorted warning table.
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
std::map<std::string, GroupInfo>::iterator I =
DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
assert(I != DiagsInGroup.end());
@@ -556,7 +557,8 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789!@#$%^*-+=:?")!=std::string::npos)
- throw "Invalid character in diagnostic group '" + I->first + "'";
+ PrintFatalError("Invalid character in diagnostic group '" +
+ I->first + "'");
OS.write_escaped(I->first) << "\","
<< std::string(MaxLen-I->first.size()+1, ' ');
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
index 5a0db501dff9..8c74064a6368 100644
--- a/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseSet.h"
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <map>
@@ -28,7 +29,7 @@ static bool isHidden(const Record &R) {
if (R.getValueAsBit("Hidden"))
return true;
// Not declared as hidden, check the parent package if it is hidden.
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
return isHidden(*DI->getDef());
return false;
@@ -42,7 +43,7 @@ static std::string getPackageFullName(const Record *R);
static std::string getParentPackageFullName(const Record *R) {
std::string name;
- if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
name = getPackageFullName(DI->getDef());
return name;
}
@@ -63,8 +64,7 @@ static std::string getCheckerFullName(const Record *R) {
}
static std::string getStringValue(const Record &R, StringRef field) {
- if (StringInit *
- SI = dynamic_cast<StringInit*>(R.getValueInit(field)))
+ if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
return SI->getValue();
return std::string();
}
@@ -131,10 +131,11 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
Record *R = checkers[i];
Record *package = 0;
if (DefInit *
- DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
+ DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
package = DI->getDef();
if (!isCheckerNamed(R) && !package)
- throw "Checker '" + R->getName() + "' is neither named, nor in a package!";
+ PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
+ "' is neither named, nor in a package!");
if (isCheckerNamed(R)) {
// Create a pseudo-group to hold this checker.
@@ -151,20 +152,20 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
// Insert the checker and its parent packages into the subgroups set of
// the corresponding parent package.
while (DefInit *DI
- = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
+ = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
Record *parentPackage = DI->getDef();
recordGroupMap[parentPackage]->SubGroups.insert(currR);
currR = parentPackage;
}
// Insert the checker into the set of its group.
- if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
recordGroupMap[DI->getDef()]->Checkers.insert(R);
}
// If a package is in group, add all its checkers and its sub-packages
// checkers into the group.
for (unsigned i = 0, e = packages.size(); i != e; ++i)
- if (DefInit *DI = dynamic_cast<DefInit*>(packages[i]->getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
typedef std::map<std::string, const Record *> SortedRecords;
@@ -205,7 +206,7 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "PACKAGE(" << "\"";
OS.write_escaped(getPackageFullName(&R)) << "\", ";
// Group index
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << groupToSortIndex[DI->getDef()] << ", ";
else
OS << "-1, ";
@@ -233,7 +234,7 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "\"";
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
// Group index
- if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << groupToSortIndex[DI->getDef()] << ", ";
else
OS << "-1, ";
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
index 9790efc061ef..1fde852ebc47 100644
--- a/utils/TableGen/Makefile
+++ b/utils/TableGen/Makefile
@@ -10,8 +10,6 @@
LEVEL = ../../../..
TOOLNAME = clang-tblgen
USEDLIBS = LLVMTableGen.a LLVMSupport.a
-REQUIRES_EH := 1
-REQUIRES_RTTI := 1
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 68373063baae..d453ededd5e9 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -245,7 +245,7 @@ static void ParseTypes(Record *r, std::string &s,
case 'f':
break;
default:
- throw TGError(r->getLoc(),
+ PrintFatalError(r->getLoc(),
"Unexpected letter: " + std::string(data + len, 1));
}
TV.push_back(StringRef(data, len + 1));
@@ -266,7 +266,8 @@ static char Widen(const char t) {
return 'l';
case 'h':
return 'f';
- default: throw "unhandled type in widen!";
+ default:
+ PrintFatalError("unhandled type in widen!");
}
}
@@ -282,7 +283,8 @@ static char Narrow(const char t) {
return 'i';
case 'f':
return 'h';
- default: throw "unhandled type in narrow!";
+ default:
+ PrintFatalError("unhandled type in narrow!");
}
}
@@ -453,7 +455,7 @@ static std::string TypeString(const char mod, StringRef typestr) {
s += quad ? "x4" : "x2";
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (mod == '2')
@@ -635,7 +637,7 @@ static std::string MangleName(const std::string &name, StringRef typestr,
}
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (ck == ClassB)
s += "_v";
@@ -773,7 +775,7 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) {
case 'h': nElts = 4; break;
case 'f': nElts = 2; break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
if (quad) nElts <<= 1;
return nElts;
@@ -1004,7 +1006,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
break;
}
default:
- throw "unknown OpKind!";
+ PrintFatalError("unknown OpKind!");
}
return s;
}
@@ -1049,7 +1051,7 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
ET = NeonTypeFlags::Float32;
break;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
return Flags.getFlags();
@@ -1381,7 +1383,7 @@ void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
if (R->getSuperClasses().size() >= 2)
classKind = ClassMap[R->getSuperClasses()[1]];
if (classKind == ClassNone && kind == OpNone)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
if (kind == OpReinterpret) {
@@ -1423,7 +1425,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) {
case 'l':
return (1 << (int)quad) - 1;
default:
- throw "unhandled type!";
+ PrintFatalError("unhandled type!");
}
}
@@ -1456,7 +1458,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
std::string name = R->getValueAsString("Name");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
@@ -1501,7 +1503,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
int si = -1, qi = -1;
uint64_t mask = 0, qmask = 0;
@@ -1600,7 +1602,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
ParseTypes(R, Types, TypeVec);
if (R->getSuperClasses().size() < 2)
- throw TGError(R->getLoc(), "Builtin has no class kind");
+ PrintFatalError(R->getLoc(), "Builtin has no class kind");
ClassKind ck = ClassMap[R->getSuperClasses()[1]];
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
index b0431a9be16b..674c89af9f99 100644
--- a/utils/TableGen/OptParserEmitter.cpp
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -7,9 +7,15 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+#include <map>
+
using namespace llvm;
static int StrCmpOptionName(const char *A, const char *B) {
@@ -32,8 +38,8 @@ static int StrCmpOptionName(const char *A, const char *B) {
}
static int CompareOptionRecords(const void *Av, const void *Bv) {
- const Record *A = *(Record**) Av;
- const Record *B = *(Record**) 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");
@@ -47,16 +53,38 @@ static int CompareOptionRecords(const void *Av, const void *Bv) {
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");
- assert(APrec != BPrec && "Options are equivalent!");
+ 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 (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName")))
+ if (isa<UnsetInit>(R.getValueInit("EnumName")))
return R.getName();
return R.getValueAsString("EnumName");
@@ -86,6 +114,48 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
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";
@@ -98,8 +168,11 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// Start a single option entry.
OS << "OPTION(";
+ // The option prefix;
+ OS << "0";
+
// The option string.
- OS << '"' << R.getValueAsString("Name") << '"';
+ OS << ", \"" << R.getValueAsString("Name") << '"';
// The option identifier name.
OS << ", "<< getOptionName(R);
@@ -109,7 +182,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The containing option group (if any).
OS << ", ";
- if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
@@ -118,7 +191,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
OS << ", INVALID, 0, 0";
// The option help text.
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
@@ -138,6 +211,10 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// 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"));
@@ -149,14 +226,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The containing option group (if any).
OS << ", ";
- if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
+ 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 = dynamic_cast<DefInit*>(R.getValueInit("Alias")))
+ if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
@@ -170,7 +247,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
for (unsigned i = 0, e = LI->size(); i != e; ++i) {
if (i)
OS << " | ";
- OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName();
+ OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
}
}
@@ -178,7 +255,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
OS << ", " << R.getValueAsInt("NumArgs");
// The option help text.
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
+ if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
@@ -187,7 +264,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
// The option meta-variable name.
OS << ", ";
- if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName")))
+ if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
write_cstring(OS, R.getValueAsString("MetaVarName"));
else
OS << "0";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index d3408ed20f4d..41471a484c69 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -19,7 +19,6 @@
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Main.h"
#include "llvm/TableGen/Record.h"
-#include "llvm/TableGen/TableGenAction.h"
using namespace llvm;
using namespace clang;
@@ -42,6 +41,9 @@ enum ActionType {
GenClangDeclNodes,
GenClangStmtNodes,
GenClangSACheckers,
+ GenClangCommentHTMLTags,
+ GenClangCommentHTMLTagsProperties,
+ GenClangCommentCommandInfo,
GenOptParserDefs, GenOptParserImpl,
GenArmNeon,
GenArmNeonSema,
@@ -95,6 +97,18 @@ namespace {
"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(GenClangCommentCommandInfo,
+ "gen-clang-comment-command-info",
+ "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",
@@ -108,82 +122,88 @@ namespace {
cl::desc("Only use warnings from specified component"),
cl::value_desc("component"), cl::Hidden);
-class ClangTableGenAction : public TableGenAction {
-public:
- bool operator()(raw_ostream &OS, RecordKeeper &Records) {
- switch (Action) {
- case GenClangAttrClasses:
- EmitClangAttrClass(Records, OS);
- break;
- case GenClangAttrImpl:
- EmitClangAttrImpl(Records, OS);
- break;
- case GenClangAttrList:
- EmitClangAttrList(Records, OS);
- break;
- case GenClangAttrPCHRead:
- EmitClangAttrPCHRead(Records, OS);
- break;
- case GenClangAttrPCHWrite:
- EmitClangAttrPCHWrite(Records, OS);
- break;
- case GenClangAttrSpellingList:
- EmitClangAttrSpellingList(Records, OS);
- break;
- case GenClangAttrLateParsedList:
- EmitClangAttrLateParsedList(Records, OS);
- break;
- case GenClangAttrTemplateInstantiate:
- EmitClangAttrTemplateInstantiate(Records, OS);
- break;
- case GenClangAttrParsedAttrList:
- EmitClangAttrParsedAttrList(Records, OS);
- break;
- case GenClangAttrParsedAttrKinds:
- EmitClangAttrParsedAttrKinds(Records, OS);
- break;
- case GenClangDiagsDefs:
- EmitClangDiagsDefs(Records, OS, ClangComponent);
- break;
- case GenClangDiagGroups:
- EmitClangDiagGroups(Records, OS);
- break;
- case GenClangDiagsIndexName:
- EmitClangDiagsIndexName(Records, OS);
- break;
- case GenClangCommentNodes:
- EmitClangASTNodes(Records, OS, "Comment", "");
- break;
- case GenClangDeclNodes:
- EmitClangASTNodes(Records, OS, "Decl", "Decl");
- EmitClangDeclContext(Records, OS);
- break;
- case GenClangStmtNodes:
- EmitClangASTNodes(Records, OS, "Stmt", "");
- break;
- case GenClangSACheckers:
- EmitClangSACheckers(Records, OS);
- break;
- case GenOptParserDefs:
- EmitOptParser(Records, OS, true);
- break;
- case GenOptParserImpl:
- EmitOptParser(Records, OS, false);
- break;
- case GenArmNeon:
- EmitNeon(Records, OS);
- break;
- case GenArmNeonSema:
- EmitNeonSema(Records, OS);
- break;
- case GenArmNeonTest:
- EmitNeonTest(Records, OS);
- break;
- }
-
- return false;
+bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
+ switch (Action) {
+ case GenClangAttrClasses:
+ EmitClangAttrClass(Records, OS);
+ break;
+ case GenClangAttrImpl:
+ EmitClangAttrImpl(Records, OS);
+ break;
+ case GenClangAttrList:
+ EmitClangAttrList(Records, OS);
+ break;
+ case GenClangAttrPCHRead:
+ EmitClangAttrPCHRead(Records, OS);
+ break;
+ case GenClangAttrPCHWrite:
+ EmitClangAttrPCHWrite(Records, OS);
+ break;
+ case GenClangAttrSpellingList:
+ EmitClangAttrSpellingList(Records, OS);
+ break;
+ case GenClangAttrLateParsedList:
+ EmitClangAttrLateParsedList(Records, OS);
+ break;
+ case GenClangAttrTemplateInstantiate:
+ EmitClangAttrTemplateInstantiate(Records, OS);
+ break;
+ case GenClangAttrParsedAttrList:
+ EmitClangAttrParsedAttrList(Records, OS);
+ break;
+ case GenClangAttrParsedAttrKinds:
+ EmitClangAttrParsedAttrKinds(Records, OS);
+ break;
+ case GenClangDiagsDefs:
+ EmitClangDiagsDefs(Records, OS, ClangComponent);
+ break;
+ case GenClangDiagGroups:
+ EmitClangDiagGroups(Records, OS);
+ break;
+ case GenClangDiagsIndexName:
+ EmitClangDiagsIndexName(Records, OS);
+ break;
+ case GenClangCommentNodes:
+ EmitClangASTNodes(Records, OS, "Comment", "");
+ break;
+ case GenClangDeclNodes:
+ EmitClangASTNodes(Records, OS, "Decl", "Decl");
+ EmitClangDeclContext(Records, OS);
+ break;
+ case GenClangStmtNodes:
+ EmitClangASTNodes(Records, OS, "Stmt", "");
+ break;
+ case GenClangSACheckers:
+ EmitClangSACheckers(Records, OS);
+ break;
+ case GenClangCommentHTMLTags:
+ EmitClangCommentHTMLTags(Records, OS);
+ break;
+ case GenClangCommentHTMLTagsProperties:
+ EmitClangCommentHTMLTagsProperties(Records, OS);
+ break;
+ case GenClangCommentCommandInfo:
+ EmitClangCommentCommandInfo(Records, OS);
+ break;
+ case GenOptParserDefs:
+ EmitOptParser(Records, OS, true);
+ break;
+ case GenOptParserImpl:
+ EmitOptParser(Records, OS, false);
+ break;
+ case GenArmNeon:
+ EmitNeon(Records, OS);
+ break;
+ case GenArmNeonSema:
+ EmitNeonSema(Records, OS);
+ break;
+ case GenArmNeonTest:
+ EmitNeonTest(Records, OS);
+ break;
}
-};
+
+ return false;
+}
}
int main(int argc, char **argv) {
@@ -191,6 +211,5 @@ int main(int argc, char **argv) {
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
- ClangTableGenAction Action;
- return TableGenMain(argv[0], Action);
+ return TableGenMain(argv[0], &ClangTableGenMain);
}
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 779de7c734b0..838fc84dcae3 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -47,6 +47,11 @@ void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS);
void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records, raw_ostream &OS);
+
+void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS);
+
void EmitNeon(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS);
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py
index c8f05cbcf474..3ca9b2bbe7eb 100755
--- a/utils/analyzer/CmpRuns.py
+++ b/utils/analyzer/CmpRuns.py
@@ -17,11 +17,8 @@ Usage:
# Load the results of both runs, to obtain lists of the corresponding
# AnalysisDiagnostic objects.
#
- # root - the name of the root directory, which will be disregarded when
- # determining the source file name
- #
- resultsA = loadResults(dirA, opts, root, deleteEmpty)
- resultsB = loadResults(dirB, opts, root, deleteEmpty)
+ resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty)
+ resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty)
# Generate a relation from diagnostics in run A to diagnostics in run B
# to obtain a list of triples (a, b, confidence).
@@ -31,8 +28,18 @@ Usage:
import os
import plistlib
+import CmpRuns
+
+# Information about analysis run:
+# path - the analysis output directory
+# root - the name of the root directory, which will be disregarded when
+# determining the source file name
+class SingleRunInfo:
+ def __init__(self, path, root="", verboseLog=None):
+ self.path = path
+ self.root = root
+ self.verboseLog = verboseLog
-#
class AnalysisDiagnostic:
def __init__(self, data, report, htmlReport):
self._data = data
@@ -41,7 +48,11 @@ class AnalysisDiagnostic:
self._htmlReport = htmlReport
def getFileName(self):
- return self._report.run.getSourceName(self._report.files[self._loc['file']])
+ root = self._report.run.root
+ fileName = self._report.files[self._loc['file']]
+ if fileName.startswith(root) :
+ return fileName[len(root):]
+ return fileName
def getLine(self):
return self._loc['line']
@@ -56,12 +67,12 @@ class AnalysisDiagnostic:
return self._data['description']
def getIssueIdentifier(self) :
- id = ''
+ id = self.getFileName() + "+"
if 'issue_context' in self._data :
- id += self._data['issue_context'] + ":"
+ id += self._data['issue_context'] + "+"
if 'issue_hash' in self._data :
- id += str(self._data['issue_hash']) + ":"
- return id + ":" + self.getFileName()
+ id += str(self._data['issue_hash'])
+ return id
def getReport(self):
if self._htmlReport is None:
@@ -72,6 +83,11 @@ class AnalysisDiagnostic:
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
self.getColumn(), self.getCategory(),
self.getDescription())
+
+ # Note, the data format is not an API and may change from one analyzer
+ # version to another.
+ def getRawData(self):
+ return self._data
class multidict:
def __init__(self, elts=()):
@@ -96,8 +112,6 @@ class multidict:
return len(self.data)
def get(self, key, default=None):
return self.data.get(key, default)
-
-#
class CmpOptions:
def __init__(self, verboseLog=None, rootA="", rootB=""):
@@ -106,29 +120,36 @@ class CmpOptions:
self.verboseLog = verboseLog
class AnalysisReport:
- def __init__(self, run, files):
+ def __init__(self, run, files, clang_vers):
self.run = run
+ self.clang_version = clang_vers
self.files = files
+ self.diagnostics = []
class AnalysisRun:
- def __init__(self, path, root, opts):
- self.path = path
- self.root = root
+ def __init__(self, info):
+ self.path = info.path
+ self.root = info.root
+ self.info = info
self.reports = []
+ # Cumulative list of all diagnostics from all the reports.
self.diagnostics = []
- self.opts = opts
- def getSourceName(self, path):
- if path.startswith(self.root):
- return path[len(self.root):]
- return path
+# Backward compatibility API.
def loadResults(path, opts, root = "", deleteEmpty=True):
- run = AnalysisRun(path, root, opts)
+ return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
+ deleteEmpty)
+
+# Load results of the analyzes from a given output folder.
+# - info is the SingleRunInfo object
+# - deleteEmpty specifies if the empty plist files should be deleted
+def loadResultsFromSingleRun(info, deleteEmpty=True):
+ path = info.path
+ run = AnalysisRun(info)
for f in os.listdir(path):
- if (not f.startswith('report') or
- not f.endswith('plist')):
+ if (not f.endswith('plist')):
continue
p = os.path.join(path, f)
@@ -146,20 +167,23 @@ def loadResults(path, opts, root = "", deleteEmpty=True):
for d in data['diagnostics']:
# FIXME: Why is this named files, when does it have multiple
# files?
- # TODO: Add the assert back in after we fix the
- # plist-html output.
- # assert len(d['HTMLDiagnostics_files']) == 1
+ assert len(d['HTMLDiagnostics_files']) == 1
htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
else:
htmlFiles = [None] * len(data['diagnostics'])
-
- report = AnalysisReport(run, data.pop('files'))
+
+ clang_version = ''
+ if 'clang_version' in data:
+ clang_version = data.pop('clang_version')
+
+ report = AnalysisReport(run, data.pop('files'), clang_version)
diagnostics = [AnalysisDiagnostic(d, report, h)
for d,h in zip(data.pop('diagnostics'),
htmlFiles)]
assert not data
-
+
+ report.diagnostics.extend(diagnostics)
run.reports.append(report)
run.diagnostics.extend(diagnostics)
@@ -193,12 +217,12 @@ def compareResults(A, B):
b = eltsB.pop()
if (a.getIssueIdentifier() == b.getIssueIdentifier()) :
res.append((a, b, 0))
- elif a._data > b._data:
- neqA.append(a)
+ elif a.getIssueIdentifier() > b.getIssueIdentifier():
eltsB.append(b)
+ neqA.append(a)
else:
- neqB.append(b)
eltsA.append(a)
+ neqB.append(b)
neqA.extend(eltsA)
neqB.extend(eltsB)
diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py
index 2d32533f6bb0..64ff4ff65683 100644
--- a/utils/analyzer/SATestAdd.py
+++ b/utils/analyzer/SATestAdd.py
@@ -33,7 +33,7 @@ def isExistingProject(PMapFile, projectID) :
# Params:
# Dir is the directory where the sources are.
# ID is a short string used to identify a project.
-def addNewProject(ID, IsScanBuild) :
+def addNewProject(ID, BuildMode) :
CurDir = os.path.abspath(os.curdir)
Dir = SATestBuild.getProjectDir(ID)
if not os.path.exists(Dir):
@@ -41,7 +41,7 @@ def addNewProject(ID, IsScanBuild) :
sys.exit(-1)
# Build the project.
- SATestBuild.testProject(ID, IsScanBuild, IsReferenceBuild=True, Dir=Dir)
+ SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir)
# Add the project ID to the project map.
ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile)
@@ -57,7 +57,7 @@ def addNewProject(ID, IsScanBuild) :
print >> sys.stdout, "Reference output has been regenerated."
else:
PMapWriter = csv.writer(PMapFile)
- PMapWriter.writerow( (ID, int(IsScanBuild)) );
+ PMapWriter.writerow( (ID, int(BuildMode)) );
print "The project map is updated: ", ProjectMapPath
finally:
PMapFile.close()
@@ -69,12 +69,14 @@ if __name__ == '__main__':
if len(sys.argv) < 2:
print >> sys.stderr, 'Usage: ', sys.argv[0],\
'project_ID <mode>' \
- 'mode - 0 for single file project; 1 for scan_build'
+ 'mode - 0 for single file project; ' \
+ '1 for scan_build; ' \
+ '2 for single file c++11 project'
sys.exit(-1)
- IsScanBuild = 1
+ BuildMode = 1
if (len(sys.argv) >= 3):
- IsScanBuild = int(sys.argv[2])
- assert((IsScanBuild == 0) | (IsScanBuild == 1))
+ BuildMode = int(sys.argv[2])
+ assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2))
- addNewProject(sys.argv[1], IsScanBuild)
+ addNewProject(sys.argv[1], BuildMode)
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index fd4bc8a8eeef..94123582225f 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -42,39 +42,66 @@ import os
import csv
import sys
import glob
+import math
import shutil
import time
import plistlib
from subprocess import check_call, CalledProcessError
-# Project map stores info about all the "registered" projects.
-ProjectMapFile = "projectMap.csv"
-
-# Names of the project specific scripts.
-# The script that needs to be executed before the build can start.
-CleanupScript = "cleanup_run_static_analyzer.sh"
-# This is a file containing commands for scan-build.
-BuildScript = "run_static_analyzer.cmd"
-
-# The log file name.
-LogFolderName = "Logs"
-BuildLogName = "run_static_analyzer.log"
-# Summary file - contains the summary of the failures. Ex: This info can be be
-# displayed when buildbot detects a build failure.
-NumOfFailuresInSummary = 10
-FailuresSummaryFileName = "failures.txt"
-# Summary of the result diffs.
-DiffsSummaryFileName = "diffs.txt"
-
-# The scan-build result directory.
-SBOutputDirName = "ScanBuildResults"
-SBOutputDirReferencePrefix = "Ref"
-
-# The list of checkers used during analyzes.
-# Currently, consists of all the non experimental checkers.
-Checkers="experimental.security.taint,core,deadcode,security,unix,osx"
-
-Verbose = 1
+#------------------------------------------------------------------------------
+# Helper functions.
+#------------------------------------------------------------------------------
+
+def detectCPUs():
+ """
+ Detects the number of CPUs on a system. Cribbed from pp.
+ """
+ # Linux, Unix and MacOS:
+ if hasattr(os, "sysconf"):
+ if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
+ # Linux & Unix:
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(ncpus, int) and ncpus > 0:
+ return ncpus
+ else: # OSX:
+ return int(capture(['sysctl', '-n', 'hw.ncpu']))
+ # Windows:
+ if os.environ.has_key("NUMBER_OF_PROCESSORS"):
+ ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
+ if ncpus > 0:
+ return ncpus
+ return 1 # Default
+
+def which(command, paths = None):
+ """which(command, [paths]) - Look up the given command in the paths string
+ (or the PATH environment variable, if unspecified)."""
+
+ if paths is None:
+ paths = os.environ.get('PATH','')
+
+ # Check for absolute match first.
+ if os.path.exists(command):
+ return command
+
+ # Would be nice if Python had a lib function for this.
+ if not paths:
+ paths = os.defpath
+
+ # Get suffixes to search.
+ # On Cygwin, 'PATHEXT' may exist but it should not be used.
+ if os.pathsep == ';':
+ pathext = os.environ.get('PATHEXT', '').split(';')
+ else:
+ pathext = ['']
+
+ # Search the paths...
+ for path in paths.split(os.pathsep):
+ for ext in pathext:
+ p = os.path.join(path, command + ext)
+ if os.path.exists(p):
+ return p
+
+ return None
# Make sure we flush the output after every print statement.
class flushfile(object):
@@ -104,6 +131,52 @@ def getSBOutputDirName(IsReferenceBuild) :
else :
return SBOutputDirName
+#------------------------------------------------------------------------------
+# Configuration setup.
+#------------------------------------------------------------------------------
+
+# Find Clang for static analysis.
+Clang = which("clang", os.environ['PATH'])
+if not Clang:
+ print "Error: cannot find 'clang' in PATH"
+ sys.exit(-1)
+
+# Number of jobs.
+Jobs = math.ceil(detectCPUs() * 0.75)
+
+# Project map stores info about all the "registered" projects.
+ProjectMapFile = "projectMap.csv"
+
+# Names of the project specific scripts.
+# The script that needs to be executed before the build can start.
+CleanupScript = "cleanup_run_static_analyzer.sh"
+# This is a file containing commands for scan-build.
+BuildScript = "run_static_analyzer.cmd"
+
+# The log file name.
+LogFolderName = "Logs"
+BuildLogName = "run_static_analyzer.log"
+# Summary file - contains the summary of the failures. Ex: This info can be be
+# displayed when buildbot detects a build failure.
+NumOfFailuresInSummary = 10
+FailuresSummaryFileName = "failures.txt"
+# Summary of the result diffs.
+DiffsSummaryFileName = "diffs.txt"
+
+# The scan-build result directory.
+SBOutputDirName = "ScanBuildResults"
+SBOutputDirReferencePrefix = "Ref"
+
+# The list of checkers used during analyzes.
+# Currently, consists of all the non experimental checkers.
+Checkers="alpha.unix.SimpleStream,alpha.security.taint,core,deadcode,security,unix,osx"
+
+Verbose = 1
+
+#------------------------------------------------------------------------------
+# Test harness logic.
+#------------------------------------------------------------------------------
+
# Run pre-processing script if any.
def runCleanupScript(Dir, PBuildLogFile):
ScriptPath = os.path.join(Dir, CleanupScript)
@@ -129,13 +202,19 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
BuildScriptPath = os.path.join(Dir, BuildScript)
if not os.path.exists(BuildScriptPath):
print "Error: build script is not defined: %s" % BuildScriptPath
- sys.exit(-1)
- SBOptions = "-plist-html -o " + SBOutputDir + " "
+ sys.exit(-1)
+ SBOptions = "--use-analyzer " + Clang + " "
+ SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
for Command in SBCommandFile:
+ # If using 'make', auto imply a -jX argument
+ # to speed up analysis. xcodebuild will
+ # automatically use the maximum number of cores.
+ if Command.startswith("make "):
+ Command += "-j" + Jobs
SBCommand = SBPrefix + Command
if Verbose == 1:
print " Executing: %s" % (SBCommand,)
@@ -160,17 +239,20 @@ def isValidSingleInputFile(FileName):
(Ext == ".m") | (Ext == "")) :
return True
return False
-
+
# Run analysis on a set of preprocessed files.
-def runAnalyzePreprocessed(Dir, SBOutputDir):
+def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
if os.path.exists(os.path.join(Dir, BuildScript)):
print "Error: The preprocessed files project should not contain %s" % \
BuildScript
raise Exception()
- CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w "
+ CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+ if (Mode == 2) :
+ CmdPrefix += "-std=c++11 "
+
PlistPath = os.path.join(Dir, SBOutputDir, "date")
FailPath = os.path.join(PlistPath, "failures");
os.makedirs(FailPath);
@@ -208,7 +290,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir):
if Failed == False:
os.remove(LogFile.name);
-def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
+def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time()
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
@@ -238,10 +320,10 @@ def buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild):
try:
runCleanupScript(Dir, PBuildLogFile)
- if IsScanBuild:
+ if (ProjectBuildMode == 1):
runScanBuild(Dir, SBOutputDir, PBuildLogFile)
else:
- runAnalyzePreprocessed(Dir, SBOutputDir)
+ runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
if IsReferenceBuild :
runCleanupScript(Dir, PBuildLogFile)
@@ -395,7 +477,7 @@ def updateSVN(Mode, ProjectsMap):
print "Error: SVN update failed."
sys.exit(-1)
-def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
+def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None):
print " \n\n--- Building project %s" % (ID,)
TBegin = time.time()
@@ -409,7 +491,7 @@ def testProject(ID, IsScanBuild, IsReferenceBuild=False, Dir=None):
RelOutputDir = getSBOutputDirName(IsReferenceBuild)
SBOutputDir = os.path.join(Dir, RelOutputDir)
- buildProject(Dir, SBOutputDir, IsScanBuild, IsReferenceBuild)
+ buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
checkBuild(SBOutputDir)
@@ -427,8 +509,9 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False):
if (len(I) != 2) :
print "Error: Rows in the ProjectMapFile should have 3 entries."
raise Exception()
- if (not ((I[1] == "1") | (I[1] == "0"))):
- print "Error: Second entry in the ProjectMapFile should be 0 or 1."
+ if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
+ print "Error: Second entry in the ProjectMapFile should be 0" \
+ " (single file), 1 (project), or 2(single file c++11)."
raise Exception()
# When we are regenerating the reference results, we might need to
diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py
index a6731bb8f243..4ef1ceb4cec5 100644
--- a/utils/analyzer/SumTimerInfo.py
+++ b/utils/analyzer/SumTimerInfo.py
@@ -28,6 +28,8 @@ if __name__ == '__main__':
ReachableBlocks = 0
ReachedMaxSteps = 0
NumSteps = 0
+ NumInlinedCallSites = 0
+ NumBifurcatedCallSites = 0
MaxCFGSize = 0
Mode = 1
for line in f:
@@ -39,25 +41,31 @@ if __name__ == '__main__':
Count = Count + 1
if (float(s[6]) > MaxTime) :
MaxTime = float(s[6])
- if ((("warning generated." in line) or ("warnings generated." in line)) and Mode == 1) :
+ if ((("warning generated." in line) or ("warnings generated" in line)) and Mode == 1) :
s = line.split()
Warnings = Warnings + int(s[0])
- if (("The # of functions analysed (as top level)." in line) and (Mode == 1)) :
+ if (("The # of functions analysed (as top level)" in line) and (Mode == 1)) :
s = line.split()
FunctionsAnalyzed = FunctionsAnalyzed + int(s[0])
if (("The % of reachable basic blocks" in line) and (Mode == 1)) :
s = line.split()
ReachableBlocks = ReachableBlocks + int(s[0])
- if (("The # of times we reached the max number of steps." in line) and (Mode == 1)) :
+ if (("The # of times we reached the max number of steps" in line) and (Mode == 1)) :
s = line.split()
ReachedMaxSteps = ReachedMaxSteps + int(s[0])
if (("The maximum number of basic blocks in a function" in line) and (Mode == 1)) :
s = line.split()
if (MaxCFGSize < int(s[0])) :
MaxCFGSize = int(s[0])
- if (("The # of steps executed." in line) and (Mode == 1)) :
+ if (("The # of steps executed" in line) and (Mode == 1)) :
s = line.split()
NumSteps = NumSteps + int(s[0])
+ if (("The # of times we inlined a call" in line) and (Mode == 1)) :
+ s = line.split()
+ NumInlinedCallSites = NumInlinedCallSites + int(s[0])
+ if (("The # of times we split the path due to imprecise dynamic dispatch info" in line) and (Mode == 1)) :
+ s = line.split()
+ NumBifurcatedCallSites = NumBifurcatedCallSites + int(s[0])
if ((") Total" in line) and (Mode == 1)) :
s = line.split()
TotalTime = TotalTime + float(s[6])
@@ -69,6 +77,7 @@ if __name__ == '__main__':
print "Reachable Blocks %d" % (ReachableBlocks)
print "Reached Max Steps %d" % (ReachedMaxSteps)
print "Number of Steps %d" % (NumSteps)
+ print "Number of Inlined calls %d (bifurcated %d)" % (NumInlinedCallSites, NumBifurcatedCallSites)
print "MaxTime %f" % (MaxTime)
print "TotalTime %f" % (TotalTime)
print "Max CFG Size %d" % (MaxCFGSize)
diff --git a/utils/analyzer/update_plist_test.pl b/utils/analyzer/update_plist_test.pl
new file mode 100755
index 000000000000..abb74a57c3c1
--- /dev/null
+++ b/utils/analyzer/update_plist_test.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -w
+use strict;
+require File::Temp;
+use File::Temp ();
+
+die "update_plist_test <test file> <plist file>\n" if ($#ARGV < 1);
+my $testFile = shift @ARGV;
+die "error: cannot read file $testFile\n" if (! -r $testFile);
+my $plistFile = shift @ARGV;
+die "error: cannot read file $plistFile\n" if (! -r $plistFile);
+
+# Create a temp file for the new test.
+my $fh = File::Temp->new();
+my $filename = $fh->filename;
+$fh->unlink_on_destroy(1);
+
+# Copy the existing temp file, skipping the FileCheck comments.
+open (IN, $testFile) or die "cannot open $testFile\n";
+while (<IN>) {
+ next if (/^\/\/ CHECK/);
+ print $fh $_;
+}
+close(IN);
+
+# Copy the plist data, and specially format it.
+open (IN, $plistFile) or die "cannot open $plistFile\n";
+my $firstArray = 1;
+my $first = 1;
+while (<IN>) {
+ # Skip everything not indented.
+ next if (/^[^\s]/);
+ # Skip the first array entry, which is for files.
+ if ($firstArray) {
+ if (/<\/array>/) { $firstArray = 0; }
+ next;
+ }
+ # Format the CHECK lines.
+ if ($first) {
+ print $fh "// CHECK: ";
+ $first = 0;
+ }
+ else {
+ print $fh "// CHECK-NEXT: ";
+ }
+ print $fh $_;
+}
+close (IN);
+close ($fh);
+
+`cp $filename $testFile`;
+print "updated $testFile\n";
diff --git a/www/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 3a902a3d36f5..4f8971c5507f 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -125,8 +125,9 @@
<td><b>osx.coreFoundation.CFNumber</b></td><td>Check for proper uses of CFNumberCreate.</td>
</tr>
<tr>
-<td><b>osx.coreFoundation.CFRetainRelease</b></td><td>Check for null arguments to CFRetain/CFRelease.</td>
+<td><b>osx.coreFoundation.CFRetainRelease</b></td><td>Check for null arguments to CFRetain/CFRelease/CFMakeCollectable.</td>
</tr>
+<tr>
<td><b>osx.coreFoundation.containers.OutOfBounds</b></td><td>Checks for index out-of-bounds when using 'CFArray' API.</td>
</tr>
<tr>
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
index fc9adf371ef0..043b53612aea 100644
--- a/www/analyzer/checker_dev_manual.html
+++ b/www/analyzer/checker_dev_manual.html
@@ -82,7 +82,7 @@ for general developer guidelines and information. </p>
the values of all the expressions in the program based on the input symbols
and the path. The execution is path sensitive and every possible path through
the program is explored. The explored execution traces are represented with
- <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ExplodedGraph.html">ExplidedGraph</a> object.
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ExplodedGraph.html">ExplodedGraph</a> object.
Each node of the graph is
<a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ExplodedNode.html">ExplodedNode</a>,
which consists of a <tt>ProgramPoint</tt> and a <tt>ProgramState</tt>.
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index ea75fbabd138..c2fa294d795f 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -63,6 +63,38 @@ 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.checkers {
+ border: 1px #cccccc solid;
+ border-collapse: collapse;
+ margin:0px; margin-top:20px; margin-bottom:20px;
+ text-align:left;
+ table-layout: fixed;
+ width: 100%;
+ word-wrap :break-word;
+ font-size: 100%;
+}
+
+table.checkers thead {
+ background-color:#eee; color:#666666;
+ border-top: 2px solid #cccccc;
+ border-bottom: 2px solid #cccccc;
+ font-weight: bold; font-family: Verdana;
+}
+
+table.checkers td {
+ padding:5px; padding-left:8px; padding-right:8px;
+ border-right: 1px #cccccc dotted;
+ border-bottom: 1px #cccccc dotted;
+}
+
+table.checkers col.namedescr { width: 45% }
+table.checkers col.example { width: 55% }
+table.checkers col.progress { width: 84px }
+table.checkers pre { margin:1px; font-size: 100%; word-wrap :break-word; }
+table.checkers .name { font-weight:bold; }
+table.checkers .checked { background-color:#81F781; }
+table.checkers .commented { color:#909090; }
+
/* Collapsing Trees: http://dbtree.megalingo.com/web/demo/simple-collapsible-tree.cfm */
#collapsetree, #collapsetree a:link, #collapsetree li a:link, #collapsetree a:visited, #collapsetree li a:visited{color:#000;text-decoration:none}
#collapsetree,#collapsetree ul{list-style-type:none; width:auto; margin:0; padding:0}
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 74c6ab0a5732..996bc34cc139 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://bit.ly/OIdyI7">checker-267.tar.bz2</a></b> (built June 1, 2012)
+<b><a href="http://bit.ly/USf8ge">checker-269.tar.bz2</a></b> (built September 25, 2012)
diff --git a/www/analyzer/menu.html.incl b/www/analyzer/menu.html.incl
index d1581a6e85fb..72160e699937 100644
--- a/www/analyzer/menu.html.incl
+++ b/www/analyzer/menu.html.incl
@@ -26,6 +26,7 @@
<li>
Development
<ul>
+ <li><a href="/potential_checkers.html">Potential Future Checkers</a></li>
<li><a href="/checker_dev_manual.html">Checker Developer Manual</a></li>
<li><a href="/dev_cxx.html">Analysis Support for C++</a></li>
</ul>
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
new file mode 100644
index 000000000000..f65106efaf92
--- /dev/null
+++ b/www/analyzer/potential_checkers.html
@@ -0,0 +1,1651 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>List of potential checkers</title>
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <script type="text/javascript" src="scripts/menu.js"></script>
+ <script type="text/javascript" src="scripts/dbtree.js"></script>
+</head>
+<body>
+
+<div id="page">
+
+<!-- menu -->
+<!--#include virtual="menu.html.incl"-->
+<!-- page content -->
+<div id="content">
+<h1>List of potential checkers</h1>
+
+<p>This page contains a list of potential checkers to implement in the static analyzer. If you are interested in contributing to the analyzer's development, this is a good resource to help you get started. The specific names of the checkers are subject to review, and are provided here as suggestions.</p>
+
+<!-- ========================= allocation/deallocation ======================= -->
+<h3>allocation/deallocation</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">memory.LeakNeverReleased<br>
+(C, C++)</span><br><br>
+Memory may be never released, potential leak of memory
+</td><td>
+<pre>
+#include &lt;stdlib.h&gt;
+
+int f() {};
+
+void test() {
+ int *p1 = (int*)malloc(sizeof(int)); // warn
+ int *p2 = new int; // warn
+ int x = f();
+ if (x==1)
+ return;
+ delete p2;
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.MismatchedFree
+<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
+Mismatched deallocation function is used
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p1 = new int;
+ int *p2 = new int[1];
+
+ free(p1); // warn
+ free(p2); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.MismatchedDelete
+<br>(C, C++)</span><br><br>
+Mismatched deallocation function is used
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p1 = new int;
+ int *p2 = new int[1];
+ int *p3 = (int*)malloc(sizeof(int));
+
+ delete[] p1; // warn
+ delete p2; // warn
+ delete p3; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.MultipleDelete
+<br>(C++)</span><br><br>
+Attempt to deallocate released memory
+</td><td><pre>
+#include &lt;new&gt;
+
+void test() {
+ int *p1 = new int;
+ int *p2 = new(p1) int;
+ int *p3 = p1;
+ delete p1;
+ delete p1; // warn
+ delete p2; // warn
+ delete p3; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.LeakPtrValChanged
+<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
+Potential memory leak: a pointer to newly allocated data loses its original
+value
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void f(const int *);
+void g(int *);
+
+void test() {
+ int *p1 = new int;
+ p1++; // warn
+ int *p2 = (int *)malloc(sizeof(int));
+ p2 = p1; // warn
+ int *p3 = new int;
+ f(p3);
+ p3++; // warn
+ int *p4 = new int;
+ f(p4);
+ p4++; // ok
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.DeallocateNonPtr
+<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
+Deallocation function is applied to non-pointer
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+class A {
+ int *p;
+public:
+ operator int *() { return p; }
+};
+
+void test() {
+ A a;
+ delete a; // warn
+ free(a); // warn
+ const char *s = "text";
+ delete s; // warn
+ free(s); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.LeakEvalOrder<br>
+(C, C++)</span><br><br>
+Potential memory leak: argument evaluation order is undefined, g() may never be called
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void f1(int, int);
+void f2(int*, int*);
+int g(int *) { throw 1; };
+int h();
+
+void test() {
+ f1(g(new int), h()); // warn
+ f1(g((int *)malloc(sizeof(int))), h()); // warn
+ f2(new int, new int);
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.DstBufferTooSmall
+<br>(C, C++)</span><br><br>
+Destination buffer too small
+</td><td><pre>
+#include &lt;string.h&gt;
+
+void test() {
+ const char* s1 = "abc";
+ char *s2 = new char;
+ strcpy(s2, s1); // warn
+
+ int* p1 = new int[3];
+ int* p2 = new int;
+ memcpy(p2, p1, 3); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">memory.NegativeArraySize
+<br>enhancement to experimental.security.MallocOverflow<br>(C, C++)
+</span><br><br>
+'n' is used to specify the buffer size may be negative
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p;
+ int n1 = -1;
+ p = new int[n1]; // warn
+}
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- ======================= constructors/destructors ====================== -->
+<h3>constructors/destructors</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">ctordtor.ExptInsideDtorExplicit<br>
+(C++)</span><br><br>
+It is dangerous to let an exception leave a destructor. Using try..catch will
+solve the problem.
+</td><td><pre>
+void f();
+
+class A {
+ A() {}
+ ~A() { throw 1; } // warn
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">ctordtor.ExptInsideDtorImplicit<br>
+(C++)</span><br><br>
+Calls to functions inside a destructor that are known to throw exceptions is
+dangerous. Using try..catch will solve the problem.
+</td><td><pre>
+void f() { throw 1; };
+
+class A {
+ A() {}
+ ~A() { f(); } // warn
+};
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- ============================== exceptions ============================= -->
+<h3>exceptions</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">exceptions.ThrowSpecButNotThrow
+<br>(C++)</span><br><br>
+Function prototype has throw(T) specifier but the function do not throw
+</td><td><pre>
+void f() throw(int) { // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">exceptions.NoThrowSpecButThrows
+<br>(C++)</span><br><br>
+An exception is throw from a function having the throw() specifier
+</td><td><pre>
+void f() throw() {
+ throw(1); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">exceptions.ThrownTypeDiffersSpec
+<br>(C++)</span><br><br>
+The type of a thrown exception differs from those specified in the throw(T)
+specifier
+</td><td><pre>
+struct S{};
+void f() throw(int) {
+ S s;
+ throw (s); // warn
+}
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- ========================= smart pointers ============================== -->
+<h3>smart pointers</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">smartptr.SmartPtrInit<br>
+(C++)</span><br><br>
+C++03: auto_ptr should store a pointer to an object obtained via new as allocated
+memory will be cleaned using delete<br>
+C++11: one should use unique_ptr&lt;T[]&gt; to keep a pointer to memory
+allocated by new[]<br>
+C++11: to keep a pointer to memory allocated by new[] in a shared_ptr one
+should use a custom deleter that calls delete[]
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+#include &lt;memory&gt;
+
+void test() {
+ std::auto_ptr&lt;int&gt; p1(new int); // Ok
+ std::auto_ptr&lt;int&gt; p2(new int[3]); // warn
+ std::auto_ptr&lt;int&gt;
+ p3((int *)malloc(sizeof(int))); // warn
+}
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- ========================= undefined behavior ========================== -->
+<h3>undefined behavior</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">undefbehavior.ExitInDtor
+<br>(C++)</span><br><br>
+Undefined behavior: std::exit is called to end the program during the
+destruction of an object with static storage duration
+</td><td><pre>
+#include &lt;cstdlib&gt;
+
+class A {
+public:
+ ~A() {
+ std::exit(1); // warn
+ }
+};
+
+A a;
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.LocalStaticDestroyed
+<br>(C++)</span><br><br>
+Undefined behavior: function containing a definition of static local object is
+called during the destruction of an object with static storage duration so that
+flow of control passes through the definition of the previously destroyed
+static local object
+</td><td><pre>
+void f();
+
+class A {
+public:
+ ~A() {
+ f(); // warn
+ }
+};
+
+class B {};
+
+A a;
+
+void f() {
+ static B b; // &lt;-
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.UseAfterRelease
+<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
+Pointer to deleted object is referenced (The effect of using an invalid pointer
+value is undefined)
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p = new int;
+ delete p;
+ int i = *p; // warn
+}
+
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ZeroAllocDereference
+<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
+The effect of dereferencing a pointer returned as a request for zero size is
+undefined
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+int *p = new int[0];
+int i = p[0]; // warn
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.DeadReferenced
+<br>(C++)</span><br><br>
+Undefined behavior: the following usage of the pointer to the object whose
+lifetime has ended can result in undefined behavior
+</td><td><pre>
+// C++03
+#include &lt;new&gt;
+
+class A {
+public:
+ int i;
+ void f() {};
+};
+
+class B : public A {
+};
+
+void test() {
+ B *b = new B;
+ new(b) A;
+ b->i; // warn
+ b->f(); // warn
+ static_cast&lt;A*&gt;(b); // warn
+ dynamic_cast&lt;A*&gt;(b); // warn
+ delete b; // warn
+}
+
+// C++11
+#include &lt;new&gt;
+
+class A {
+public:
+ int i;
+ void f() {};
+};
+
+class B : public A {
+public:
+ ~B() {};
+};
+
+void test() {
+ A *a = new A;
+ new(a) B;
+ a->i; // warn
+ a->f(); // warn
+ B *b = new B;
+ new(b) A;
+ b->i; // warn
+ b->f(); // warn
+ static_cast&lt;A*&gt;(b); // warn
+ dynamic_cast&lt;A*&gt;(b); // warn
+ delete b; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ObjLocChanges
+<br>(C++)</span><br><br>
+Undefined behavior: the program must ensure that an object occupies the same
+storage location when the implicit or explicit destructor call takes place
+</td><td><pre>
+#include &lt;new&gt;
+
+class T { };
+struct B {
+ ~B();
+};
+
+void test() {
+ B *b1 = new B;
+ B b2;
+ new (b1) T;
+ new (&amp;b2) T;
+ delete b1; // warn
+} // warn
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ExprEvalOrderUndef
+<br>(C, C++03)</span><br><br>
+Undefined behavior: a scalar object shall have its stored value modified at
+most once by the evaluation of an expression
+</td><td><pre>
+void test () {
+ int i = 0;
+ int v[1] = {0};
+ i = v[i++]; // warn
+ i = ++i + 1; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.StaticInitReentered
+<br>(C)</span><br><br>
+Undefined behavior: static declaration is re-entered while the object is being
+initialized
+</td><td><pre>
+int test(int i) {
+ static int s = test(2*i); // warn
+ return i+1;
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ConstModified
+<br>(C, C++)</span><br><br>
+Undefined behavior: const object is being modified
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+class X {
+public :
+ mutable int i;
+ int j;
+};
+class Y {
+public :
+ X x;
+ Y();
+};
+
+void test() {
+ const int *ciq =
+ (int *)malloc(sizeof(int));
+ int *iq = const_cast&lt;int *&gt;(ciq);
+ *iq = 1; // warn
+
+ const Y y;
+ Y* p = const_cast&lt;Y*&gt;(&amp;y);
+ p-&gt;x.i = 1; // ok
+ p-&gt;x.j = 1; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.DeadDestructed
+<br>(C++)</span><br><br>
+Undefined behavior: the destructor is invoked for an object whose lifetime
+has ended
+</td><td><pre>
+class A {
+public:
+ void f() {};
+ A() {};
+ ~A() {};
+};
+
+void test() {
+ A a;
+ a.~A();
+} // warn
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.MethodCallBeforeBaseInit
+<br>(C++)</span><br><br>
+Undefined behavior: calls member function but base not yet initialized
+</td><td><pre>
+class A {
+public :
+ A(int );
+};
+class B : public A {
+public :
+ int f();
+ B() : A(f()) {} // warn
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.MemberOrBaseRefBeforeCtor
+<br>(C++)</span><br><br>
+C++ Undefined behavior: non-static member or base class of non-POD class type
+is referred before constructor begins execution<br>
+C++11 Undefined behavior: non-static member or base class of a class with a
+non-trivial constructor is referred before constructor begins execution
+</td><td><pre>
+// C++03
+struct POD {
+ int i;
+};
+
+struct non_POD : public POD {
+ int j;
+ POD pod;
+};
+
+extern POD pod;
+extern non_POD non_pod;
+
+int *p1 = &amp;non_pod.j; // warn
+int *p2 = &amp;non_pod.pod.i; // warn
+int *p3 = &amp;pod.i; // ok
+POD *p4 = &amp;non_pod; // warn
+
+POD a;
+non_POD b;
+
+struct S {
+ int *k;
+ non_POD non_pod;
+ S() : k(&amp;non_pod.j) {} // warn
+};
+
+// C++11
+struct trivial {
+ int i;
+};
+
+struct non_trivial: public trivial {
+ non_trivial() {};
+ int j;
+ trivial pod;
+};
+
+extern trivial t;
+extern non_trivial nt;
+
+int *p1 = &amp;nt.j; // warn
+int *p2 = &amp;nt.i; // warn
+int *p3 = &amp;t.i; // ok
+trivial *p4 = &amp;nt;
+
+trivial t;
+non_trivial nt;
+
+struct S {
+ int *k;
+ non_trivial nt;
+ S() : k(&amp;nt.j) {} // warn
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.MemberRefAfterDtor
+<br>(C++)</span><br><br>
+C++03: Undefined behavior: non-static member of non-POD class type is referred
+after destructor ends execution<br>
+C++11: Undefined behavior: non-static member of a class with a non-trivial
+destructor is referred after destructor ends execution
+</td><td><pre>
+// C++03
+struct non_POD {
+ virtual void f() {};
+};
+
+void test() {
+ non_POD *non_pod = new non_POD();
+ non_pod->~non_POD();
+ non_pod->f(); // warn
+}
+
+// C++11
+struct S {
+ ~S() {};
+ void f() {};
+};
+
+void test() {
+ S *s = new S();
+ s->~S();
+ s->f(); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.CtorForeignCall
+<br>(C++)</span><br><br>
+Undefined behavior: call to virtual function of an object under construction
+whose type is neither the constructors own class or one of its bases
+</td><td><pre>
+class A {
+public:
+ virtual void f() {};
+};
+
+class B {
+public:
+ B(A* a) { a-&gt;f(); } // warn
+};
+
+class C : public A, B {
+public:
+ C() : B((A*)this) {}
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.CtorForeignCast
+undefbehavior.CtorForeignTypeid
+<br>(C++)</span><br><br>
+Undefined behavior: the operand of typeid/dynamic_cast is an object under
+construction whose type is neither the constructors own class or one of its
+bases
+</td><td><pre>
+#include &lt;typeinfo&gt;
+
+class A {
+public:
+ virtual void f() {};
+};
+
+class B {
+public:
+ B(A* a) {
+ typeid(*a); // warn
+ dynamic_cast&lt;B*&gt;(a); //warn
+ }
+};
+
+class C : public A, B {
+public:
+ C() : B((A*)this) {}
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.MemberRefInCatch
+undefbehavior.BaseRefInCatch
+<br>(C++)</span><br><br>
+Undefined behavior: referring to any non-static member or base class of an
+object in the handler for a function-try-block of a constructor or destructor
+for that object results in undefined behavior
+</td><td><pre>
+class C {
+ int i;
+public :
+ C()
+ try
+ : i(1) {}
+ catch (...)
+ {
+ i=2; // warn
+ }
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ReturnAtCatchEnd
+<br>(C++)</span><br><br>
+Undefined behavior: a function returns when control reaches the end of a
+handler. This results in undefined behavior in a value-returning
+function
+</td><td><pre>
+int test() try {
+}
+catch(int) {
+} // warn
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.AutoptrsOwnSameObj
+<br>(C++03)</span><br><br>
+Undefined behavior: if more than one auto_ptr owns the same object at the same
+time the behavior of the program is undefined.
+</td><td><pre>
+#include &lt;memory&gt;
+
+void test() {
+ int *data = new int;
+ std::auto_ptr&lt;int&gt; p(data);
+ std::auto_ptr&lt;int&gt; q(data); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.BasicStringBoundAccess
+<br>(C++03)</span><br><br>
+Undefined behavior: out-of-bound basic_string access
+</td><td><pre>
+void test() {
+ std::basic_string&lt;char&gt; s;
+ char c = s[10]; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.BasicStringBoundModification
+<br>(C++)</span><br><br>
+Undefined behavior: out-of-bound basic_string modification
+</td><td><pre>
+void test() {
+ std::basic_string&lt;char&gt; s;
+ s[10] = 0; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.EosDereference
+<br>(C++)</span><br><br>
+Undefined behavior: the result of operator*() on an end of stream is
+undefined
+</td><td><pre>
+#include &lt;vector&gt;
+
+void test() {
+ std::vector&lt;int&gt; v;
+ int i = *v.end(); // warn
+ *v.end() = 0; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.QsortNonPOD
+undefbehavior.QsortNonTrivial
+<br>C++</span><br><br>
+C++03: Undefined behavior: the objects in the array passed to qsort are of
+non-POD type<br>
+C++11: Undefined behavior: the objects in the array passed to qsort are of
+non-trivial type
+</td><td><pre>
+// C++03
+#include &lt;cstdlib&gt;
+
+struct non_POD {
+ int i;
+ non_POD(int ii) : i(ii) {}
+};
+
+non_POD values[] = { non_POD(2), non_POD(1) };
+
+int compare(const void *a,
+ const void *b) {
+ return ( (*(non_POD*)a).i -
+ (*(non_POD*)b).i );
+}
+
+void test() {
+ qsort(values, 2, sizeof(non_POD),
+ compare); // warn
+}
+
+// C++11
+#include &lt;cstdlib&gt;
+
+struct S {};
+
+struct trivial_non_POD : public S {
+ int i;
+};
+
+struct non_trivial {
+ int i;
+ non_trivial() {}
+};
+
+trivial_non_POD tnp[2];
+non_trivial nt[2];
+
+int compare1(const void *a,
+ const void *b) {
+ return ( (*(trivial_non_POD *)a).i -
+ (*(trivial_non_POD *)b).i );
+}
+
+int compare2(const void *a,
+ const void *b) {
+ return ( (*(non_trivial *)a).i -
+ (*(non_trivial *)b).i );
+}
+
+void test() {
+ qsort(tnp, 2, sizeof(trivial_non_POD),
+ compare1); // ok
+ qsort(nt, 2, sizeof(non_trivial),
+ compare2); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ThrowWhileCopy
+<br>C++</span><br><br>
+Undefined behavior: copy constructor/assignment operator can throw an exception.
+The effects are undefined if an exception is thrown.
+</td><td><pre>
+struct S {
+ int i, j;
+ S (const S &amp;s) {
+ i = s.i;
+ throw 1; // warn
+ j = s.j;
+ };
+ S &amp;operator=(const S &amp;s) {
+ i = s.i;
+ throw 1; // warn
+ j = s.j;
+ }
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ValarrayArgBound
+<br>(C++)</span><br><br>
+Undefined behavior: the value of the second argument is greater than the number
+of values pointed to by the first argument
+</td><td><pre>
+#include &lt;valarray&gt;
+
+struct S {
+ int i;
+ S(int ii) : i(ii) {};
+};
+
+void test(void) {
+ S s[] = { S(1), S(2) };
+ std::valarray&lt;S&gt; v(s,3); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ValarrayLengthDiffer
+<br>(C++)</span><br><br>
+Undefined behavior: valarray operands are of different length
+</td><td><pre>
+// C++03
+#include &lt;valarray&gt;
+
+void test(void) {
+ std::valarray&lt;int&gt; a(0, 1), b(0, 2);
+ std::valarray&lt;bool&gt; c(false, 1);
+ a = b; // warn
+ a *= b; // warn
+ a = a * b; // warn
+ c = a == b; // warn
+ b.resize(1);
+ a = b; // OK
+}
+
+// C++11
+#include &lt;valarray&gt;
+
+void test(void) {
+ std::valarray&lt;int&gt; a(0, 1), b(0, 2);
+ std::valarray&lt;bool&gt; c(false, 1);
+ a = b; // ok
+ a *= b; // ok
+ a = a * b; // warn
+ c = a == b; // warn
+ b.resize(1);
+ a = b; // OK
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ValarrayZeroLength
+<br>(C++)</span><br><br>
+Undefined behavior: calling sum()/min()/max() method of an array having zero
+length, the behavior is undefined
+</td><td><pre>
+#include &lt;valarray&gt;
+
+void test(void) {
+ std::valarray&lt;int&gt; v(0, 0);
+ v.sum(); // warn
+ v.min(); // warn
+ v.max(); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.ValarrayBadIndirection
+<br>(C++)</span><br><br>
+Undefined behavior: element N is specified more than once in the
+indirection
+</td><td><pre>
+#include &lt;valarray&gt;
+
+void test() {
+ size_t addr[] = {0, 1, 1}; // N is 1
+ std::valarray&lt;size_t&gt;indirect(addr, 3);
+ std::valarray&lt;int&gt; a(0, 5), b(1, 3);
+ a[indirect] = b; //warn
+ a[indirect] *= b; //warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.IosBaseDestroyedBeforeInit
+<br>(C++)</span><br>
+<br>Undefined behavior: ios_base object is destroyed before initialization have
+taken place. basic_ios::init should be call to initialize ios_base
+members
+</td><td><pre>
+#include &lt;ios&gt;
+
+using namespace std;
+template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
+class my_stream1 : public std::basic_ios&lt;T, Traits&gt; {
+};
+
+template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
+class my_stream2 : public std::basic_ios&lt;T, Traits&gt; {
+ class my_streambuf : public std::basic_streambuf&lt;T, Traits&gt; {
+ };
+public:
+ my_stream2() {
+ this->init(new my_streambuf);
+ }
+};
+
+void test() {
+ my_stream1&lt;char&gt; *p1 = new my_stream1&lt;char&gt;
+ my_stream2&lt;char&gt; *p2 = new my_stream2&lt;char&gt;
+ delete p1; // warn
+ delete p2; // ok
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.IosBaseUsedBeforeInit
+<br>(C++11)</span><br><br>
+Undefined behavior: ios_base object is used before initialization have taken
+place. basic_ios::init should be call to initialize ios_base members
+</td><td><pre>
+#include &lt;ios&gt;
+
+using namespace std;
+template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
+class my_stream1 : public std::basic_ios&lt;T, Traits&gt; {
+};
+
+template &lt;class T, class Traits = std::char_traits&lt;T&gt;&gt;
+class my_stream2 : public std::basic_ios&lt;T, Traits&gt; {
+ class my_streambuf : public std::basic_streambuf&lt;T, Traits&gt; {
+ };
+public:
+ my_stream2() {
+ this->init(new my_streambuf);
+ }
+};
+
+void test() {
+ my_stream1&lt;char&gt; *p1 = new my_stream1&lt;char&gt;
+ my_stream2&lt;char&gt; *p2 = new my_stream2&lt;char&gt;
+ p1->narrow('a', 'b'); // warn
+ p2->narrow('a', 'b'); // ok
+ delete p1; // warn
+ delete p2; // ok
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">undefbehavior.MinusOnePosType
+<br>(C++)</span><br><br>
+Undefined behavior: passing -1 to any streambuf/istream/ostream member that
+accepts a value of type traits::pos_type result in undefined behavior
+</td><td><pre>
+#include &lt;fstream&gt;
+
+class my_streambuf : public std::streambuf {
+ void f() {
+ seekpos(-1); // warn
+ }
+};
+
+void test() {
+ std::filebuf fb;
+ std::istream in(&amp;fb);
+ std::ostream out(&amp;fb);
+ std::filebuf::off_type pos(-1);
+ in.seekg(pos); // warn
+ out.seekp(-1); // warn
+}
+</pre></td><td></td></tr>
+</table>
+
+<!-- ============================ different ================================ -->
+<h3>different</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">different.ArgEvalOrderUndef
+<br>(C)</span><br><br>
+Errors because of the order of evaluation of function arguments is undefined
+</td><td><pre>
+void f(int, int);
+
+void test() {
+ int i = 0;
+ int v[1] = {0};
+ f(v[i], i++); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.IdenticalExprBinOp
+<br>(C)</span><br><br>
+There are identical sub-expressions to the left and to the right of the
+operator
+</td><td><pre>
+#define A 1
+#define B 1
+
+bool isNan(double d) {
+ return d != d; // ok
+}
+
+int f();
+
+void test() {
+ int i = 0;
+ if (i != 0 && i != 0) {} // warn
+
+ if(i == A || i == B) {} // ok
+
+ if (++i != 0 && ++i != 0) {} // ok
+
+ if (f() && f()) {} // ok
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.FuncPtrInsteadOfCall
+<br>(C)</span><br><br>
+Possibly a function call should be used instead of a pointer to function
+</td><td><pre>
+int f();
+
+void test() {
+ if (f == 0) {} // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.IdenticalCondIfElseIf
+<br>(C)</span><br><br>
+The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a
+probability of logical error presence
+</td><td><pre>
+void test() {
+ int i = 7;
+ if (i == 1) {}
+ else if (i == 1) {} // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">SuccessiveAssign
+<br>(C)</span><br><br>
+Successive assign to a variable
+</td><td><pre>
+void test() {
+ int i=0;
+ i=1;
+ i=2; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.NullDerefStmtOrder
+<br>enhancement to core.NullDereference<br>(C)</span><br><br>
+Dereferencing of the null pointer might take place. Checking the pointer for
+null should be performed first
+</td><td><pre>
+struct S {
+ int x;
+};
+
+S* f();
+
+void test() {
+ S *p1 = f();
+ int x1 = p1-&gt;x; // warn
+ if (p1) {};
+
+ S *p2 = f();
+ int x2 = p2-&gt;x; // ok
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.NullDerefCondOrder
+<br>enhancement to core.NullDereference<br>(C)</span><br><br>
+Dereferencing of the null pointer might take place. Checking the pointer for
+null should be performed first
+</td><td><pre>
+struct S{bool b;};
+
+S* f();
+
+void test() {
+ S *p = f();
+ if (p-&gt;b && p) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.IdenticalStmtThenElse
+<br>(C)</span><br><br>
+The 'else' statement is equivalent to the 'then' statement
+</td><td><pre>
+void test() {
+ int i;
+ if (i==1) {
+ i++;
+ }
+ else { // warn
+ i++;
+ }
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.MultipleAccessors
+<br>(C++)</span><br><br>
+multiple accessors met for 'class::field'
+</td><td><pre>
+class A {
+ int i;
+ int j;
+public:
+ int getI() { return i; }
+ int getJ() { return i; } // warn
+ void setI(int& ii) { i = ii; }
+ void setJ(int& jj) { i = jj; } // warn
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.AccessorsForPublic
+<br>(C++)</span><br><br>
+Accessors exist for 'class::field'. Should this field really be public?
+</td><td><pre>
+class A {
+public:
+ int i; // warn
+ int getI() { return i; }
+ void setI(int& ii) { i = ii; }
+};
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.LibFuncResultUnised
+<br>(C, C++)</span><br><br>
+Calling 'f' ignoring its return value is of no use (* create the list of known
+system/library/API functions falling into this category)
+</td><td><pre>
+#include &lt;vector&gt;
+
+void test() {
+ std::vector&lt;int&gt; v;
+ v.empty(); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.WrongVarForStmt
+<br>(C, C++)</span><br><br>
+Possibly wrong variable is used in the loop/cond-expression of the 'for'
+statement. Did you mean 'proper_variable_name'?
+</td><td><pre>
+void test() {
+ int i;
+ int j;
+ for (j=0; j&lt;3; ++i); // warn
+ for (int j=0; i&lt;3; ++j); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.FloatingCompare
+<br>(C)</span><br><br>
+Comparing floating point numbers may be not precise
+</td><td><pre>
+#include &lt;math.h&gt;
+
+void test() {
+ double b = sin(M_PI / 6.0);
+ if (b == 0.5) // warn
+ b = 0;
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.BoolCompare
+<br>maybe merge with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
+Comparing boolean to a value other then 0 or 1
+</td><td><pre>
+void test() {
+ int i;
+ if (0 < i < 3) {}; // warn
+ bool b;
+ if (b == 3) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.BitwiseOpBoolArg
+<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
+bool value is used at the left/right part of the &amp; (|) operator. Did you mean
+&amp;&amp; (||) ?
+</td><td><pre>
+int f();
+
+void test() {
+ bool b = true;
+ if (b &amp; f()) {} // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.LabelInsideSwitch
+<br>(C)</span><br><br>
+Possible misprint: label found inside the switch() statement. (* did you mean
+'default'?)
+</td><td><pre>
+void test() {
+ int c = 7;
+ switch(c){
+ case 1:
+ c += 1; break;
+ defalt: // warn
+ c -= 1; break;
+ }
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.IdenticalCondIfIf
+<br>(C)</span><br><br>
+The conditions of two subsequent 'if' statements are identical
+</td><td><pre>
+void test() {
+ int c = 7;
+ if (c &gt; 5) // &lt;-
+ c += 1;
+ if (c &gt; 5) // warn
+ c -= 1;
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.CondOpIdenticalReturn
+<br>(C)</span><br><br>
+The return expressions of the '?:' operator are identical
+</td><td><pre>
+void test() {
+ unsigned a;
+ a = a > 5 ? a : a; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.UnaryPlusWithUnsigned
+<br>(C)</span><br><br>
+Using 'unary +' with unsigned is meaningless
+</td><td><pre>
+void test() {
+ unsigned a;
+ a = +a; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.LogicalOpUselessArg
+<br>(C)</span><br><br>
+The second operand of the &amp;&amp; operator has no impact on expression result
+</td><td><pre>
+void test() {
+ unsigned a;
+ if (a&lt;7 &amp;&amp; a&lt;10) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.SameResLogicalExpr
+<br>(C)</span><br><br>
+The expression always evaluates to true/false
+</td><td><pre>
+void test() {
+ int i=0;
+ if (i!=0) {}; // warn
+ if (i==0 &amp;&amp; i==1) {}; // warn
+ if (i<0 || i>=0) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.SameResUnsignedCmp
+<br>(C)</span><br><br>
+Comparison of unsigned expression 'op expr' is always true/false
+</td><td><pre>
+void test() {
+ unsigned u;
+ if (u &lt; -1) {}; // warn
+ if (u &gt;= 0) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.OpPrecedenceAssignCmp
+<br>(C)</span><br><br>
+Comparison operation has higher precedence then assignment. Bool value is
+assigned to variable of type 'type'. Parenthesis may bee required around an
+assignment
+</td><td><pre>
+int f();
+
+void test() {
+ bool b;
+ int x, y;
+ if((b = x != y)) {} // ok
+ if((x = f() != y)) {} // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.OpPrecedenceIifShift
+<br>(C)</span><br><br>
+?: has lower precedence then &lt;&lt;
+</td><td><pre>
+#include &lt;iostream&gt;
+
+void test() {
+ int a;
+ std::cout &lt;&lt; a ? "a" : "b"; // warn
+ a &lt;&lt; a&gt;7 ? 1 : 2; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.ObjectUnused
+<br>(C++)</span><br><br>
+The object was created but is not being used<br><br>
+The exception object was created but is not being used. Did you mean
+'throw std::exception();'?
+</td><td><pre>
+#include &lt;exception&gt;
+
+struct S {
+ int x, y;
+ S(int xx, int yy) : x(xx), y(yy) {
+ }
+ S(int xx) {
+ S(xx, 0); // warn
+ }
+};
+
+void test() {
+ S(0, 0); // warn
+ std::exception(); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.StaticArrayPtrCompare
+<br>(C)</span><br><br>
+Pointer to static array is being compared to NULL. May the subscripting is
+missing
+</td><td><pre>
+void test() {
+ int a1[1];
+ if (a1 == 0) {}; // warn
+
+ int a2[1][1];
+ if (a2[0]) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.ConversionToBool
+<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
+Odd implicit conversion from 'type' to 'bool'
+</td><td><pre>
+bool test() {
+ return 1.; // warn
+ return ""; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.ArrayBound
+<br>enhancement to experimental.security.ArrayBound[v2]<br>(C, C++)</span><br><br>
+Out-of-bound dynamic array access
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+void test() {
+ int *p2 = new int[1];
+ if(p2[1]) {}; // warn
+ int i = 1;
+ if(p2[i]) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.StrcpyInputSize
+<BR>enhancement to experimental.unix.cstring.OutOfBounds<br>(C)</span><br><br>
+Buffer copy without checking size of input
+</td><td><pre>
+void test(char* string) {
+ char buf[24];
+ strcpy(buf, string); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.IntegerOverflow
+<br>(C)</span><br><br>
+Integer overflow
+</td><td><pre>
+#include &lt;limits.h&gt;
+
+int f(int x) {
+ return INT_MAX+1; // warn
+}
+
+void test() {
+ int x = INT_MAX+1; // warn
+ f(INT_MAX+1); // warn
+
+ int y = INT_MAX/2+1; // warn
+ x = y*2; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.SignExtension
+<br>(C)</span><br><br>
+Unexpected sign extension might take place
+</td><td><pre>
+void f(unsigned int i);
+int g();
+
+unsigned int test() {
+ long long sll;
+ unsigned long long ull = sll; // warn
+ long sl;
+ unsigned long ul = sl; // warn
+ int si;
+ unsigned int ui = si; // warn
+ short ss;
+ unsigned short us = ss; // warn
+ signed char sc;
+ unsigned char uc = sc; // warn
+ f(si); // warn
+ ui = g(); // warn
+ return si; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.NumericTruncation
+<br>(C)</span><br><br>
+Numeric truncation might take place
+</td><td><pre>
+void f(int i);
+int g();
+
+int test() {
+ unsigned long long ull;
+ long long sll;
+ unsigned long ul = ull; // warn
+ long sl = sll; // warn
+ unsigned int ui = ul; // warn
+ int si = sl; // warn
+ unsigned short us = ui; // warn
+ short ss = si; // warn
+ unsigned char uc = us; // warn
+ signed char sc = uc; // warn
+ f(sll); // warn
+ ss = g(); // warn
+ return sll; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">different.MissingCopyCtorAssignOp
+<br>(C, C++)</span><br><br>
+The class has dynamically allocated data members but do not define a copy
+constructor/assignment operator
+</td><td><pre>
+class C { // warn
+ int *p; // &lt;-
+public:
+ C() { p = new int; }
+ ~C() { delete p; }
+};
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- ============================ WinAPI =================================== -->
+<h3>WinAPI</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">WinAPI.CreateProcess
+<br>(C)</span><br><br>
+After calling CreateProcess(), ensure that process and thread handles get closed
+(* for the given example: examine data flow from pi, pi.hProcess and pi.hThread)
+</td><td><pre>
+#include &lt;windows.h&gt;
+
+void test() {
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL fSuccess;
+ fSuccess = CreateProcess(
+ NULL, TEXT("MyProgram.exe"), NULL, NULL,
+ TRUE, 0, NULL, NULL, &amp;si, &amp;pi);
+} // warn
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">WinAPI.LoadLibrary
+<br>(C)</span><br><br>
+Calling LoadLibrary without a fully qualified path may allow to load a DLL from
+arbitrary location
+</td><td><pre>
+#include &lt;windows.h&gt;
+
+void test() {
+ HINSTANCE h = LoadLibrary("X.dll"); // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">WinAPI.WideCharToMultiByte
+<br>(C)</span><br><br>
+Buffer overrun while calling WideCharToMultiByte
+</td><td><pre>
+#include &lt;windows.h&gt;
+
+void test()
+{
+ wchar_t ws[] = L"abc";
+ char s[3];
+ int res1 = WideCharToMultiByte(
+ CP_UTF8, 0, ws, -1, s,
+ 3, NULL, NULL); // warn
+ int res2 = WideCharToMultiByte(
+ CP_UTF8, 0, ws, -1, s,
+ 3, NULL, NULL); // ok
+ if (res2 == sizeof(s))
+ s[res2-1] = 0;
+ else
+ s[res2] = 0;
+}
+</pre></td><td></td></tr>
+
+</table>
+
+<!-- =========================== optimization ============================== -->
+<h3>optimization</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">optimization.PassConstObjByValue
+<br>(C, C++)</span><br><br>
+Optimization: It is more effective to pass const n-th parameter by reference to
+avoid unnecessary object copying
+</td><td><pre>
+struct A {
+ int a[20];
+ int b;
+};
+
+bool FirstIsZero(const struct A a) { // warn
+ return a.a[0] == 0;
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">optimization.PostfixIncIter
+<br>(C++)</span><br><br>
+Optimization: It is more effective to use prefix ++ with iterator here
+</td><td><pre>
+#include &lt;vector&gt;
+
+void test() {
+ std::vector&lt;int&gt; v;
+ std::vector&lt;int&gt;::const_iterator it;
+ for(it = v.begin();
+ it != v.end(); it++) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">optimization.MultipleCallsStrlen
+<br>(C)</span><br><br>
+Optimization: multiple calls to strlen for a given string in the given
+expression. It is more effective to hold strlen result in a temporary
+variable
+</td><td><pre>
+#include &lt;string.h&gt;
+
+void test() {
+ const char* s = "abc";
+ if (strlen(s) &gt; 0 &amp;&amp;
+ strlen(s) &lt; 7) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">optimization.EmptyCstrDetect
+<br>(C)</span><br><br>
+Optimization: it is more efficient to use "str[0] != '\0'" to identify an empty
+string
+</td><td><pre>
+#include &lt;string.h&gt;
+
+void test() {
+ const char* s = "abc";
+ if (strlen(s) &gt; 0) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">optimization.StrLengthCalculation
+<br>(C, C++)</span><br><br>
+Optimization: it is more efficient to use string::length() method to calculate
+string length
+</td><td><pre>
+#include &lt;string&gt;
+#include &lt;string.h&gt;
+
+void test() {
+ std::string s;
+ if (strlen(s.c_str()) != 0) {}; // warn
+}
+</pre></td><td></td></tr>
+
+<tr><td><span class="name">optimization.EmptyContainerDetect
+<br>(C, C++)</span><br><br>
+Optimization: It is more efficient to use container.empty() to identify an
+empty container
+</td><td><pre>
+#include &lt;list&gt;
+
+void test() {
+ std::list&lt;int&gt; l;
+ if (l.size() != 0) {}; // warn
+}
+</pre></td><td></td></tr>
+
+</table>
+
+<br>
+</div> <!-- page -->
+</div> <!-- content -->
+</body>
+</html>
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 79f0e0d2db4b..60f323b7afa8 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,29 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<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>highlights:</b></p>
+ <ul>
+ <li>Significantly improves interprocedural analysis for Objective-C.</li>
+ <li>Numerous bug fixes and heuristics to reduce false positives reported
+ over checker-268.</li>
+ </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>highlights:</b></p>
+
+<ul>
+ <li>Adds initial interprocedural analysis support for C++ and Objective-C. This will greatly improve analysis coverage and find deeper bugs in Objective-C and C++ code.</li>
+ <li>Contains a static analyzer newer than Xcode 4.4.</li>
+</ul>
+
+<p>NOTE: this checker build includes a <i>huge</i> number of changes. It has the potential to find many more bugs, but may report new kinds of false positives. We'd like to know about
+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>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 50ec73673c5b..e2ab51fc17c6 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -23,7 +23,7 @@
<!--*************************************************************************-->
<h1>C++98 and C++11 Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2012-05-23 03:38:11 +0200 (Wed, 23 May 2012) $</p>
+<p>Last updated: $Date: 2012-10-23 02:32:41 +0200 (Tue, 23 Oct 2012) $</p>
<h2 id="cxx98">C++98 implementation status</h2>
@@ -41,8 +41,10 @@
<p>You can use Clang in C++11 mode either
with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
Patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
-and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang in
-C++11 mode.</p>
+work with Clang in C++11 mode. Patches are also needed to make
+<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.</p>
<table width="689" border="1" cellspacing="0">
<tr>
diff --git a/www/libstdc++4.6-clang11.patch b/www/libstdc++4.6-clang11.patch
new file mode 100644
index 000000000000..cc2cb1404da5
--- /dev/null
+++ b/www/libstdc++4.6-clang11.patch
@@ -0,0 +1,11 @@
+--- type_traits.orig 2012-10-04 15:20:43.452992946 -0700
++++ type_traits 2012-10-04 15:21:32.423657167 -0700
+@@ -1110,7 +1110,7 @@
+
+ template<typename _Tp, typename _Up>
+ struct common_type<_Tp, _Up>
+- { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; };
++ { typedef typename decay<decltype(true ? declval<_Tp>() : declval<_Up>())>::type type; };
+
+ template<typename _Tp, typename _Up, typename... _Vp>
+ struct common_type<_Tp, _Up, _Vp...>
diff --git a/www/menu.css b/www/menu.css
index 4a887b1907a3..bece0ad3dcd6 100644
--- a/www/menu.css
+++ b/www/menu.css
@@ -8,9 +8,9 @@
}
[id=content] {
/* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
- position:absolute;
- left:29ex;
+ margin-left:29ex;
padding-right:4ex;
+ word-wrap: break-word;
}
/**************/
diff --git a/www/timing-data/2008-10-31/176.gcc-01.txt b/www/timing-data/2008-10-31/176.gcc-01.txt
deleted file mode 100644
index 3809e0d3b299..000000000000
--- a/www/timing-data/2008-10-31/176.gcc-01.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-Title: 176.gcc Timings
-Timestamp: 2008-10-31_17-10
-Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
-Path: /Users/ddunbar/nightlytest/176.gcc
-Runs: 3
-
-LLVM SVN Rev.: 58536
-
-clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
-gcc: /usr/bin/gcc-4.2
-llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
-
-Mode: Eonly Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 0.8321 0.8274 0.8274 0.8435 0.0080 2.4964
- sys 0.4209 0.4140 0.4140 0.4307 0.0071 1.2626
-wall 1.2965 1.2829 1.2829 1.3176 0.0152 3.8894
-
-Mode: Eonly Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 0.8534 0.8465 0.8563 0.8575 0.0050 2.5603
- sys 0.5327 0.5200 0.5291 0.5490 0.0121 1.5980
-wall 1.4336 1.4104 1.4330 1.4575 0.0192 4.3009
-
-Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 1.1313 1.1277 1.1304 1.1359 0.0034 3.3940
- sys 0.5579 0.5530 0.5539 0.5669 0.0063 1.6738
-wall 1.7860 1.7669 1.7890 1.8020 0.0145 5.3580
-
-
-Mode: parse-noop Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 0.9276 0.9267 0.9269 0.9292 0.0011 2.7827
- sys 0.4284 0.4244 0.4255 0.4353 0.0049 1.2852
-wall 1.3994 1.3941 1.3954 1.4086 0.0066 4.1981
-
-
-Mode: disable-free Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.2716 1.2497 1.2713 1.2937 0.0180 3.8147
- sys 0.4835 0.4815 0.4738 0.4953 0.0089 1.4506
-wall 1.8149 1.7838 1.8137 1.8471 0.0259 5.4446
-
-
-Mode: syntax Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.4042 1.4031 1.4044 1.4044 0.0009 4.2127
- sys 0.4818 0.4802 0.4838 0.4838 0.0015 1.4454
-wall 1.9359 1.9333 1.9376 1.9376 0.0019 5.8077
-
-Mode: syntax Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 3.9188 3.8766 3.8846 3.9951 0.0541 11.7563
- sys 1.0207 1.0195 1.0141 1.0285 0.0059 3.0622
-wall 5.0500 5.0023 5.0092 5.1386 0.0627 15.1500
-
-Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 3.8854 3.8647 3.8868 3.9048 0.0164 11.6563
- sys 0.8548 0.8436 0.8455 0.8753 0.0145 2.5644
-wall 4.8695 4.8369 4.8614 4.9103 0.0305 14.6086
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 2.7903 2.7606 2.8026 2.8079 0.0211 8.3710
- sys 0.6645 0.6509 0.6759 0.6667 0.0104 1.9935
-wall 3.5577 3.4894 3.5650 3.6186 0.0530 10.6730
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 4.1711 4.1389 4.1729 4.2015 0.0256 12.5133
- sys 0.9335 0.9339 0.9218 0.9448 0.0094 2.8004
-wall 5.2380 5.1985 5.2417 5.2738 0.0309 15.7140
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 5.2797 5.1709 5.2643 5.4040 0.0958 15.8392
- sys 0.7739 0.7547 0.7726 0.7944 0.0162 2.3217
-wall 6.1807 6.1082 6.1174 6.3165 0.0961 18.5421
- Asm Lines: 735931
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 8.2410 8.1034 8.2230 8.3965 0.1203 24.7230
- sys 1.1924 1.1576 1.2112 1.2082 0.0246 3.5771
-wall 9.6010 9.3792 9.6800 9.7438 0.1590 28.8030
- Asm Lines: 514962
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 6.3978 6.3894 6.3894 6.4726 0.0579 19.1935
- sys 1.0638 1.0562 1.0562 1.0861 0.0160 3.1914
-wall 7.6185 7.5807 7.5807 7.6876 0.0489 22.8555
- Asm Lines: 597193
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.9798 3.9728 3.9752 3.9914 0.0083 11.9393
- sys 0.7313 0.7260 0.7326 0.7353 0.0039 2.1938
-wall 4.7915 4.7799 4.7878 4.8066 0.0112 14.3744
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 5.4838 5.4701 5.4701 5.5172 0.0238 16.4513
- sys 1.0527 1.0401 1.0401 1.0757 0.0163 3.1581
-wall 6.7059 6.6768 6.6768 6.7254 0.0210 20.1177
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 6.8213 6.7836 6.8060 6.8743 0.0386 20.4639
- sys 0.8527 0.8376 0.8598 0.8607 0.0107 2.5582
-wall 7.8055 7.7154 7.8109 7.8902 0.0714 23.4165
- Asm Lines: 1581804
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 8.7962 8.6334 8.7861 8.9691 0.1373 26.3887
- sys 1.2758 1.2395 1.2780 1.3100 0.0288 3.8275
-wall 10.2714 10.1274 10.2232 10.4635 0.1414 30.8142
- Asm Lines: 1403421
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.9903 7.9383 7.9821 8.0504 0.0461 23.9708
- sys 1.1587 1.1374 1.1592 1.1794 0.0171 3.4760
-wall 9.3711 9.2555 9.2884 9.5692 0.1408 28.1132
- Asm Lines: 1580849
-
-
- Done: 2008-10-31_17-16
diff --git a/www/timing-data/2008-10-31/176.gcc-02.txt b/www/timing-data/2008-10-31/176.gcc-02.txt
deleted file mode 100644
index dd898c181068..000000000000
--- a/www/timing-data/2008-10-31/176.gcc-02.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-Title: 176.gcc Timings
-Timestamp: 2008-10-31_17-17
-Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
-Path: /Users/ddunbar/nightlytest/176.gcc
-Runs: 3
-
-LLVM SVN Rev.: 58536
-
-clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
-gcc: /usr/bin/gcc-4.2
-llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
-
-Mode: Eonly Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 0.8238 0.8184 0.8187 0.8342 0.0074 2.4713
- sys 0.4030 0.3891 0.3953 0.4247 0.0155 1.2091
-wall 1.2731 1.2477 1.2565 1.3152 0.0299 3.8194
-
-Mode: Eonly Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 0.8584 0.8501 0.8560 0.8692 0.0080 2.5753
- sys 0.5426 0.5268 0.5453 0.5556 0.0119 1.6277
-wall 1.4485 1.4214 1.4503 1.4737 0.0214 4.3454
-
-Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 1.1289 1.1338 1.1322 1.1207 0.0058 3.3866
- sys 0.5857 0.5787 0.5734 0.6051 0.0138 1.7572
-wall 1.8195 1.8110 1.8124 1.8350 0.0110 5.4585
-
-
-Mode: parse-noop Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 0.9286 0.9250 0.9250 0.9370 0.0059 2.7859
- sys 0.4255 0.4163 0.4163 0.4417 0.0115 1.2764
-wall 1.3970 1.3826 1.3826 1.4241 0.0192 4.1910
-
-
-Mode: disable-free Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.2962 1.2963 1.2963 1.3114 0.0125 3.8885
- sys 0.4842 0.4864 0.4864 0.4901 0.0059 1.4527
-wall 1.8424 1.8356 1.8356 1.8534 0.0078 5.5273
-
-
-Mode: syntax Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.4120 1.4055 1.4118 1.4188 0.0054 4.2360
- sys 0.4824 0.4786 0.4821 0.4864 0.0032 1.4471
-wall 1.9573 1.9467 1.9570 1.9682 0.0088 5.8719
-
-Mode: syntax Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 3.9243 3.8431 3.9624 3.9675 0.0575 11.7730
- sys 1.0094 0.9967 1.0135 1.0180 0.0091 3.0282
-wall 5.0495 4.9447 5.1012 5.1025 0.0741 15.1484
-
-Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 3.9287 3.8760 3.9226 3.9874 0.0457 11.7860
- sys 0.8949 0.8684 0.9014 0.9147 0.0195 2.6846
-wall 4.9625 4.8722 4.9601 5.0550 0.0747 14.8874
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 2.8082 2.7806 2.8106 2.8334 0.0216 8.4246
- sys 0.6608 0.6564 0.6582 0.6677 0.0049 1.9823
-wall 3.5453 3.5150 3.5559 3.5650 0.0218 10.6359
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 4.1471 4.1512 4.1505 4.1395 0.0053 12.4413
- sys 0.9221 0.9069 0.9203 0.9391 0.0132 2.7663
-wall 5.2138 5.1919 5.2001 5.2495 0.0255 15.6415
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 5.1674 5.1537 5.1637 5.1637 0.0129 15.5022
- sys 0.7424 0.7404 0.7376 0.7376 0.0049 2.2271
-wall 6.0284 5.9844 6.0964 6.0964 0.0487 18.0852
- Asm Lines: 735931
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 8.0945 8.0259 8.1235 8.1342 0.0487 24.2835
- sys 1.1599 1.1517 1.1626 1.1654 0.0059 3.4796
-wall 9.4120 9.2935 9.4036 9.5390 0.1004 28.2361
- Asm Lines: 514962
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 6.4405 6.3577 6.4623 6.5014 0.0607 19.3214
- sys 1.0571 1.0454 1.0359 1.0902 0.0237 3.1714
-wall 7.6688 7.5631 7.6376 7.8058 0.1015 23.0065
- Asm Lines: 597193
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.9883 3.9539 3.9626 4.0485 0.0427 11.9650
- sys 0.7333 0.7209 0.7377 0.7413 0.0089 2.1998
-wall 4.8088 4.7485 4.7821 4.8957 0.0630 14.4263
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 5.4875 5.4528 5.5017 5.5017 0.0247 16.4626
- sys 1.0308 1.0231 1.0248 1.0248 0.0097 3.0923
-wall 6.6781 6.6372 6.7006 6.7006 0.0290 20.0342
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 6.7945 6.6664 6.7352 6.9819 0.1355 20.3835
- sys 0.8359 0.8172 0.8329 0.8577 0.0167 2.5077
-wall 7.7458 7.6003 7.7080 7.9290 0.1368 23.2374
- Asm Lines: 1581804
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 8.7280 8.6884 8.7084 8.7870 0.0426 26.1839
- sys 1.3031 1.2940 1.3118 1.3037 0.0073 3.9094
-wall 10.2039 10.1039 10.1162 10.3916 0.1328 30.6116
- Asm Lines: 1403421
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.9987 7.9805 7.9805 8.0493 0.0362 23.9962
- sys 1.1561 1.1523 1.1523 1.1626 0.0047 3.4682
-wall 9.3154 9.2801 9.2801 9.3606 0.0336 27.9463
- Asm Lines: 1580849
-
-
- Done: 2008-10-31_17-23
diff --git a/www/timing-data/2008-10-31/176.gcc.png b/www/timing-data/2008-10-31/176.gcc.png
deleted file mode 100644
index 53efd879312b..000000000000
--- a/www/timing-data/2008-10-31/176.gcc.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2008-10-31/sketch-01.txt b/www/timing-data/2008-10-31/sketch-01.txt
deleted file mode 100644
index ff5d83e1281b..000000000000
--- a/www/timing-data/2008-10-31/sketch-01.txt
+++ /dev/null
@@ -1,187 +0,0 @@
-Title: Sketch Timings
-Timestamp: 2008-10-31_16-46
-Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
-Path: /Users/ddunbar/nightlytest/Sketch.ref
-Runs: 3
-
-LLVM SVN Rev.: 58536
-
-clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
-gcc: /usr/bin/gcc-4.2
-llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
-
-Mode: Eonly Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.3762 1.3711 1.3724 1.3849 0.0062 4.1285
- sys 0.8306 0.8276 0.8274 0.8367 0.0044 2.4917
-wall 2.2290 2.2207 2.2219 2.2445 0.0109 6.6870
-
-Mode: Eonly Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 2.2970 2.2352 2.2374 2.4184 0.0858 6.8910
- sys 1.0716 1.0338 1.0342 1.1470 0.0533 3.2149
-wall 3.4039 3.3027 3.3046 3.6043 0.1417 10.2116
-
-Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 2.8472 2.7770 2.7770 2.9893 0.1005 8.5416
- sys 1.3153 1.2699 1.2699 1.4079 0.0655 3.9460
-wall 4.2134 4.0909 4.0909 4.4421 0.1618 12.6403
-
-
-Mode: parse-noop Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.7295 1.7228 1.7237 1.7421 0.0089 5.1886
- sys 0.8510 0.8468 0.8448 0.8615 0.0074 2.5530
-wall 2.6034 2.5913 2.5914 2.6277 0.0172 7.8103
-
-
-Mode: disable-free Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 2.7310 2.7274 2.7288 2.7288 0.0042 8.1930
- sys 0.9950 0.9890 0.9917 0.9917 0.0068 2.9851
-wall 3.7720 3.7515 3.7866 3.7866 0.0150 11.3161
-
-
-Mode: syntax Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 3.1817 3.1284 3.1620 3.2547 0.0534 9.5451
- sys 1.0815 1.0569 1.0737 1.1138 0.0239 3.2444
-wall 4.2918 4.2129 4.2635 4.3991 0.0786 12.8755
-
-Mode: syntax Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 6.4086 6.3289 6.4012 6.4956 0.0682 19.2258
- sys 1.7617 1.7257 1.7615 1.7979 0.0295 5.2851
-wall 8.2403 8.1235 8.2432 8.3541 0.0942 24.7208
-
-Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 6.9711 6.8657 6.9738 7.0739 0.0850 20.9133
- sys 1.7577 1.7226 1.7801 1.7702 0.0251 5.2730
-wall 8.8020 8.6601 8.8243 8.9216 0.1079 26.4061
-
-Mode: syntax Compiler: gcc PCH: 1 Flags:
-name avg min med max SD total
-user 0.6082 0.6078 0.6083 0.6085 0.0003 1.8245
- sys 0.8901 0.8826 0.8949 0.8927 0.0053 2.6702
-wall 1.5593 1.5558 1.5605 1.5617 0.0025 4.6780
-
-Mode: syntax Compiler: llvm-gcc PCH: 1 Flags:
-name avg min med max SD total
-user 0.6413 0.6409 0.6409 0.6407 0.0008 1.9240
- sys 0.7872 0.7805 0.7805 0.7954 0.0062 2.3615
-wall 1.4837 1.4760 1.4760 1.4877 0.0054 4.4510
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 3.3512 3.2800 3.3205 3.4530 0.0739 10.0535
- sys 1.0991 1.0690 1.0833 1.1450 0.0330 3.2974
-wall 4.4934 4.4015 4.4394 4.6392 0.1043 13.4801
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 7.1104 7.0581 7.1061 7.1670 0.0446 21.3311
- sys 1.7621 1.7462 1.7556 1.7845 0.0163 5.2863
-wall 8.9510 8.8993 8.9352 9.0187 0.0500 26.8531
-
-Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 0.8446 0.8300 0.8499 0.8538 0.0104 2.5338
- sys 0.8742 0.8366 0.8861 0.9000 0.0272 2.6227
-wall 1.7871 1.7366 1.8046 1.8201 0.0362 5.3613
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 3.4794 3.4750 3.4794 3.4794 0.0035 10.4381
- sys 1.0876 1.0817 1.0874 1.0874 0.0049 3.2628
-wall 4.6112 4.5958 4.6223 4.6223 0.0112 13.8337
- Asm Lines: 46279
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 6.8875 6.7735 6.8748 7.0143 0.0987 20.6626
- sys 1.8035 1.7586 1.8049 1.8472 0.0362 5.4106
-wall 8.7785 8.6100 8.7574 8.9682 0.1470 26.3356
- Asm Lines: 41008
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 7.3392 7.2327 7.3071 7.4779 0.1026 22.0176
- sys 1.8018 1.7703 1.7930 1.8420 0.0299 5.4053
-wall 9.2274 9.0793 9.1968 9.4062 0.1352 27.6823
- Asm Lines: 47243
-
-Mode: asm Compiler: gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 1.0485 1.0361 1.0429 1.0666 0.0131 3.1456
- sys 1.0277 1.0097 1.0437 1.0296 0.0140 3.0830
-wall 2.1621 2.1181 2.1496 2.2185 0.0419 6.4862
- Asm Lines: 41001
-
-Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 0.9927 0.9898 0.9932 0.9951 0.0022 2.9781
- sys 0.8640 0.8529 0.8610 0.8781 0.0105 2.5920
-wall 1.9183 1.9041 1.9193 1.9315 0.0112 5.7550
- Asm Lines: 47238
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.3843 3.3639 3.3719 3.4173 0.0235 10.1530
- sys 1.0862 1.0743 1.0789 1.1053 0.0136 3.2585
-wall 4.5248 4.4754 4.4906 4.6084 0.0595 13.5744
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.4463 7.3855 7.3897 7.5638 0.0831 22.3390
- sys 1.7927 1.7653 1.7841 1.8286 0.0265 5.3780
-wall 9.3259 9.2350 9.2660 9.4767 0.1074 27.9777
-
-Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.1532 1.1527 1.1527 1.1556 0.0018 3.4596
- sys 0.8746 0.8663 0.8663 0.8774 0.0060 2.6238
-wall 2.1168 2.0914 2.0914 2.1464 0.0226 6.3503
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.6819 3.5955 3.7080 3.7422 0.0627 11.0458
- sys 1.1386 1.0879 1.1480 1.1798 0.0381 3.4158
-wall 4.8606 4.7204 4.8947 4.9668 0.1034 14.5819
- Asm Lines: 106056
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.9271 7.8581 7.8581 8.0696 0.1008 23.7814
- sys 2.0275 1.9943 1.9943 2.0711 0.0322 6.0826
-wall 10.0313 9.9266 9.9266 10.2314 0.1415 30.0939
- Asm Lines: 177342
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.7083 7.6793 7.6941 7.6941 0.0312 23.1249
- sys 1.8122 1.7971 1.8204 1.8204 0.0107 5.4365
-wall 9.6227 9.5591 9.6555 9.6555 0.0450 28.8682
- Asm Lines: 203358
-
-Mode: asm Compiler: gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.2589 1.2129 1.2130 1.3509 0.0650 3.7767
- sys 1.2141 1.1467 1.1601 1.3355 0.0860 3.6423
-wall 2.5426 2.4325 2.4357 2.7596 0.1534 7.6278
- Asm Lines: 177335
-
-Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.4234 1.3843 1.4009 1.4849 0.0440 4.2701
- sys 0.9822 0.9153 0.9446 1.0867 0.0749 2.9466
-wall 2.4856 2.3713 2.4482 2.6372 0.1117 7.4567
- Asm Lines: 203353
-
-
- Done: 2008-10-31_16-55
diff --git a/www/timing-data/2008-10-31/sketch-02.txt b/www/timing-data/2008-10-31/sketch-02.txt
deleted file mode 100644
index 88af3267ea61..000000000000
--- a/www/timing-data/2008-10-31/sketch-02.txt
+++ /dev/null
@@ -1,187 +0,0 @@
-Title: Sketch Timings
-Timestamp: 2008-10-31_16-59
-Uname: Darwin lordcrumb.apple.com 10.0.0d3 Darwin Kernel Version 10.0.0d3: Fri Oct 24 02:12:11 PDT 2008; root:xnu-1353~2/RELEASE_I386 i386
-Path: /Users/ddunbar/nightlytest/Sketch.ref
-Runs: 3
-
-LLVM SVN Rev.: 58536
-
-clang: /Users/ddunbar/llvm/Release-Asserts/bin//clang
-gcc: /usr/bin/gcc-4.2
-llvm-gcc: /Users/ddunbar/llvm-gcc/install/bin/llvm-gcc
-
-Mode: Eonly Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.4030 1.3765 1.3887 1.4437 0.0293 4.2089
- sys 0.8561 0.8388 0.8497 0.8796 0.0173 2.5682
-wall 2.2809 2.2373 2.2586 2.3468 0.0474 6.8426
-
-Mode: Eonly Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 2.3041 2.2821 2.2821 2.3563 0.0371 6.9123
- sys 1.0772 1.0593 1.0593 1.0976 0.0157 3.2316
-wall 3.4323 3.3918 3.3918 3.4905 0.0422 10.2970
-
-Mode: Eonly Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 2.7593 2.7038 2.7831 2.7831 0.0393 8.2778
- sys 1.2805 1.2605 1.2868 1.2868 0.0144 3.8414
-wall 4.0893 4.0056 4.1319 4.1319 0.0592 12.2679
-
-
-Mode: parse-noop Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 1.7430 1.7252 1.7429 1.7610 0.0146 5.2291
- sys 0.8573 0.8457 0.8605 0.8656 0.0085 2.5718
-wall 2.6237 2.5942 2.6266 2.6504 0.0230 7.8711
-
-
-Mode: disable-free Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 2.7684 2.7291 2.7310 2.8450 0.0542 8.3051
- sys 1.0088 0.9948 0.9960 1.0356 0.0189 3.0263
-wall 3.8203 3.7581 3.7635 3.9394 0.0842 11.4610
-
-
-Mode: syntax Compiler: clang PCH: 0 Flags:
-name avg min med max SD total
-user 3.1106 3.1115 3.1107 3.1095 0.0008 9.3317
- sys 1.0674 1.0630 1.0672 1.0721 0.0037 3.2022
-wall 4.2059 4.2015 4.2077 4.2085 0.0031 12.6176
-
-Mode: syntax Compiler: gcc PCH: 0 Flags:
-name avg min med max SD total
-user 6.4166 6.3461 6.4479 6.4559 0.0500 19.2499
- sys 1.7649 1.7256 1.7836 1.7854 0.0278 5.2946
-wall 8.2536 8.1547 8.3018 8.3045 0.0700 24.7609
-
-Mode: syntax Compiler: llvm-gcc PCH: 0 Flags:
-name avg min med max SD total
-user 7.0297 6.9018 7.0003 7.1869 0.1182 21.0890
- sys 1.7782 1.7336 1.7875 1.8136 0.0333 5.3347
-wall 8.8942 8.7128 8.8699 9.0999 0.1590 26.6826
-
-Mode: syntax Compiler: gcc PCH: 1 Flags:
-name avg min med max SD total
-user 0.6133 0.6065 0.6089 0.6244 0.0079 1.8398
- sys 0.9115 0.8880 0.9019 0.9446 0.0241 2.7345
-wall 1.5864 1.5593 1.5669 1.6330 0.0331 4.7592
-
-Mode: syntax Compiler: llvm-gcc PCH: 1 Flags:
-name avg min med max SD total
-user 0.6412 0.6387 0.6387 0.6477 0.0047 1.9235
- sys 0.7820 0.7654 0.7654 0.7955 0.0125 2.3461
-wall 1.4909 1.4783 1.4783 1.5124 0.0153 4.4726
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 3.2926 3.2939 3.2939 3.2998 0.0065 9.8778
- sys 1.0746 1.0728 1.0728 1.0793 0.0034 3.2237
-wall 4.4097 4.4045 4.4045 4.4150 0.0043 13.2290
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 7.3232 7.2559 7.3145 7.3991 0.0588 21.9695
- sys 1.8050 1.7967 1.7982 1.8201 0.0107 5.4151
-wall 9.2155 9.1243 9.2130 9.3092 0.0755 27.6465
-
-Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 0.8337 0.8288 0.8288 0.8444 0.0076 2.5011
- sys 0.8575 0.8484 0.8484 0.8773 0.0140 2.5725
-wall 1.7973 1.7406 1.7406 1.9054 0.0764 5.3919
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0
-name avg min med max SD total
-user 3.4909 3.4823 3.4896 3.4896 0.0077 10.4728
- sys 1.0997 1.1027 1.1028 1.1028 0.0043 3.2991
-wall 4.6332 4.6179 4.6483 4.6483 0.0124 13.8996
- Asm Lines: 46279
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 6.8956 6.7882 6.9057 6.9929 0.0839 20.6868
- sys 1.7978 1.7703 1.7928 1.8302 0.0247 5.3933
-wall 8.7724 8.6360 8.7818 8.8994 0.1077 26.3172
- Asm Lines: 41008
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0
-name avg min med max SD total
-user 7.2722 7.2087 7.3014 7.3014 0.0450 21.8167
- sys 1.8020 1.7828 1.8083 1.8083 0.0139 5.4060
-wall 9.1527 9.0609 9.2011 9.2011 0.0650 27.4582
- Asm Lines: 47243
-
-Mode: asm Compiler: gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 1.0563 1.0337 1.0373 1.0979 0.0294 3.1689
- sys 1.0249 0.9862 0.9837 1.1048 0.0565 3.0747
-wall 2.1458 2.0764 2.0838 2.2772 0.0930 6.4374
- Asm Lines: 41001
-
-Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0
-name avg min med max SD total
-user 0.9983 0.9929 0.9929 1.0110 0.0090 2.9950
- sys 0.8616 0.8525 0.8525 0.8822 0.0146 2.5849
-wall 1.9268 1.9061 1.9061 1.9632 0.0259 5.7804
- Asm Lines: 47238
-
-
-Mode: llvm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.4344 3.3999 3.4302 3.4730 0.0300 10.3032
- sys 1.1155 1.0881 1.1394 1.1191 0.0211 3.3466
-wall 4.5875 4.5279 4.6054 4.6292 0.0432 13.7626
-
-Mode: llvm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.5996 7.5021 7.5389 7.7578 0.1129 22.7988
- sys 1.8546 1.8469 1.8262 1.8908 0.0270 5.5639
-wall 9.5392 9.4246 9.4575 9.7353 0.1394 28.6175
-
-Mode: llvm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.1556 1.1512 1.1542 1.1542 0.0042 3.4667
- sys 0.9021 0.8890 0.8971 0.8971 0.0131 2.7062
-wall 2.1308 2.1126 2.1487 2.1487 0.0147 6.3924
-
-
-Mode: asm Compiler: clang PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 3.6020 3.5895 3.5904 3.6259 0.0169 10.8059
- sys 1.0967 1.0879 1.0879 1.1143 0.0124 3.2901
-wall 4.7362 4.7169 4.7182 4.7736 0.0264 14.2087
- Asm Lines: 106056
-
-Mode: asm Compiler: gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 8.0264 7.8409 8.0350 8.2033 0.1481 24.0792
- sys 2.0315 1.9767 2.0315 2.0864 0.0448 6.0946
-wall 10.1477 9.9000 10.1584 10.3846 0.1980 30.4430
- Asm Lines: 177342
-
-Mode: asm Compiler: llvm-gcc PCH: 0 Flags: -O0 -g
-name avg min med max SD total
-user 7.8449 7.8189 7.8471 7.8687 0.0204 23.5346
- sys 1.8727 1.8768 1.8539 1.8874 0.0140 5.6181
-wall 9.8164 9.7803 9.8029 9.8661 0.0363 29.4492
- Asm Lines: 203358
-
-Mode: asm Compiler: gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.2216 1.2137 1.2168 1.2342 0.0090 3.6647
- sys 1.1771 1.1627 1.1630 1.2055 0.0201 3.5312
-wall 2.4619 2.4419 2.4429 2.5008 0.0275 7.3856
- Asm Lines: 177335
-
-Mode: asm Compiler: llvm-gcc PCH: 1 Flags: -O0 -g
-name avg min med max SD total
-user 1.3980 1.3682 1.3688 1.4569 0.0416 4.1939
- sys 0.9354 0.8951 0.9181 0.9930 0.0418 2.8062
-wall 2.4380 2.3312 2.3606 2.6224 0.1309 7.3141
- Asm Lines: 203353
-
-
- Done: 2008-10-31_17-08
diff --git a/www/timing-data/2008-10-31/sketch.png b/www/timing-data/2008-10-31/sketch.png
deleted file mode 100644
index 5ce3b11087ac..000000000000
--- a/www/timing-data/2008-10-31/sketch.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.pdf b/www/timing-data/2009-03-02/176.gcc.pdf
deleted file mode 100644
index 0b2e610d085a..000000000000
--- a/www/timing-data/2009-03-02/176.gcc.pdf
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.png b/www/timing-data/2009-03-02/176.gcc.png
deleted file mode 100644
index 4ae08e11adc4..000000000000
--- a/www/timing-data/2009-03-02/176.gcc.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-03-02/176.gcc.txt b/www/timing-data/2009-03-02/176.gcc.txt
deleted file mode 100644
index f965e9729e6a..000000000000
--- a/www/timing-data/2009-03-02/176.gcc.txt
+++ /dev/null
@@ -1,1120 +0,0 @@
-ccc_path = """/Volumes/Data/ddunbar/llvm.install/bin/ccc"""
-ccc_clang = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb"""
-ccc_gcc = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb -ccc-no-clang"""
-gcc = """/usr/bin/gcc-4.2"""
-ccc_clang_info = """
-ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
- "/Volumes/Data/ddunbar/llvm.install/bin/clang" "-S" "-disable-free" "--relocation-model=pic" "--disable-fp-elim" "--nozero-initialized-in-bss" "--unwind-tables=1" "--mcpu=core2" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-arch" "x86_64" "-o" "/tmp/tmp62ee6x.s" "-x" "c" "/dev/null"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpyLxO26.o" "/tmp/tmp62ee6x.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpyLxO26.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
-"""
-ccc_gcc_info = """
-ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/tmp/tmpDx0Rtr.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpNbvYrM.o" "/tmp/tmpDx0Rtr.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpNbvYrM.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
-"""
-gcc_info = """
-Using built-in specs.
-Target: i686-apple-darwin10
-Configured with: /var/tmp/gcc/gcc-5641~3/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
-Thread model: posix
-gcc version 4.2.1 (Apple Inc. build 5641)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/tmp//ccDnCoVC.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/tmp//ccwsOXBR.o" "/var/tmp//ccDnCoVC.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/tmp//ccwsOXBR.o" "-lgcc" "-lSystem"
-"""
-style = """make"""
-runs = []
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.041626, 0.067272, 0.122191),
- (1, 0.041643, 0.067045, 0.122192),
- (2, 0.041655, 0.067055, 0.121649),
- (3, 0.041562, 0.066648, 0.121432),
- (4, 0.041613, 0.066810, 0.121305),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.041606, 0.066993, 0.121704),
- (1, 0.041581, 0.066630, 0.121471),
- (2, 0.041602, 0.066922, 0.121765),
- (3, 0.041581, 0.066859, 0.121405),
- (4, 0.041689, 0.066980, 0.124326),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.041675, 0.067138, 0.121728),
- (1, 0.041612, 0.066859, 0.121205),
- (2, 0.041580, 0.066483, 0.120964),
- (3, 0.041594, 0.066483, 0.120985),
- (4, 0.041568, 0.066532, 0.120499),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.186639, 1.937014, 4.437061),
- (1, 2.186681, 1.945610, 4.433872),
- (2, 2.188041, 1.947231, 4.462319),
- (3, 2.188190, 1.943516, 4.470365),
- (4, 2.187020, 1.950682, 4.436890),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.195748, 1.947951, 4.443053),
- (1, 2.194402, 1.940449, 4.432535),
- (2, 2.195423, 1.943498, 4.447053),
- (3, 2.196253, 1.950332, 4.448664),
- (4, 2.195660, 1.942226, 4.437071),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.136111, 0.313413, 0.499384),
- (1, 0.136203, 0.313310, 0.500697),
- (2, 0.136639, 0.314917, 0.558877),
- (3, 0.136173, 0.313843, 0.501008),
- (4, 0.135965, 0.312723, 0.498594),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.819676, 2.374582, 5.801642),
- (1, 2.819568, 2.375962, 5.525720),
- (2, 2.819725, 2.377977, 5.526612),
- (3, 2.819563, 2.374766, 5.525245),
- (4, 2.820020, 2.378179, 5.531853),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.979842, 2.393759, 5.773241),
- (1, 2.978360, 2.388217, 5.699588),
- (2, 2.979615, 2.392749, 5.713015),
- (3, 2.978055, 2.388861, 5.697303),
- (4, 2.979260, 2.390138, 5.710568),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.525414, 2.495433, 6.457547),
- (1, 3.523990, 2.498728, 6.378505),
- (2, 3.523183, 2.492712, 6.370535),
- (3, 3.523363, 2.494413, 6.376960),
- (4, 3.525216, 2.501657, 6.413753),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.143927, 2.857721, 9.407785),
- (1, 6.144766, 2.871091, 9.396498),
- (2, 6.143893, 2.860256, 9.392155),
- (3, 6.146454, 2.866420, 9.447510),
- (4, 6.146771, 2.864488, 9.664806),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.975961, 1.044303, 5.199328),
- (1, 3.976843, 1.044060, 5.209434),
- (2, 3.976622, 1.043787, 5.223585),
- (3, 3.975836, 1.043403, 5.198575),
- (4, 3.975980, 1.035674, 5.196275),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.707728, 2.859466, 9.115580),
- (1, 5.709064, 2.858221, 9.094858),
- (2, 5.707868, 2.868881, 9.006296),
- (3, 5.706836, 2.856589, 8.998487),
- (4, 5.706603, 2.857047, 9.028045),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.855523, 3.041195, 11.679531),
- (1, 7.855184, 3.046897, 11.389012),
- (2, 7.855530, 3.039149, 11.435265),
- (3, 7.856299, 3.037483, 11.382391),
- (4, 7.854147, 3.043133, 11.373174),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.926280, 3.168833, 14.542014),
- (1, 10.931726, 3.174573, 14.573554),
- (2, 10.933809, 3.163183, 14.857843),
- (3, 10.927966, 3.164824, 14.543822),
- (4, 10.927423, 3.166222, 14.658131),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.755856, 1.342961, 10.311273),
- (1, 8.756782, 1.346296, 10.314137),
- (2, 8.760167, 1.338744, 10.442545),
- (3, 8.759031, 1.346241, 10.333765),
- (4, 8.758174, 1.339294, 10.328992),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.159773, 3.431851, 13.319311),
- (1, 9.156190, 3.421113, 13.203571),
- (2, 9.157752, 3.417859, 13.220865),
- (3, 9.156178, 3.413504, 13.204341),
- (4, 9.150167, 3.412242, 13.252471),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.062994, 3.497204, 16.184210),
- (1, 12.065757, 3.486858, 16.503552),
- (2, 12.063830, 3.499430, 16.171503),
- (3, 12.065427, 3.500838, 16.268848),
- (4, 12.063384, 3.503007, 16.164980),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.836694, 1.570806, 11.863629),
- (1, 9.835162, 1.580921, 11.762224),
- (2, 9.836416, 1.572111, 11.893337),
- (3, 9.835066, 1.571860, 11.751330),
- (4, 9.836771, 1.575158, 11.783299),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.262905, 3.437217, 13.459870),
- (1, 9.262539, 3.446216, 13.349994),
- (2, 9.260750, 3.445077, 13.357125),
- (3, 9.263932, 3.448647, 13.366228),
- (4, 9.258133, 3.443125, 13.369278),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.163348, 3.513017, 16.559292),
- (1, 12.159476, 3.526493, 16.430252),
- (2, 12.157784, 3.513763, 16.306505),
- (3, 12.159307, 3.530832, 16.495815),
- (4, 12.160843, 3.516564, 16.331499),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.945925, 1.592199, 11.971326),
- (1, 9.944375, 1.603629, 11.899797),
- (2, 9.945863, 1.601172, 11.917642),
- (3, 9.946878, 1.601530, 12.113196),
- (4, 9.943168, 1.596300, 11.910257),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.042234, 0.072110, 0.068216),
- (1, 0.042155, 0.071582, 0.067917),
- (2, 0.042120, 0.071280, 0.067838),
- (3, 0.042134, 0.071281, 0.067688),
- (4, 0.042182, 0.071185, 0.068571),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.042195, 0.072394, 0.067753),
- (1, 0.042154, 0.071378, 0.067667),
- (2, 0.042126, 0.071503, 0.067645),
- (3, 0.042142, 0.071525, 0.067641),
- (4, 0.042137, 0.071263, 0.067512),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.042117, 0.071863, 0.067866),
- (1, 0.042095, 0.071587, 0.067778),
- (2, 0.042123, 0.071824, 0.067718),
- (3, 0.042017, 0.071448, 0.067336),
- (4, 0.042098, 0.071669, 0.067649),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.312764, 2.250083, 2.579668),
- (1, 2.313524, 2.255599, 2.581617),
- (2, 2.314576, 2.236269, 2.751308),
- (3, 2.313798, 2.247632, 2.576000),
- (4, 2.308146, 2.127675, 2.449384),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.319161, 2.248583, 2.579843),
- (1, 2.320569, 2.254949, 2.582595),
- (2, 2.319615, 2.254838, 2.582868),
- (3, 2.317640, 2.234440, 2.566378),
- (4, 2.319468, 2.253768, 2.582185),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.138760, 0.342468, 0.274713),
- (1, 0.138529, 0.338083, 0.270603),
- (2, 0.138419, 0.339997, 0.272035),
- (3, 0.138474, 0.339942, 0.271676),
- (4, 0.138476, 0.339545, 0.271208),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.927601, 2.621882, 3.040263),
- (1, 2.928817, 2.618327, 3.042979),
- (2, 2.925842, 2.616328, 3.034669),
- (3, 2.933845, 2.642455, 3.077028),
- (4, 2.947212, 2.620121, 3.167388),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.095391, 2.632837, 3.130378),
- (1, 3.096120, 2.626309, 3.120448),
- (2, 3.095708, 2.622912, 3.125333),
- (3, 3.096435, 2.628234, 3.124718),
- (4, 3.095836, 2.623590, 3.124194),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.674570, 2.716479, 3.444615),
- (1, 3.673243, 2.720120, 3.443432),
- (2, 3.673080, 2.709820, 3.443546),
- (3, 3.673200, 2.709185, 3.426130),
- (4, 3.670534, 2.711744, 3.427015),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.389665, 3.072630, 4.983543),
- (1, 6.385878, 3.080763, 4.975980),
- (2, 6.389956, 3.069652, 4.982242),
- (3, 6.388396, 3.078156, 4.977871),
- (4, 6.391305, 3.090905, 4.994381),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.079359, 1.112710, 2.692685),
- (1, 4.077052, 1.114109, 2.689234),
- (2, 4.078218, 1.119202, 2.693919),
- (3, 4.077124, 1.108491, 2.690559),
- (4, 4.077296, 1.112142, 2.684408),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.043907, 3.082369, 4.874229),
- (1, 6.044110, 3.072240, 4.860724),
- (2, 6.049991, 3.085666, 4.927778),
- (3, 6.050681, 3.087747, 4.866959),
- (4, 6.046383, 3.081174, 4.865700),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.277376, 3.241075, 6.041627),
- (1, 8.274767, 3.246052, 6.032635),
- (2, 8.273632, 3.240323, 6.034355),
- (3, 8.283322, 3.235898, 6.055232),
- (4, 8.279572, 3.237813, 6.040545),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 11.267468, 3.368598, 7.582008),
- (1, 11.264991, 3.356817, 7.573902),
- (2, 11.258736, 3.371794, 7.616322),
- (3, 11.272174, 3.375177, 7.750662),
- (4, 11.265369, 3.355828, 7.569228),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.948892, 1.408841, 5.346675),
- (1, 8.947425, 1.388794, 5.341078),
- (2, 8.959290, 1.397633, 5.703015),
- (3, 8.948915, 1.391639, 5.351654),
- (4, 8.946706, 1.404458, 5.345449),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.576401, 3.659016, 6.972346),
- (1, 9.577255, 3.641158, 6.953448),
- (2, 9.572443, 3.647954, 7.051130),
- (3, 9.571615, 3.646782, 6.956555),
- (4, 9.572963, 3.653229, 6.957711),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.425333, 3.720605, 8.468826),
- (1, 12.420657, 3.729020, 8.648778),
- (2, 12.424221, 3.709511, 8.467562),
- (3, 12.425595, 3.726297, 8.449276),
- (4, 12.422584, 3.718660, 8.713483),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.042865, 1.647364, 6.147098),
- (1, 10.038624, 1.646965, 6.107788),
- (2, 10.036193, 1.643319, 6.100944),
- (3, 10.037764, 1.637319, 6.121365),
- (4, 10.044532, 1.648919, 6.354301),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.686781, 3.657538, 7.098294),
- (1, 9.679355, 3.674326, 7.109849),
- (2, 9.678938, 3.659032, 7.093127),
- (3, 9.683371, 3.655282, 7.396885),
- (4, 9.677578, 3.661111, 7.086666),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.511083, 3.753316, 8.574587),
- (1, 12.517391, 3.745202, 8.579089),
- (2, 12.515167, 3.747517, 8.906780),
- (3, 12.510503, 3.744116, 8.561728),
- (4, 12.516263, 3.740046, 8.578455),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.139224, 1.659640, 6.213839),
- (1, 10.144829, 1.668260, 6.423697),
- (2, 10.144182, 1.670476, 6.213931),
- (3, 10.144068, 1.658834, 6.211693),
- (4, 10.138223, 1.667654, 6.222308),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.044057, 0.093485, 0.045956),
- (1, 0.044004, 0.092769, 0.045605),
- (2, 0.043901, 0.092551, 0.045247),
- (3, 0.043818, 0.091785, 0.045295),
- (4, 0.043924, 0.091899, 0.045216),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.043938, 0.092531, 0.045317),
- (1, 0.043985, 0.092990, 0.045413),
- (2, 0.043847, 0.091943, 0.044986),
- (3, 0.043889, 0.091626, 0.045207),
- (4, 0.043936, 0.091446, 0.045068),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.043935, 0.092137, 0.045550),
- (1, 0.044036, 0.092432, 0.045443),
- (2, 0.043907, 0.092597, 0.045207),
- (3, 0.043906, 0.092773, 0.045220),
- (4, 0.043932, 0.092273, 0.045162),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.510229, 2.524326, 1.447378),
- (1, 2.511153, 2.582682, 1.463158),
- (2, 2.509131, 2.551808, 1.443700),
- (3, 2.530506, 2.606601, 1.631594),
- (4, 2.525546, 2.556516, 1.460912),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.519330, 2.572381, 1.455862),
- (1, 2.519059, 2.662137, 1.521106),
- (2, 2.506144, 2.556738, 1.456221),
- (3, 2.511366, 2.577441, 1.459606),
- (4, 2.526218, 2.553722, 1.574747),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.147023, 0.430956, 0.176525),
- (1, 0.147430, 0.429136, 0.175834),
- (2, 0.146893, 0.428812, 0.175145),
- (3, 0.147174, 0.429968, 0.175169),
- (4, 0.147492, 0.431385, 0.174682),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.167799, 3.158706, 1.805685),
- (1, 3.167239, 3.135936, 1.802571),
- (2, 3.157960, 3.130196, 1.803330),
- (3, 3.146711, 3.153077, 1.813078),
- (4, 3.149927, 3.152081, 1.801526),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.342516, 3.109718, 1.823208),
- (1, 3.353297, 3.103074, 1.819566),
- (2, 3.333260, 3.149734, 1.829796),
- (3, 3.338234, 3.103725, 1.822010),
- (4, 3.336550, 3.100652, 1.832110),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.970523, 3.209725, 1.991844),
- (1, 3.937210, 3.198855, 1.976041),
- (2, 3.955488, 3.206959, 1.989544),
- (3, 3.946574, 3.198149, 1.980601),
- (4, 3.948581, 3.205880, 1.983994),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.732216, 3.619584, 2.782476),
- (1, 6.745420, 3.616948, 2.790903),
- (2, 6.750526, 3.594650, 2.790881),
- (3, 6.738845, 3.612443, 2.790569),
- (4, 6.747457, 3.617553, 2.788687),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.194680, 1.292044, 1.444048),
- (1, 4.190321, 1.300927, 1.441506),
- (2, 4.198820, 1.293219, 1.444174),
- (3, 4.209445, 1.289162, 1.447259),
- (4, 4.187489, 1.282234, 1.440277),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.517757, 3.615464, 2.854763),
- (1, 6.519460, 3.617775, 2.756124),
- (2, 6.498704, 3.602169, 2.756365),
- (3, 6.509982, 3.621462, 2.745702),
- (4, 6.489827, 3.608797, 2.747793),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.825143, 3.794072, 3.362608),
- (1, 8.824013, 3.765690, 3.355471),
- (2, 8.813541, 3.783641, 3.357039),
- (3, 8.786371, 3.786659, 3.345793),
- (4, 8.772730, 3.771638, 3.454307),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 11.738484, 3.836784, 4.120546),
- (1, 11.739288, 3.848616, 4.125808),
- (2, 11.738261, 3.837534, 4.136642),
- (3, 11.735003, 3.844597, 4.120444),
- (4, 11.761638, 3.862457, 4.145417),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.155087, 1.561075, 2.833868),
- (1, 9.154934, 1.538791, 2.833134),
- (2, 9.183035, 1.553281, 2.902132),
- (3, 9.151130, 1.546822, 2.879777),
- (4, 9.151844, 1.542450, 2.825560),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.166988, 4.242308, 3.894601),
- (1, 10.218686, 4.265537, 3.896997),
- (2, 10.208211, 4.256174, 3.905990),
- (3, 10.182169, 4.254989, 4.094963),
- (4, 10.165336, 4.239672, 3.873703),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.960833, 4.319633, 4.628599),
- (1, 12.997509, 4.323695, 4.942418),
- (2, 12.940625, 4.326994, 4.624419),
- (3, 12.947641, 4.300034, 4.597456),
- (4, 12.942562, 4.308688, 4.619190),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.300396, 1.823967, 3.250894),
- (1, 10.305252, 1.822285, 3.244746),
- (2, 10.307011, 1.845773, 3.260861),
- (3, 10.319953, 1.831435, 3.500671),
- (4, 10.320805, 1.834782, 3.246639),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.297812, 4.264184, 4.013061),
- (1, 10.315407, 4.293257, 4.021099),
- (2, 10.257966, 4.265659, 4.006248),
- (3, 10.307857, 4.273741, 4.044614),
- (4, 10.273398, 4.260286, 4.216469),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 13.040233, 4.302015, 4.719135),
- (1, 13.046999, 4.316412, 5.773880),
- (2, 13.081143, 4.324329, 4.745519),
- (3, 13.025611, 4.311093, 4.738916),
- (4, 13.063041, 4.336277, 4.771969),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.419745, 1.855515, 3.343652),
- (1, 10.447391, 1.858839, 3.374031),
- (2, 10.428436, 1.866242, 3.381289),
- (3, 10.428931, 1.879273, 3.582034),
- (4, 10.410715, 1.836761, 3.371333),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.044629, 0.104236, 0.047124),
- (1, 0.044357, 0.101072, 0.046054),
- (2, 0.044261, 0.099350, 0.045512),
- (3, 0.044279, 0.099032, 0.045401),
- (4, 0.044291, 0.098233, 0.045262),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.044388, 0.101047, 0.045972),
- (1, 0.044267, 0.100816, 0.045836),
- (2, 0.044319, 0.100931, 0.045829),
- (3, 0.044242, 0.102208, 0.046286),
- (4, 0.044197, 0.101894, 0.046310),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.044199, 0.099476, 0.045336),
- (1, 0.044064, 0.099032, 0.045431),
- (2, 0.044081, 0.097169, 0.044910),
- (3, 0.044055, 0.099088, 0.044957),
- (4, 0.044322, 0.099454, 0.045563),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.768949, 3.566605, 1.008622),
- (1, 2.753933, 3.515221, 1.011067),
- (2, 2.790210, 3.581213, 1.006835),
- (3, 2.742393, 3.612996, 1.065939),
- (4, 2.783563, 3.457715, 0.977203),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.803126, 3.542212, 1.140376),
- (1, 2.794538, 3.523127, 1.000266),
- (2, 2.821545, 3.533185, 0.996633),
- (3, 2.754702, 3.604113, 1.127400),
- (4, 2.773800, 3.590831, 1.023085),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.162694, 0.629660, 0.131824),
- (1, 0.162231, 0.630903, 0.131937),
- (2, 0.162713, 0.636833, 0.133010),
- (3, 0.163527, 0.627696, 0.130973),
- (4, 0.162591, 0.628073, 0.128269),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.398995, 4.386961, 1.222372),
- (1, 3.433913, 4.302404, 1.191109),
- (2, 3.403972, 4.249079, 1.179600),
- (3, 3.430418, 4.241026, 1.173406),
- (4, 3.405708, 4.295249, 1.192367),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.589608, 4.234909, 1.206952),
- (1, 3.595580, 4.250801, 1.195809),
- (2, 3.598782, 4.186360, 1.189533),
- (3, 3.576135, 4.210771, 1.192198),
- (4, 3.596508, 4.272774, 1.195682),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.188318, 4.323380, 1.272841),
- (1, 4.204432, 4.301331, 1.276169),
- (2, 4.232123, 4.359346, 1.308850),
- (3, 4.254709, 4.295013, 1.277959),
- (4, 4.214074, 4.293825, 1.275462),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.056727, 4.672983, 1.677022),
- (1, 7.064183, 4.697158, 1.685536),
- (2, 7.013256, 4.653804, 1.669026),
- (3, 7.077917, 4.720479, 1.692836),
- (4, 7.028864, 4.654591, 1.674130),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.250811, 1.598520, 0.822128),
- (1, 4.255341, 1.616523, 0.819562),
- (2, 4.282720, 1.628032, 0.823764),
- (3, 4.296236, 1.628292, 0.828753),
- (4, 4.263254, 1.614337, 0.822968),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.828563, 4.698920, 1.665128),
- (1, 6.887088, 4.678607, 1.660858),
- (2, 6.867776, 4.703203, 1.657673),
- (3, 6.841523, 4.645255, 1.637169),
- (4, 6.904172, 4.682556, 1.690968),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.164624, 4.728257, 2.026243),
- (1, 9.258789, 4.757386, 1.996115),
- (2, 9.215979, 4.740186, 1.995604),
- (3, 9.241390, 4.750833, 2.007054),
- (4, 9.161773, 4.742841, 1.987729),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 12.113609, 4.726450, 2.385739),
- (1, 12.121322, 4.784194, 2.416434),
- (2, 12.095256, 4.762198, 2.394130),
- (3, 12.125848, 4.743744, 2.386863),
- (4, 12.117883, 4.759723, 2.384746),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.196017, 1.794764, 1.538604),
- (1, 9.293693, 1.830825, 1.559088),
- (2, 9.210498, 1.813935, 1.538989),
- (3, 9.207860, 1.799598, 1.536893),
- (4, 9.202729, 1.797648, 1.530905),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.574802, 5.298921, 2.539728),
- (1, 10.657320, 5.376201, 2.329437),
- (2, 10.650595, 5.345177, 2.311878),
- (3, 10.611628, 5.366770, 2.319432),
- (4, 10.599574, 5.358888, 2.479782),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 13.432160, 5.417611, 2.691172),
- (1, 13.443341, 5.377409, 2.678012),
- (2, 13.343336, 5.338212, 2.812471),
- (3, 13.333183, 5.333529, 2.687594),
- (4, 13.384371, 5.414969, 2.837339),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.381974, 2.152140, 1.786428),
- (1, 10.378996, 2.143003, 1.774503),
- (2, 10.453921, 2.187323, 1.794154),
- (3, 10.398109, 2.212740, 2.013101),
- (4, 10.435604, 2.197729, 1.779200),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.786656, 5.383657, 2.435159),
- (1, 10.689933, 5.362047, 2.435158),
- (2, 10.761754, 5.406655, 2.462640),
- (3, 10.760319, 5.401706, 2.571526),
- (4, 10.666932, 5.361587, 2.444485),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 13.519919, 5.421898, 2.821722),
- (1, 13.447262, 5.364940, 2.926024),
- (2, 13.464838, 5.369476, 2.802961),
- (3, 13.514555, 5.440290, 2.831226),
- (4, 13.443975, 5.410124, 2.947296),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.498388, 2.171118, 2.153460),
- (1, 10.524313, 2.175829, 1.899075),
- (2, 10.502688, 2.185754, 1.894639),
- (3, 10.498667, 2.201617, 1.888811),
- (4, 10.488970, 2.166527, 1.885400),
-]}
-))
diff --git a/www/timing-data/2009-03-02/sketch.pdf b/www/timing-data/2009-03-02/sketch.pdf
deleted file mode 100644
index 3b98a3d054a3..000000000000
--- a/www/timing-data/2009-03-02/sketch.pdf
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-03-02/sketch.png b/www/timing-data/2009-03-02/sketch.png
deleted file mode 100644
index 3d1bc142beea..000000000000
--- a/www/timing-data/2009-03-02/sketch.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-03-02/sketch.txt b/www/timing-data/2009-03-02/sketch.txt
deleted file mode 100644
index d2270e471a2b..000000000000
--- a/www/timing-data/2009-03-02/sketch.txt
+++ /dev/null
@@ -1,2368 +0,0 @@
-ccc_path = """/Volumes/Data/ddunbar/llvm.install/bin/ccc"""
-ccc_clang = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb"""
-ccc_gcc = """/Volumes/Data/ddunbar/zorg/xcb_scripts/cc/xcc.fb -ccc-no-clang"""
-gcc = """/usr/bin/gcc-4.2"""
-ccc_clang_info = """
-ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
- "/Volumes/Data/ddunbar/llvm.install/bin/clang" "-S" "-disable-free" "--relocation-model=pic" "--disable-fp-elim" "--nozero-initialized-in-bss" "--unwind-tables=1" "--mcpu=core2" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-arch" "x86_64" "-o" "/tmp/tmpugUQni.s" "-x" "c" "/dev/null"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpH8AOZI.o" "/tmp/tmpugUQni.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpH8AOZI.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
-"""
-ccc_gcc_info = """
-ccc version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/tmp/tmpTiOyJZ.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/tmp/tmpTi0lCN.o" "/tmp/tmpTiOyJZ.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/tmp/tmpTi0lCN.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
-"""
-gcc_info = """
-Using built-in specs.
-Target: i686-apple-darwin10
-Configured with: /var/tmp/gcc/gcc-5630~5/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
-Thread model: posix
-gcc version 4.2.1 (Apple Inc. build 5630)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/tmp//ccuvh82w.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/tmp//ccb3T8Fr.o" "/var/tmp//ccuvh82w.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.5.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/tmp//ccb3T8Fr.o" "-lgcc_s.10.5" "-lgcc" "-lSystem"
-"""
-style = """xcb"""
-runs = []
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.405425, 0.222438, 0.698198),
- (1, 0.403472, 0.218381, 0.695599),
- (2, 0.403354, 0.217344, 0.695414),
- (3, 0.403856, 0.218787, 0.703370),
- (4, 0.404353, 0.221186, 0.695619),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.393260, 0.212802, 0.656048),
- (1, 0.393075, 0.211285, 0.654796),
- (2, 0.394300, 0.213498, 0.695105),
- (3, 0.393851, 0.213657, 0.695272),
- (4, 0.395458, 0.213304, 0.695908),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.403360, 0.216918, 0.704434),
- (1, 0.403818, 0.219731, 0.696158),
- (2, 0.402206, 0.218530, 0.697751),
- (3, 0.403133, 0.218441, 0.695443),
- (4, 0.403311, 0.218882, 0.695080),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.395200, 0.213912, 0.696117),
- (1, 0.395331, 0.213822, 0.695887),
- (2, 0.395293, 0.212402, 0.697557),
- (3, 0.395446, 0.213684, 0.695732),
- (4, 0.394667, 0.213321, 0.656472),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.403665, 0.217763, 0.694820),
- (1, 0.403482, 0.217606, 0.695959),
- (2, 0.404965, 0.219817, 0.819840),
- (3, 0.404437, 0.217515, 0.695675),
- (4, 0.402886, 0.216456, 0.703275),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.393583, 0.212237, 0.655196),
- (1, 0.394063, 0.212744, 0.695220),
- (2, 0.393998, 0.212889, 0.695448),
- (3, 0.394364, 0.213507, 0.695090),
- (4, 0.395886, 0.214974, 0.696254),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.129656, 0.771133, 2.056006),
- (1, 1.129855, 0.772644, 2.055649),
- (2, 1.130559, 0.768629, 2.055976),
- (3, 1.130291, 0.769030, 2.059280),
- (4, 1.130861, 0.771000, 2.055720),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.086760, 0.741197, 1.976344),
- (1, 1.087919, 0.739640, 1.975560),
- (2, 1.087589, 0.739815, 2.015386),
- (3, 1.087730, 0.738847, 1.976232),
- (4, 1.088193, 0.739529, 2.016033),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.138506, 0.768675, 2.064631),
- (1, 1.138085, 0.770549, 2.097210),
- (2, 1.138889, 0.771511, 2.096435),
- (3, 1.138765, 0.770142, 2.064291),
- (4, 1.138779, 0.768611, 2.095530),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.096902, 0.741661, 2.015757),
- (1, 1.097165, 0.740449, 2.015432),
- (2, 1.096494, 0.740608, 2.016453),
- (3, 1.096410, 0.739960, 1.975427),
- (4, 1.096579, 0.743114, 2.016444),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.444144, 0.284384, 0.814217),
- (1, 0.445853, 0.286540, 0.816314),
- (2, 0.446338, 0.287002, 0.814997),
- (3, 0.445384, 0.284369, 0.823090),
- (4, 0.444071, 0.284531, 0.815854),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.435113, 0.278547, 0.817260),
- (1, 0.433108, 0.275659, 0.775024),
- (2, 0.434473, 0.276611, 0.784047),
- (3, 0.434224, 0.275786, 0.775677),
- (4, 0.433396, 0.276622, 0.775240),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_pch",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.328464, 0.973747, 2.577016),
- (1, 1.324318, 0.855290, 2.424347),
- (2, 1.323693, 0.856675, 2.416951),
- (3, 1.323004, 0.857324, 2.417132),
- (4, 1.323843, 0.856000, 2.415804),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_pch",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.748207, 1.141266, 4.576484),
- (1, 2.744640, 1.137930, 4.416237),
- (2, 2.745616, 1.136230, 4.495978),
- (3, 2.746108, 1.139037, 4.496219),
- (4, 2.746059, 1.137958, 4.416920),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.051374, 0.650962, 3.144706),
- (1, 2.050914, 0.648174, 3.215974),
- (2, 2.050343, 0.649010, 3.176205),
- (3, 2.051910, 0.648745, 3.176613),
- (4, 2.051386, 0.648306, 3.217578),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.835919, 1.148648, 3.257076),
- (1, 1.835307, 1.146862, 3.264809),
- (2, 1.834812, 1.147964, 3.257005),
- (3, 1.835016, 1.144979, 3.256861),
- (4, 1.836571, 1.148836, 3.256094),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.288802, 1.569778, 4.095720),
- (1, 2.288176, 1.573356, 4.176816),
- (2, 2.287878, 1.573807, 4.096939),
- (3, 2.288041, 1.571541, 4.097750),
- (4, 2.288190, 1.569398, 4.097146),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.220738, 1.167367, 3.657062),
- (1, 2.219840, 1.170754, 3.657627),
- (2, 2.220897, 1.172925, 3.657043),
- (3, 2.221644, 1.167701, 3.656328),
- (4, 2.223199, 1.171444, 3.657134),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.717655, 1.602645, 4.536037),
- (1, 2.716324, 1.603188, 4.536210),
- (2, 2.718783, 1.605672, 4.576816),
- (3, 2.718146, 1.602360, 4.536958),
- (4, 2.718544, 1.606428, 4.577367),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.453390, 1.390902, 5.176330),
- (1, 3.453408, 1.394547, 5.176325),
- (2, 3.453141, 1.392043, 5.176946),
- (3, 3.457040, 1.390031, 5.257617),
- (4, 3.453262, 1.395063, 5.138977),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.077200, 1.866592, 6.223139),
- (1, 4.076044, 1.873001, 6.214158),
- (2, 4.079719, 1.869271, 6.235665),
- (3, 4.078223, 1.866927, 6.217922),
- (4, 4.076013, 1.867985, 6.204512),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.397072, 2.178746, 6.177185),
- (1, 3.397804, 2.167804, 6.177276),
- (2, 3.398193, 2.168075, 6.250655),
- (3, 3.397029, 2.165686, 6.184421),
- (4, 3.397568, 2.178013, 6.179279),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.486708, 2.445768, 10.254543),
- (1, 7.491379, 2.458432, 10.337225),
- (2, 7.486408, 2.433698, 10.257034),
- (3, 7.487016, 2.456457, 10.270939),
- (4, 7.487323, 2.439337, 10.258257),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.670173, 1.622433, 4.897808),
- (1, 2.666760, 1.609756, 4.776822),
- (2, 2.667040, 1.610998, 4.856885),
- (3, 2.671149, 1.594163, 4.816301),
- (4, 2.669699, 1.607578, 4.866539),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.803057, 1.908280, 8.963127),
- (1, 6.805076, 1.939662, 8.969825),
- (2, 6.802844, 1.921782, 8.970996),
- (3, 6.805031, 1.913186, 8.967523),
- (4, 6.805252, 1.919294, 8.959788),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.627373, 1.415978, 5.377556),
- (1, 3.625026, 1.415306, 5.337455),
- (2, 3.624699, 1.411942, 5.377834),
- (3, 3.627468, 1.422229, 5.376680),
- (4, 3.625721, 1.421354, 5.377509),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.249780, 1.891114, 6.438770),
- (1, 4.248041, 1.893114, 6.416578),
- (2, 4.248877, 1.890255, 6.422580),
- (3, 4.248459, 1.891867, 6.425267),
- (4, 4.251042, 1.896335, 6.438381),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.813308, 1.436255, 5.577048),
- (1, 3.812973, 1.436260, 5.577759),
- (2, 3.814667, 1.436329, 5.576892),
- (3, 3.814164, 1.439684, 5.577863),
- (4, 3.816874, 1.432057, 5.625098),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.438589, 1.914821, 6.634438),
- (1, 4.436802, 1.913064, 6.628424),
- (2, 4.438023, 1.918364, 6.632666),
- (3, 4.438494, 1.922851, 6.645062),
- (4, 4.439727, 1.920331, 6.685016),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.975290, 2.296164, 6.913135),
- (1, 3.977464, 2.309821, 6.916908),
- (2, 3.976537, 2.309954, 6.848258),
- (3, 3.977155, 2.305060, 7.357985),
- (4, 3.974276, 2.289059, 6.862249),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.928091, 2.684142, 11.969055),
- (1, 8.929295, 2.683263, 11.988445),
- (2, 8.929175, 2.678390, 11.956474),
- (3, 8.926613, 2.665122, 11.965071),
- (4, 8.926613, 2.680630, 11.964381),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.249871, 1.745454, 5.497846),
- (1, 3.249460, 1.737577, 5.538376),
- (2, 3.253966, 1.727548, 5.616847),
- (3, 3.251405, 1.725884, 5.496698),
- (4, 3.250563, 1.721386, 5.536694),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.249350, 2.147359, 10.672894),
- (1, 8.252421, 2.146136, 10.687439),
- (2, 8.252766, 2.142015, 10.683719),
- (3, 8.279512, 2.152184, 11.070527),
- (4, 8.250015, 2.161431, 10.703253),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.917675, 1.531758, 5.777717),
- (1, 3.917453, 1.532169, 5.777704),
- (2, 3.920630, 1.538518, 5.857605),
- (3, 3.917549, 1.535710, 5.776730),
- (4, 3.917673, 1.529128, 5.776450),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.536313, 2.003164, 6.831313),
- (1, 4.537451, 2.014513, 6.846562),
- (2, 4.540679, 2.016759, 6.865437),
- (3, 4.538081, 2.008899, 6.845811),
- (4, 4.538438, 2.009600, 6.836498),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.123486, 2.383752, 7.115483),
- (1, 4.127545, 2.372840, 7.151675),
- (2, 4.125900, 2.381678, 7.138942),
- (3, 4.123891, 2.369579, 7.127788),
- (4, 4.125164, 2.370661, 7.117664),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.076157, 2.771491, 12.341310),
- (1, 9.074681, 2.764608, 12.205139),
- (2, 9.076881, 2.766755, 12.228073),
- (3, 9.073910, 2.771638, 12.204252),
- (4, 9.076773, 2.777037, 12.235749),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.388061, 1.779190, 5.737793),
- (1, 3.387862, 1.790856, 5.697850),
- (2, 3.387800, 1.789477, 5.780238),
- (3, 3.387509, 1.788586, 5.743236),
- (4, 3.388152, 1.784450, 6.178092),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.376118, 2.205600, 10.877337),
- (1, 8.372512, 2.219382, 10.868894),
- (2, 8.375968, 2.225479, 10.996566),
- (3, 8.379525, 2.215791, 10.910221),
- (4, 8.375433, 2.210534, 10.890280),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.948571, 1.553366, 5.857777),
- (1, 3.946872, 1.549844, 5.817926),
- (2, 3.948643, 1.545410, 5.817794),
- (3, 3.947022, 1.548687, 5.816790),
- (4, 3.951557, 1.560511, 5.937022),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.568105, 2.037309, 6.888153),
- (1, 4.567872, 2.037818, 6.893678),
- (2, 4.569582, 2.037795, 6.894469),
- (3, 4.571991, 2.042292, 6.920444),
- (4, 4.568506, 2.036233, 6.895221),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.153075, 2.389230, 7.183219),
- (1, 4.150947, 2.401330, 7.175264),
- (2, 4.150807, 2.390926, 7.237253),
- (3, 4.152335, 2.393576, 7.265347),
- (4, 4.154240, 2.408743, 7.201345),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.104507, 2.799196, 12.284425),
- (1, 9.102214, 2.804734, 12.263326),
- (2, 9.102799, 2.797758, 12.263314),
- (3, 9.102472, 2.797718, 12.283471),
- (4, 9.101655, 2.799231, 12.257987),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.412096, 1.803347, 5.817859),
- (1, 3.412334, 1.792039, 5.897059),
- (2, 3.413608, 1.789291, 5.817810),
- (3, 3.413812, 1.785669, 5.827047),
- (4, 3.413291, 1.782601, 5.738213),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.402455, 2.228676, 10.943842),
- (1, 8.396442, 2.225608, 10.902714),
- (2, 8.401735, 2.220712, 10.918381),
- (3, 8.400619, 2.226284, 10.926158),
- (4, 8.398896, 2.221540, 10.901292),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.421126, 0.234655, 0.534969),
- (1, 0.418396, 0.232067, 0.536121),
- (2, 0.419512, 0.236062, 0.536636),
- (3, 0.420755, 0.236390, 0.535508),
- (4, 0.421343, 0.234614, 0.537189),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.411128, 0.230994, 0.499097),
- (1, 0.412593, 0.231427, 0.536123),
- (2, 0.407668, 0.229908, 0.495794),
- (3, 0.410890, 0.229289, 0.535618),
- (4, 0.412812, 0.229662, 0.535043),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.421792, 0.234957, 0.536236),
- (1, 0.421073, 0.235668, 0.538946),
- (2, 0.418909, 0.236416, 0.535464),
- (3, 0.420363, 0.235692, 0.535257),
- (4, 0.419598, 0.234400, 0.534633),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.409040, 0.230090, 0.534802),
- (1, 0.411753, 0.232552, 0.537293),
- (2, 0.415536, 0.231495, 0.536877),
- (3, 0.410714, 0.227612, 0.535090),
- (4, 0.409547, 0.230152, 0.497187),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.421181, 0.235033, 0.535407),
- (1, 0.420747, 0.236700, 0.535928),
- (2, 0.418786, 0.235032, 0.534312),
- (3, 0.420015, 0.233378, 0.535452),
- (4, 0.421154, 0.235218, 0.535269),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.411356, 0.231786, 0.537593),
- (1, 0.412772, 0.230723, 0.537039),
- (2, 0.410034, 0.228264, 0.494194),
- (3, 0.412693, 0.230932, 0.536339),
- (4, 0.411372, 0.228262, 0.497113),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.185856, 0.840347, 1.416460),
- (1, 1.186435, 0.854091, 1.415674),
- (2, 1.183343, 0.844916, 1.415643),
- (3, 1.181560, 0.857296, 1.415242),
- (4, 1.187699, 0.853918, 1.415647),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.138810, 0.818035, 1.335935),
- (1, 1.141064, 0.827249, 1.337062),
- (2, 1.138410, 0.811996, 1.335346),
- (3, 1.142644, 0.820159, 1.337486),
- (4, 1.138460, 0.815423, 1.335647),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.194684, 0.841290, 1.415885),
- (1, 1.195720, 0.844873, 1.416552),
- (2, 1.194440, 0.850513, 1.415595),
- (3, 1.191931, 0.850890, 1.414722),
- (4, 1.192481, 0.853052, 1.416102),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.148891, 0.817183, 1.335717),
- (1, 1.149617, 0.823096, 1.336040),
- (2, 1.149791, 0.805679, 1.337424),
- (3, 1.150876, 0.814239, 1.336748),
- (4, 1.153157, 0.809177, 1.336246),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.463514, 0.310817, 0.614767),
- (1, 0.464612, 0.310198, 0.618455),
- (2, 0.463460, 0.308990, 0.616282),
- (3, 0.463413, 0.311280, 0.617026),
- (4, 0.467009, 0.310382, 0.857752),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.453517, 0.301571, 0.575912),
- (1, 0.452100, 0.300588, 0.576359),
- (2, 0.448456, 0.297936, 0.575121),
- (3, 0.451645, 0.298907, 0.577323),
- (4, 0.450964, 0.301582, 0.574520),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_pch",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.381350, 0.944251, 1.776275),
- (1, 1.380373, 0.930919, 1.775617),
- (2, 1.379352, 0.937129, 1.736723),
- (3, 1.380977, 0.944068, 1.737369),
- (4, 1.381796, 0.938486, 1.776093),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_pch",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.805408, 1.220930, 3.697693),
- (1, 2.804236, 1.204836, 3.657105),
- (2, 2.803037, 1.210121, 3.696933),
- (3, 2.807280, 1.219531, 3.779261),
- (4, 2.802821, 1.208316, 3.736487),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.076567, 0.672051, 2.896169),
- (1, 2.070465, 0.668786, 2.895749),
- (2, 2.077549, 0.673245, 2.896393),
- (3, 2.075634, 0.671026, 2.976119),
- (4, 2.074463, 0.671262, 2.975937),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.909827, 1.258607, 2.215806),
- (1, 1.910547, 1.261354, 2.255924),
- (2, 1.907436, 1.262299, 2.216659),
- (3, 1.908875, 1.254564, 2.256077),
- (4, 1.906568, 1.264632, 2.215638),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.384586, 1.708563, 2.495874),
- (1, 2.386876, 1.705256, 2.456596),
- (2, 2.383560, 1.707485, 2.456364),
- (3, 2.388580, 1.714631, 2.496008),
- (4, 2.383943, 1.709754, 2.455848),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.296978, 1.274825, 2.415106),
- (1, 2.303460, 1.279010, 2.456151),
- (2, 2.300862, 1.277879, 2.536542),
- (3, 2.297727, 1.277312, 2.416137),
- (4, 2.299045, 1.281014, 2.457338),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.823962, 1.752509, 2.738192),
- (1, 2.825617, 1.738546, 2.736478),
- (2, 2.825608, 1.744360, 2.735298),
- (3, 2.822577, 1.756988, 2.735053),
- (4, 2.828362, 1.751245, 2.737930),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.586428, 1.498329, 3.258357),
- (1, 3.581922, 1.510793, 3.258049),
- (2, 3.584574, 1.523963, 3.256754),
- (3, 3.585929, 1.525886, 3.296728),
- (4, 3.583339, 1.509529, 3.255773),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.249019, 2.030066, 3.658088),
- (1, 4.244427, 1.997319, 3.618002),
- (2, 4.247446, 2.034549, 3.656419),
- (3, 4.250734, 1.984081, 3.616241),
- (4, 4.247304, 2.029095, 3.656926),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.533690, 2.339185, 4.777496),
- (1, 3.542505, 2.348833, 4.697715),
- (2, 3.544757, 2.349717, 4.658518),
- (3, 3.542116, 2.342489, 4.697843),
- (4, 3.532830, 2.358614, 4.777230),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.911000, 2.638922, 5.859227),
- (1, 7.898019, 2.606325, 5.856922),
- (2, 7.905536, 2.635740, 5.857377),
- (3, 7.904312, 2.612189, 5.858381),
- (4, 7.905098, 2.630487, 5.896411),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.751623, 1.803556, 3.817713),
- (1, 2.747727, 1.810833, 3.816503),
- (2, 2.748505, 1.805853, 3.937231),
- (3, 2.751082, 1.785040, 3.856857),
- (4, 2.712181, 1.628194, 4.458047),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.130218, 2.046734, 5.375091),
- (1, 7.178329, 2.050762, 5.101087),
- (2, 7.169060, 2.043104, 5.099096),
- (3, 7.173283, 2.044239, 5.098124),
- (4, 7.175252, 2.051192, 5.098199),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.789165, 1.527458, 3.336326),
- (1, 3.777274, 1.538660, 3.375557),
- (2, 3.784557, 1.519313, 3.376128),
- (3, 3.787602, 1.522217, 3.335926),
- (4, 3.787288, 1.526795, 3.337409),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.447726, 2.033431, 3.740433),
- (1, 4.442726, 2.033703, 3.738224),
- (2, 4.442734, 2.032771, 3.738289),
- (3, 4.444849, 2.031724, 3.737305),
- (4, 4.447839, 2.041379, 3.737854),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.976113, 1.536616, 3.457503),
- (1, 3.982885, 1.550541, 3.459236),
- (2, 3.980745, 1.542500, 3.418313),
- (3, 3.983197, 1.534735, 3.416768),
- (4, 3.984319, 1.549369, 3.456912),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.646497, 2.058736, 3.857968),
- (1, 4.645902, 2.056331, 3.816948),
- (2, 4.644425, 2.042617, 3.817483),
- (3, 4.650170, 2.053945, 3.816996),
- (4, 4.652057, 2.054087, 3.817612),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.227559, 2.531595, 5.137862),
- (1, 4.227397, 2.523166, 5.177460),
- (2, 4.221999, 2.507393, 5.217410),
- (3, 4.222567, 2.526250, 5.217654),
- (4, 4.227901, 2.540431, 5.098870),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.519619, 2.893774, 6.844787),
- (1, 9.519173, 2.909991, 6.855886),
- (2, 9.510792, 2.877242, 6.838998),
- (3, 9.510783, 2.891383, 6.824785),
- (4, 9.519126, 2.885516, 6.833841),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.451087, 1.898383, 4.336398),
- (1, 3.449852, 1.892527, 4.337959),
- (2, 3.454374, 1.893303, 4.658079),
- (3, 3.455111, 1.882656, 4.378217),
- (4, 3.450626, 1.869007, 4.337978),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.787702, 2.320593, 6.058270),
- (1, 8.789275, 2.306274, 6.057923),
- (2, 8.784843, 2.316817, 6.057423),
- (3, 8.783675, 2.311861, 6.060013),
- (4, 8.781261, 2.313746, 6.057873),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.083893, 1.630474, 3.536216),
- (1, 4.087591, 1.635289, 3.497630),
- (2, 4.085695, 1.632900, 3.538942),
- (3, 4.091750, 1.621504, 3.537607),
- (4, 4.083429, 1.624206, 3.538044),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.741063, 2.114975, 3.939181),
- (1, 4.742471, 2.134199, 3.937271),
- (2, 4.751861, 2.134679, 3.937887),
- (3, 4.748915, 2.139128, 3.937938),
- (4, 4.744369, 2.118603, 4.016509),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.373580, 2.603582, 5.297729),
- (1, 4.375890, 2.576323, 5.258865),
- (2, 4.371432, 2.583884, 5.297363),
- (3, 4.374495, 2.589453, 5.257298),
- (4, 4.369606, 2.606228, 5.257661),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.661360, 2.976421, 7.177350),
- (1, 9.668097, 2.986125, 6.963308),
- (2, 9.667800, 2.983053, 6.959276),
- (3, 9.663941, 2.979323, 6.939242),
- (4, 9.662299, 2.970007, 6.988974),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.579784, 1.946620, 4.378033),
- (1, 3.579704, 1.964725, 4.377985),
- (2, 3.584964, 1.951670, 4.376971),
- (3, 3.576692, 1.920906, 4.418008),
- (4, 3.590239, 1.966765, 4.377119),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.908318, 2.358443, 6.137820),
- (1, 8.900847, 2.342913, 6.137705),
- (2, 8.902168, 2.355932, 6.179136),
- (3, 8.903369, 2.363490, 6.097751),
- (4, 8.896827, 2.364196, 6.098246),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.122590, 1.633583, 3.696664),
- (1, 4.114949, 1.638141, 3.578111),
- (2, 4.114996, 1.631617, 3.536742),
- (3, 4.118038, 1.641230, 3.578327),
- (4, 4.112972, 1.639592, 3.575918),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.774701, 2.146296, 3.977572),
- (1, 4.775361, 2.153011, 3.979860),
- (2, 4.767364, 2.152865, 4.057217),
- (3, 4.762550, 2.149360, 3.979342),
- (4, 4.778981, 2.139902, 3.978489),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.400574, 2.604084, 5.299578),
- (1, 4.404470, 2.623904, 5.338578),
- (2, 4.396282, 2.608549, 5.297828),
- (3, 4.410117, 2.614698, 5.340116),
- (4, 4.406122, 2.619452, 5.337443),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.691876, 2.983326, 7.028989),
- (1, 9.686101, 2.995257, 6.984466),
- (2, 9.699200, 2.989842, 7.028152),
- (3, 9.694729, 2.989742, 6.973924),
- (4, 9.684670, 2.977108, 6.989194),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.603234, 1.964083, 4.458006),
- (1, 3.607074, 1.941178, 4.417525),
- (2, 3.603034, 1.943612, 4.737094),
- (3, 3.602477, 1.935710, 4.378785),
- (4, 3.603014, 1.920944, 4.496731),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.919863, 2.380177, 6.178527),
- (1, 8.915304, 2.377547, 6.139442),
- (2, 8.912262, 2.361640, 6.382166),
- (3, 8.928109, 2.368477, 6.192743),
- (4, 8.926360, 2.372693, 6.196191),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.433816, 0.270779, 0.497217),
- (1, 0.435460, 0.270028, 0.496532),
- (2, 0.433553, 0.269600, 0.496135),
- (3, 0.444402, 0.277012, 0.497745),
- (4, 0.435023, 0.270357, 0.496884),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.427882, 0.266594, 0.456246),
- (1, 0.436036, 0.268734, 0.457465),
- (2, 0.432485, 0.268278, 0.495730),
- (3, 0.431188, 0.269520, 0.457981),
- (4, 0.429806, 0.265927, 0.457372),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.439986, 0.271715, 0.496550),
- (1, 0.433586, 0.270013, 0.496199),
- (2, 0.432029, 0.268060, 0.497939),
- (3, 0.439059, 0.272464, 0.497620),
- (4, 0.434181, 0.272563, 0.497461),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.432427, 0.269396, 0.457136),
- (1, 0.428288, 0.270302, 0.737128),
- (2, 0.431231, 0.268325, 0.456252),
- (3, 0.427926, 0.267086, 0.456874),
- (4, 0.420557, 0.264270, 0.457617),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.434424, 0.272190, 0.498161),
- (1, 0.434165, 0.269235, 0.494824),
- (2, 0.432662, 0.270415, 0.500255),
- (3, 0.438368, 0.274265, 0.496769),
- (4, 0.436696, 0.274610, 0.495729),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.433117, 0.267209, 0.457335),
- (1, 0.431207, 0.267527, 0.457362),
- (2, 0.427488, 0.263088, 0.456154),
- (3, 0.424716, 0.264632, 0.456745),
- (4, 0.430324, 0.266478, 0.457237),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.243380, 0.979720, 1.137169),
- (1, 1.278996, 0.992319, 1.137506),
- (2, 1.287192, 0.993761, 1.138362),
- (3, 1.287132, 0.979672, 1.137975),
- (4, 1.280673, 0.991069, 1.134803),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.199258, 0.944011, 1.056302),
- (1, 1.238243, 0.967198, 1.055378),
- (2, 1.251064, 0.952736, 1.058118),
- (3, 1.238275, 0.953812, 1.056281),
- (4, 1.230085, 0.961011, 1.058278),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.303555, 1.002749, 1.177122),
- (1, 1.297516, 0.987769, 1.179257),
- (2, 1.291316, 0.989683, 1.134877),
- (3, 1.297521, 0.998087, 1.177932),
- (4, 1.298070, 0.996104, 1.136646),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.242426, 0.951754, 1.054691),
- (1, 1.251845, 0.955747, 1.055754),
- (2, 1.216099, 0.939568, 1.057614),
- (3, 1.252534, 0.953115, 1.057181),
- (4, 1.255139, 0.957134, 1.056560),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.480008, 0.367388, 0.535985),
- (1, 0.482634, 0.363998, 0.537057),
- (2, 0.487524, 0.362915, 0.536461),
- (3, 0.486824, 0.371502, 0.536601),
- (4, 0.486100, 0.368487, 0.536231),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.471967, 0.356792, 0.537280),
- (1, 0.471389, 0.351906, 0.537328),
- (2, 0.476653, 0.364830, 0.536856),
- (3, 0.473745, 0.360644, 0.536245),
- (4, 0.471692, 0.358740, 0.536919),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_pch",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.488745, 1.084366, 1.498790),
- (1, 1.477772, 1.072057, 1.497152),
- (2, 1.481656, 1.079815, 1.497487),
- (3, 1.488131, 1.086291, 1.497713),
- (4, 1.484908, 1.083611, 1.497307),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_pch",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.892219, 1.358115, 3.416973),
- (1, 2.908085, 1.361083, 3.458190),
- (2, 2.911845, 1.363507, 3.498229),
- (3, 2.861631, 1.340626, 3.497350),
- (4, 2.902695, 1.349841, 3.498252),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.094289, 0.731166, 2.856787),
- (1, 2.094159, 0.727149, 3.098345),
- (2, 2.099123, 0.725737, 2.857987),
- (3, 2.099356, 0.725484, 2.857824),
- (4, 2.092198, 0.722902, 2.856964),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.072042, 1.472173, 1.777206),
- (1, 2.082600, 1.489627, 1.777280),
- (2, 2.056884, 1.488123, 1.817614),
- (3, 2.070744, 1.497244, 1.776597),
- (4, 2.067240, 1.482836, 1.777571),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.533060, 2.043311, 1.777522),
- (1, 2.628373, 2.047752, 1.777593),
- (2, 2.630915, 2.051977, 1.777852),
- (3, 2.630455, 2.065881, 1.777911),
- (4, 2.631787, 2.049902, 1.778263),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.505337, 1.496155, 1.898006),
- (1, 2.495744, 1.488942, 1.897842),
- (2, 2.515831, 1.484552, 1.897723),
- (3, 2.498317, 1.488449, 1.897741),
- (4, 2.515904, 1.484614, 1.897771),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.125124, 2.066737, 1.896962),
- (1, 3.066430, 2.061710, 1.897127),
- (2, 2.951498, 2.032558, 1.899777),
- (3, 3.102248, 2.072226, 1.938907),
- (4, 2.965375, 2.034301, 1.901575),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.959637, 1.775658, 2.417471),
- (1, 3.731703, 1.768139, 2.338378),
- (2, 3.938876, 1.797903, 2.376989),
- (3, 3.942618, 1.776899, 2.376468),
- (4, 3.955662, 1.784850, 2.417537),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.711232, 2.418611, 2.457315),
- (1, 4.710700, 2.405150, 2.458243),
- (2, 4.701677, 2.393935, 2.458244),
- (3, 4.700064, 2.411945, 2.458502),
- (4, 4.435552, 2.373475, 2.417904),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.765235, 3.147148, 4.457806),
- (1, 3.792075, 3.092380, 4.138512),
- (2, 3.755530, 3.109232, 4.099198),
- (3, 3.775577, 3.132702, 4.259349),
- (4, 3.765380, 3.153395, 4.138279),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.733600, 3.141350, 3.819429),
- (1, 8.729315, 3.130464, 3.818712),
- (2, 8.758360, 3.153188, 3.898371),
- (3, 8.284330, 3.049157, 3.698701),
- (4, 8.287672, 3.024545, 3.697567),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.874930, 2.387032, 3.537592),
- (1, 2.912332, 2.467479, 3.577891),
- (2, 2.864476, 2.410851, 3.499089),
- (3, 2.907625, 2.451013, 3.618200),
- (4, 2.911261, 2.404477, 4.099524),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.915458, 2.450591, 3.219913),
- (1, 7.956233, 2.439542, 3.300366),
- (2, 7.913691, 2.473252, 3.218957),
- (3, 7.509113, 2.397069, 3.138018),
- (4, 7.904014, 2.456804, 3.218425),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.942240, 1.800567, 2.417458),
- (1, 4.154844, 1.814089, 2.457805),
- (2, 4.176584, 1.830900, 2.457020),
- (3, 4.158194, 1.830085, 2.778865),
- (4, 4.150232, 1.830750, 2.459318),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.905547, 2.434522, 2.537988),
- (1, 4.924605, 2.457269, 2.538644),
- (2, 4.657417, 2.378047, 2.458053),
- (3, 4.911690, 2.470984, 2.537993),
- (4, 4.929673, 2.455544, 2.538190),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.418219, 1.850523, 2.536990),
- (1, 4.366724, 1.852566, 2.538399),
- (2, 4.384926, 1.854429, 2.539958),
- (3, 4.394250, 1.842192, 2.539435),
- (4, 4.397239, 1.838145, 2.540060),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.130585, 2.493244, 2.579148),
- (1, 5.162982, 2.497135, 2.578713),
- (2, 5.129066, 2.472889, 2.619872),
- (3, 4.874468, 2.405774, 2.497419),
- (4, 5.128376, 2.467295, 2.578880),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.630875, 3.227827, 4.420094),
- (1, 4.603130, 3.292521, 4.698425),
- (2, 4.637749, 3.169974, 4.378697),
- (3, 4.662829, 3.216485, 4.459226),
- (4, 4.661186, 3.194321, 4.459337),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.094412, 3.382733, 4.299690),
- (1, 10.607728, 3.485426, 4.420339),
- (2, 10.672437, 3.500697, 4.499281),
- (3, 10.081432, 3.369802, 4.260940),
- (4, 10.637020, 3.507006, 4.419349),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.756469, 2.606486, 3.858024),
- (1, 3.742525, 2.585514, 3.860432),
- (2, 3.763984, 2.594155, 3.858338),
- (3, 3.750329, 2.597445, 3.861970),
- (4, 3.780330, 2.594397, 4.178249),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.783391, 2.778921, 3.858346),
- (1, 9.291026, 2.713206, 3.741779),
- (2, 9.763105, 2.769221, 3.818018),
- (3, 9.781831, 2.771892, 3.860051),
- (4, 9.795868, 2.814192, 3.861095),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.526822, 1.970779, 2.579904),
- (1, 4.516155, 1.962200, 2.579553),
- (2, 4.502726, 1.967558, 2.657639),
- (3, 4.475255, 1.944838, 2.578810),
- (4, 4.552333, 1.965428, 2.620439),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.260314, 2.603498, 2.660341),
- (1, 4.995161, 2.487917, 2.539731),
- (2, 5.272310, 2.582304, 2.619170),
- (3, 5.297074, 2.584287, 2.659045),
- (4, 5.276844, 2.591704, 2.658579),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.820446, 3.357945, 4.457265),
- (1, 4.695519, 3.299694, 4.700489),
- (2, 4.802906, 3.355605, 4.499002),
- (3, 4.790937, 3.298910, 4.497635),
- (4, 4.807253, 3.403019, 4.538081),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.775635, 3.627255, 4.498454),
- (1, 10.819002, 3.627111, 4.498795),
- (2, 10.777939, 3.603335, 4.579594),
- (3, 10.261991, 3.489692, 4.340296),
- (4, 10.783511, 3.603470, 4.497803),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.926690, 2.635944, 3.858194),
- (1, 3.904631, 2.622227, 3.819312),
- (2, 3.902995, 2.656935, 3.899565),
- (3, 3.842353, 2.559599, 3.939178),
- (4, 3.912334, 2.629019, 3.858092),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.417663, 2.778879, 3.779754),
- (1, 9.981881, 2.854902, 3.981156),
- (2, 9.922719, 2.849422, 3.895627),
- (3, 9.932923, 2.851789, 3.899661),
- (4, 9.882651, 2.809967, 3.860299),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.524352, 1.986189, 2.979131),
- (1, 4.571793, 1.979632, 2.617329),
- (2, 4.551874, 1.976839, 2.657311),
- (3, 4.535069, 1.982461, 2.660565),
- (4, 4.517949, 1.967234, 2.619985),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.308971, 2.608535, 2.660880),
- (1, 5.300322, 2.591561, 2.698928),
- (2, 5.007866, 2.516937, 2.617425),
- (3, 5.004273, 2.518780, 2.620204),
- (4, 5.298584, 2.603459, 2.697609),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.829605, 3.306560, 4.499574),
- (1, 4.834964, 3.359516, 4.499708),
- (2, 4.848950, 3.406535, 4.500607),
- (3, 4.846305, 3.301867, 4.501270),
- (4, 4.841747, 3.311314, 4.460786),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.261230, 3.487758, 4.377307),
- (1, 10.821449, 3.608144, 4.579734),
- (2, 10.818690, 3.639902, 4.538873),
- (3, 10.288671, 3.520532, 4.378760),
- (4, 10.827655, 3.621076, 4.540632),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.945245, 2.727926, 4.020004),
- (1, 3.927023, 2.718237, 3.937944),
- (2, 3.864097, 2.645215, 4.258710),
- (3, 3.959593, 2.659668, 3.857486),
- (4, 3.949860, 2.636461, 3.860314),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.988320, 2.894515, 3.979462),
- (1, 9.984554, 2.865497, 3.978603),
- (2, 9.969262, 2.894911, 3.940909),
- (3, 9.971215, 2.860655, 3.939045),
- (4, 9.928752, 2.859610, 4.140611),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.437223, 0.305541, 0.456598),
- (1, 0.437365, 0.302782, 0.455612),
- (2, 0.444941, 0.302766, 0.458539),
- (3, 0.443284, 0.309348, 0.457267),
- (4, 0.438558, 0.302788, 0.456867),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.433141, 0.299426, 0.457566),
- (1, 0.433713, 0.302028, 0.456971),
- (2, 0.432310, 0.301072, 0.457115),
- (3, 0.431210, 0.298571, 0.456809),
- (4, 0.432891, 0.306442, 0.458554),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.440129, 0.307891, 0.457005),
- (1, 0.441966, 0.305756, 0.456712),
- (2, 0.444503, 0.310015, 0.457176),
- (3, 0.439473, 0.304319, 0.457442),
- (4, 0.443194, 0.306398, 0.457362),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.431106, 0.301673, 0.458410),
- (1, 0.434829, 0.302589, 0.456891),
- (2, 0.430545, 0.302707, 0.457500),
- (3, 0.436609, 0.301462, 0.456980),
- (4, 0.429837, 0.300629, 0.456958),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.441827, 0.306401, 0.457803),
- (1, 0.440791, 0.307818, 0.456863),
- (2, 0.441486, 0.306428, 0.456280),
- (3, 0.441639, 0.303644, 0.457488),
- (4, 0.435752, 0.302272, 0.456606),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.434382, 0.299908, 0.458576),
- (1, 0.430466, 0.299767, 0.458895),
- (2, 0.433482, 0.301923, 0.457146),
- (3, 0.437816, 0.305736, 0.460591),
- (4, 0.433787, 0.300150, 0.457657),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.248580, 1.078897, 1.137297),
- (1, 1.240939, 1.052455, 1.415574),
- (2, 1.241209, 1.084570, 1.136554),
- (3, 1.240406, 1.093724, 1.136429),
- (4, 1.240385, 1.082323, 1.136401),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.290192, 1.199382, 0.936326),
- (1, 1.276522, 1.198278, 0.936272),
- (2, 1.273170, 1.185225, 0.935751),
- (3, 1.281657, 1.188458, 0.934154),
- (4, 1.285165, 1.186782, 0.935658),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.261013, 1.087419, 1.135864),
- (1, 1.261208, 1.088418, 1.134847),
- (2, 1.243520, 1.091952, 1.135702),
- (3, 1.256916, 1.061697, 1.138041),
- (4, 1.262088, 1.105355, 1.137939),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.304031, 1.188856, 0.937909),
- (1, 1.293276, 1.188637, 0.935459),
- (2, 1.278288, 1.189283, 0.936833),
- (3, 1.302987, 1.181945, 0.936069),
- (4, 1.293851, 1.192556, 0.936999),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.490107, 0.418154, 0.575664),
- (1, 0.489843, 0.413785, 0.535501),
- (2, 0.487683, 0.415899, 0.535610),
- (3, 0.484014, 0.413119, 0.535279),
- (4, 0.491381, 0.413503, 0.537277),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.486695, 0.445844, 0.494296),
- (1, 0.481367, 0.455675, 0.497159),
- (2, 0.481974, 0.481187, 0.496221),
- (3, 0.479369, 0.425384, 0.495441),
- (4, 0.478301, 0.457115, 0.494315),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_pch",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.434857, 1.168123, 1.455765),
- (1, 1.436208, 1.190995, 1.496024),
- (2, 1.439552, 1.161674, 1.455066),
- (3, 1.436967, 1.180953, 1.494596),
- (4, 1.435067, 1.162529, 1.456440),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_pch",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.854271, 1.448036, 3.456023),
- (1, 2.864284, 1.464534, 3.456831),
- (2, 2.860290, 1.477350, 3.377527),
- (3, 2.857286, 1.458217, 3.417068),
- (4, 2.855595, 1.464395, 3.376247),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.095114, 0.776987, 2.855911),
- (1, 2.099607, 0.795455, 2.856180),
- (2, 2.095073, 0.792649, 2.896811),
- (3, 2.094082, 0.789727, 2.897515),
- (4, 2.100236, 0.781259, 2.774968),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.999042, 1.594807, 1.777251),
- (1, 1.990498, 1.601683, 1.736392),
- (2, 2.006314, 1.599276, 1.897380),
- (3, 1.994969, 1.622299, 1.775973),
- (4, 1.988203, 1.577170, 1.736153),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"cpp",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.703651, 2.613281, 1.374149),
- (1, 2.700635, 2.658189, 1.415542),
- (2, 2.723514, 2.623613, 1.375880),
- (3, 2.698653, 2.597336, 1.376495),
- (4, 2.682678, 2.616761, 1.377316),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.415923, 1.586213, 1.856706),
- (1, 2.413466, 1.580113, 1.854297),
- (2, 2.415569, 1.611288, 1.856562),
- (3, 2.398350, 1.569858, 1.855165),
- (4, 2.394427, 1.597305, 1.856311),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"parse",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.166052, 2.593652, 1.456512),
- (1, 3.196717, 2.604754, 1.456743),
- (2, 3.101508, 2.536190, 1.456607),
- (3, 3.174828, 2.591447, 1.456659),
- (4, 3.201618, 2.596692, 1.457126),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.712949, 1.873531, 2.336073),
- (1, 3.691984, 1.870964, 2.297376),
- (2, 3.733735, 1.860346, 2.296816),
- (3, 3.702759, 1.885194, 2.336534),
- (4, 3.725368, 1.861191, 2.296488),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.674568, 2.896322, 1.777463),
- (1, 4.751183, 2.932167, 1.774656),
- (2, 4.619575, 2.943985, 1.775820),
- (3, 4.831743, 2.966127, 1.785376),
- (4, 4.696926, 2.918956, 1.774947),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.619956, 3.111231, 4.057294),
- (1, 3.634434, 3.079039, 4.176458),
- (2, 3.619489, 3.150783, 4.138602),
- (3, 3.621266, 3.104540, 4.058816),
- (4, 3.608454, 3.122193, 4.057912),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.685876, 3.735123, 2.538354),
- (1, 8.928202, 3.820031, 2.775907),
- (2, 9.001593, 3.780341, 2.615105),
- (3, 8.914982, 3.802006, 2.576587),
- (4, 8.672801, 3.745031, 2.537300),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.804784, 2.299355, 3.497193),
- (1, 2.837757, 2.362386, 3.538558),
- (2, 2.872059, 2.437397, 3.497046),
- (3, 2.822245, 2.354290, 3.416766),
- (4, 2.852352, 2.360742, 3.536904),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.840658, 2.912237, 2.176625),
- (1, 7.786177, 2.867490, 2.098460),
- (2, 8.029733, 2.900113, 2.094914),
- (3, 7.787848, 2.850907, 2.096058),
- (4, 8.009086, 2.890278, 2.097071),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.924865, 1.882098, 2.377105),
- (1, 3.946578, 1.907070, 2.377384),
- (2, 3.942964, 1.879682, 2.376026),
- (3, 3.891159, 1.892699, 2.377748),
- (4, 3.967042, 1.868087, 2.417171),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"irgen",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.959364, 2.975161, 1.817129),
- (1, 5.054176, 2.984549, 1.817835),
- (2, 4.919681, 2.991480, 1.815857),
- (3, 4.910313, 2.971126, 1.816666),
- (4, 4.951734, 2.972542, 1.815437),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.101830, 1.911448, 2.454536),
- (1, 4.134987, 1.907901, 2.417187),
- (2, 4.137531, 1.889402, 2.416253),
- (3, 4.106261, 1.900297, 2.418632),
- (4, 4.116540, 1.914047, 2.415859),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.144013, 2.981688, 1.855810),
- (1, 5.084562, 2.953167, 1.816353),
- (2, 5.123251, 2.985708, 1.937743),
- (3, 5.218549, 3.005248, 1.816337),
- (4, 5.121341, 2.958136, 1.817163),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.391211, 3.194895, 4.297978),
- (1, 4.320212, 3.215877, 4.336974),
- (2, 4.317236, 3.185048, 4.297096),
- (3, 4.347551, 3.210930, 4.337750),
- (4, 4.340133, 3.158959, 4.298051),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.533776, 4.099156, 2.857560),
- (1, 10.875003, 4.167712, 2.978028),
- (2, 10.559224, 4.084177, 2.898004),
- (3, 10.529217, 4.091320, 2.857602),
- (4, 10.531274, 4.079794, 2.857786),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.572211, 2.564058, 3.657172),
- (1, 3.610311, 2.554201, 3.738315),
- (2, 3.503969, 2.457425, 3.656664),
- (3, 3.497522, 2.477225, 3.776817),
- (4, 3.516315, 2.450350, 3.697352),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.667563, 3.247271, 2.416874),
- (1, 9.737532, 3.221747, 2.496587),
- (2, 9.683672, 3.255651, 2.416956),
- (3, 9.897372, 3.270324, 2.457738),
- (4, 9.960110, 3.282960, 2.536374),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.216047, 2.040267, 2.417042),
- (1, 4.198596, 2.057673, 2.417291),
- (2, 4.355761, 2.050442, 2.456578),
- (3, 4.269654, 2.046761, 2.414728),
- (4, 4.258278, 2.065794, 2.415867),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.364820, 3.155647, 1.856490),
- (1, 5.380241, 3.164256, 1.895779),
- (2, 5.258991, 3.099702, 1.858494),
- (3, 5.408499, 3.143804, 1.858232),
- (4, 5.433442, 3.172182, 1.896951),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.509842, 3.336711, 4.298495),
- (1, 4.493119, 3.342058, 4.338363),
- (2, 4.497302, 3.391293, 4.376365),
- (3, 4.552023, 3.326395, 4.296523),
- (4, 4.511749, 3.315174, 4.258914),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 11.063909, 4.331076, 2.975250),
- (1, 10.750918, 4.265164, 2.897127),
- (2, 10.773158, 4.274519, 2.858005),
- (3, 10.989661, 4.295921, 2.937906),
- (4, 10.991448, 4.334725, 2.977596),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.668731, 2.619398, 3.657468),
- (1, 3.654504, 2.592248, 3.696077),
- (2, 3.665061, 2.625732, 3.699196),
- (3, 3.673349, 2.573183, 3.697462),
- (4, 3.682111, 2.613733, 3.738984),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.810406, 3.300637, 2.416778),
- (1, 10.048934, 3.350114, 2.496649),
- (2, 9.875004, 3.340279, 2.537774),
- (3, 10.160045, 3.376951, 2.619453),
- (4, 10.115032, 3.362591, 2.537008),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.241536, 2.082256, 2.455986),
- (1, 4.286330, 2.067488, 2.496313),
- (2, 4.291944, 2.084961, 2.496839),
- (3, 4.299382, 2.050242, 2.497274),
- (4, 4.256038, 2.063266, 2.497293),
-]}
-))
-runs.append(( { 'cc':"ccc_clang",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 5.421218, 3.170845, 1.936421),
- (1, 5.384884, 3.153992, 1.897806),
- (2, 5.296851, 3.153219, 1.951468),
- (3, 5.260795, 3.139369, 2.177163),
- (4, 5.278498, 3.141780, 1.895288),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.484287, 3.364861, 4.377941),
- (1, 4.531560, 3.308326, 4.377562),
- (2, 4.578896, 3.345062, 4.377173),
- (3, 4.566615, 3.446052, 4.417550),
- (4, 4.515315, 3.375575, 4.336788),
-]}
-))
-runs.append(( { 'cc':"ccc_gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.788959, 4.299290, 2.977905),
- (1, 11.090341, 4.345425, 3.058836),
- (2, 11.066430, 4.319885, 2.976521),
- (3, 10.779432, 4.283670, 3.018155),
- (4, 10.788091, 4.327036, 2.978633),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.682013, 2.568734, 3.737019),
- (1, 3.782095, 2.599814, 3.777516),
- (2, 3.694371, 2.626584, 3.858657),
- (3, 3.701257, 2.616141, 4.138741),
- (4, 3.772297, 2.652233, 3.697378),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.129212, 3.382389, 2.576426),
- (1, 10.165855, 3.362136, 2.579688),
- (2, 10.085414, 3.375557, 2.539346),
- (3, 10.106707, 3.375161, 2.777265),
- (4, 10.163243, 3.374295, 2.579247),
-]}
-))
diff --git a/www/timing-data/2009-06-26/176.gcc.pdf b/www/timing-data/2009-06-26/176.gcc.pdf
deleted file mode 100644
index 50a8bc355e6b..000000000000
--- a/www/timing-data/2009-06-26/176.gcc.pdf
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-06-26/176.gcc.png b/www/timing-data/2009-06-26/176.gcc.png
deleted file mode 100644
index da10f11b66c2..000000000000
--- a/www/timing-data/2009-06-26/176.gcc.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-06-26/176.gcc.txt b/www/timing-data/2009-06-26/176.gcc.txt
deleted file mode 100644
index e8b9c4468fe9..000000000000
--- a/www/timing-data/2009-06-26/176.gcc.txt
+++ /dev/null
@@ -1,699 +0,0 @@
-start = """2009-06-26_10-19"""
-clang = """/Volumes/Data/ddunbar/llvm.install/bin/clang"""
-gcc = """/usr/bin/gcc-4.2"""
-clang_info = """
-clang version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk 70266M)
-Target: x86_64-apple-darwin10
- "/Volumes/Data/ddunbar/llvm.install/bin/../libexec/clang-cc" "-triple" "x86_64-apple-darwin10" "-S" "-disable-free" "-main-file-name" "null" "--relocation-model" "pic" "-pic-level=1" "--disable-fp-elim" "--unwind-tables=1" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-fdiagnostics-show-option" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-CVKyzP.s" "-x" "c" "/dev/null"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-yeTCzJ.o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-CVKyzP.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-yeTCzJ.o" "-lSystem" "-lgcc"
-"""
-gcc_info = """
-Using built-in specs.
-Target: i686-apple-darwin10
-Configured with: /var/tmp/gcc/gcc-5646~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
-Thread model: posix
-gcc version 4.2.1 (Apple Inc. build 5646)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//cc1kQh9M.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccQcv4DT.o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//cc1kQh9M.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccQcv4DT.o" "-lSystem" "-lgcc" "-lSystem"
-"""
-style = """make"""
-runs = []
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.065445, 0.110578, 0.041286),
- (1, 0.064915, 0.107837, 0.038992),
- (2, 0.065191, 0.106475, 0.039233),
- (3, 0.064924, 0.107004, 0.039142),
- (4, 0.065260, 0.108901, 0.038903),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.066126, 0.112036, 0.040769),
- (1, 0.065207, 0.108471, 0.038945),
- (2, 0.065186, 0.107970, 0.038926),
- (3, 0.065149, 0.108577, 0.039189),
- (4, 0.065456, 0.109348, 0.039253),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.206667, 0.425607, 0.110976),
- (1, 0.204719, 0.410080, 0.107065),
- (2, 0.204989, 0.410953, 0.108714),
- (3, 0.204985, 0.407392, 0.107438),
- (4, 0.203424, 0.408111, 0.108717),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.265631, 0.798950, 0.161461),
- (1, 0.263615, 0.805888, 0.160308),
- (2, 0.263824, 0.686335, 0.145542),
- (3, 0.262625, 0.949966, 0.177774),
- (4, 0.263458, 0.820937, 0.162473),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.464727, 0.818916, 0.657338),
- (1, 1.492318, 0.850179, 0.351025),
- (2, 1.492530, 0.861113, 0.349530),
- (3, 1.515402, 0.868510, 0.354163),
- (4, 1.501033, 0.855415, 0.351763),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.339387, 1.362012, 0.808105),
- (1, 4.327148, 1.319992, 0.794006),
- (2, 4.327374, 1.320020, 0.793893),
- (3, 4.319876, 1.319808, 0.787893),
- (4, 4.329951, 1.344321, 0.796930),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.977307, 1.244670, 0.754129),
- (1, 3.948981, 1.236009, 0.751078),
- (2, 3.987417, 1.247336, 0.750608),
- (3, 3.973621, 1.227822, 0.746016),
- (4, 3.947019, 1.234332, 0.741703),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.749291, 1.404829, 1.149195),
- (1, 6.750589, 1.434406, 1.151828),
- (2, 6.744767, 1.415306, 1.146994),
- (3, 6.738192, 1.425966, 1.147283),
- (4, 6.755475, 1.410701, 1.147945),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.403397, 1.560103, 1.539962),
- (1, 9.398348, 1.540148, 1.526404),
- (2, 9.421496, 1.551876, 1.744563),
- (3, 9.456310, 1.589165, 1.539901),
- (4, 9.417963, 1.545186, 1.528347),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.032359, 1.747400, 1.467280),
- (1, 7.962687, 1.720919, 1.391892),
- (2, 7.986155, 1.694753, 1.426921),
- (3, 7.978081, 1.695359, 1.416691),
- (4, 7.977982, 1.687328, 1.419240),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.750102, 1.794398, 1.729777),
- (1, 10.730841, 1.801150, 1.728536),
- (2, 10.723943, 1.779271, 1.701177),
- (3, 10.730824, 1.778987, 1.705904),
- (4, 10.741052, 1.819326, 1.724089),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.070440, 1.732707, 1.518658),
- (1, 8.111095, 1.739793, 1.542162),
- (2, 8.106386, 1.751412, 1.552584),
- (3, 8.062847, 1.723786, 1.540230),
- (4, 8.075670, 1.701288, 1.509957),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.803240, 1.832409, 1.822466),
- (1, 10.797956, 1.833142, 1.875121),
- (2, 10.815192, 1.818826, 1.835845),
- (3, 10.826268, 1.809307, 1.823997),
- (4, 10.815709, 1.809185, 1.840403),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.060892, 0.065833, 0.155946),
- (1, 0.060517, 0.064263, 0.133922),
- (2, 0.060487, 0.064208, 0.133807),
- (3, 0.060484, 0.063849, 0.134039),
- (4, 0.060465, 0.064026, 0.133506),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.060780, 0.064833, 0.136229),
- (1, 0.060581, 0.064090, 0.134156),
- (2, 0.060534, 0.064191, 0.133656),
- (3, 0.060524, 0.064027, 0.133635),
- (4, 0.060523, 0.063964, 0.133708),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.182177, 0.218261, 0.480256),
- (1, 0.181253, 0.215086, 0.446808),
- (2, 0.181503, 0.215725, 0.450776),
- (3, 0.181187, 0.215330, 0.447765),
- (4, 0.181176, 0.215050, 0.446595),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.236347, 0.301491, 0.583495),
- (1, 0.235946, 0.299452, 0.568506),
- (2, 0.235676, 0.298048, 0.559954),
- (3, 0.235782, 0.298448, 0.561808),
- (4, 0.235882, 0.299948, 0.563575),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.355242, 0.589876, 2.134110),
- (1, 1.354939, 0.586215, 2.111487),
- (2, 1.354329, 0.589784, 2.109410),
- (3, 1.355080, 0.586192, 2.122027),
- (4, 1.354042, 0.581133, 2.111260),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.044141, 0.951252, 5.162733),
- (1, 4.043237, 0.954487, 5.147568),
- (2, 4.043888, 0.952179, 5.146153),
- (3, 4.043125, 0.948038, 5.147289),
- (4, 4.043883, 0.943084, 5.147096),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.444049, 0.848918, 4.534581),
- (1, 3.444084, 0.854620, 4.525171),
- (2, 3.444498, 0.862757, 4.598576),
- (3, 3.442347, 0.856215, 4.518719),
- (4, 3.443622, 0.866269, 4.532286),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.065809, 1.034261, 7.390113),
- (1, 6.064420, 1.027780, 7.396403),
- (2, 6.065132, 1.030652, 7.471856),
- (3, 6.060587, 1.031604, 7.337894),
- (4, 6.064466, 1.050338, 7.360592),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 8.960646, 1.236906, 10.456741),
- (1, 8.957264, 1.234577, 10.357447),
- (2, 8.956407, 1.237590, 10.352680),
- (3, 8.957027, 1.241364, 10.398440),
- (4, 8.956120, 1.239588, 10.355988),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.277301, 1.238993, 8.973009),
- (1, 7.277048, 1.246566, 9.027985),
- (2, 7.277032, 1.226791, 8.944300),
- (3, 7.277537, 1.242752, 8.970441),
- (4, 7.278972, 1.238938, 8.989529),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.081783, 1.335714, 11.707981),
- (1, 10.081742, 1.344538, 11.682596),
- (2, 10.079740, 1.330281, 11.681210),
- (3, 10.074737, 1.324856, 11.632253),
- (4, 10.075030, 1.350316, 11.633475),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.377028, 1.265309, 9.283505),
- (1, 7.376723, 1.253489, 9.102278),
- (2, 7.376104, 1.255404, 9.094650),
- (3, 7.376589, 1.260461, 9.246790),
- (4, 7.377455, 1.255013, 9.095294),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.172422, 1.355756, 11.797816),
- (1, 10.173442, 1.357210, 11.808185),
- (2, 10.173484, 1.346743, 11.781768),
- (3, 10.170524, 1.352371, 11.749764),
- (4, 10.171428, 1.362057, 11.760581),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.061930, 0.070826, 0.090142),
- (1, 0.061012, 0.067330, 0.073687),
- (2, 0.060994, 0.067246, 0.073681),
- (3, 0.061099, 0.067234, 0.074369),
- (4, 0.061022, 0.066989, 0.073428),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.061591, 0.069558, 0.083641),
- (1, 0.061059, 0.067184, 0.073565),
- (2, 0.061076, 0.067165, 0.073724),
- (3, 0.061096, 0.066990, 0.073567),
- (4, 0.061062, 0.067199, 0.073221),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.185243, 0.234231, 0.256557),
- (1, 0.184673, 0.232841, 0.245015),
- (2, 0.184453, 0.232130, 0.244661),
- (3, 0.184370, 0.230836, 0.243152),
- (4, 0.184320, 0.231212, 0.244266),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.239474, 0.325816, 0.314883),
- (1, 0.238393, 0.326431, 0.306354),
- (2, 0.238299, 0.326449, 0.307918),
- (3, 0.237867, 0.325013, 0.305753),
- (4, 0.238329, 0.326355, 0.306446),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.386532, 0.594929, 1.083410),
- (1, 1.385214, 0.591925, 1.071299),
- (2, 1.385670, 0.596527, 1.071159),
- (3, 1.385205, 0.595489, 1.071494),
- (4, 1.385904, 0.590797, 1.067600),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.154845, 0.996239, 2.665919),
- (1, 4.149680, 0.998786, 2.651533),
- (2, 4.150974, 1.006984, 2.655142),
- (3, 4.152007, 1.008280, 2.659809),
- (4, 4.152938, 1.003288, 2.658114),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.644865, 0.892229, 2.404722),
- (1, 3.639556, 0.887595, 2.387664),
- (2, 3.643246, 0.880541, 2.387287),
- (3, 3.643391, 0.883751, 2.401062),
- (4, 3.644145, 0.886052, 2.392286),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.307048, 1.072104, 3.873967),
- (1, 6.313464, 1.064256, 3.870116),
- (2, 6.307031, 1.064902, 3.865455),
- (3, 6.309147, 1.070336, 3.900830),
- (4, 6.307909, 1.066836, 3.868847),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.143474, 1.275600, 5.365390),
- (1, 9.141933, 1.276966, 5.352204),
- (2, 9.141995, 1.270270, 5.353590),
- (3, 9.143375, 1.285837, 5.356607),
- (4, 9.144897, 1.283080, 5.494642),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.533151, 1.293809, 4.718994),
- (1, 7.528865, 1.295241, 4.726586),
- (2, 7.528888, 1.303576, 4.729746),
- (3, 7.525020, 1.295358, 4.716415),
- (4, 7.528346, 1.289752, 4.721087),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.287174, 1.382953, 6.031426),
- (1, 10.283068, 1.389433, 6.021822),
- (2, 10.283543, 1.392869, 6.004187),
- (3, 10.284358, 1.377433, 5.997940),
- (4, 10.289169, 1.391765, 6.007507),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.619409, 1.304847, 4.862155),
- (1, 7.623702, 1.312795, 4.906194),
- (2, 7.621269, 1.306275, 4.840736),
- (3, 7.621495, 1.319364, 4.862966),
- (4, 7.621999, 1.304611, 4.860783),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.367482, 1.401449, 6.145377),
- (1, 10.373043, 1.412685, 6.172106),
- (2, 10.373049, 1.398992, 6.103300),
- (3, 10.373781, 1.396096, 6.107375),
- (4, 10.366926, 1.406716, 6.112696),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.064425, 0.090165, 0.056533),
- (1, 0.062985, 0.083843, 0.047935),
- (2, 0.062983, 0.083616, 0.047921),
- (3, 0.063039, 0.084145, 0.048157),
- (4, 0.063026, 0.084462, 0.048349),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.064141, 0.088108, 0.053766),
- (1, 0.063195, 0.084658, 0.048108),
- (2, 0.063350, 0.085147, 0.049666),
- (3, 0.063052, 0.083725, 0.047925),
- (4, 0.063048, 0.083896, 0.048249),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.195147, 0.299573, 0.157355),
- (1, 0.193085, 0.296310, 0.156304),
- (2, 0.193189, 0.295669, 0.155085),
- (3, 0.193301, 0.292950, 0.152589),
- (4, 0.193210, 0.292226, 0.154638),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.250242, 0.409797, 0.192336),
- (1, 0.248762, 0.398072, 0.187157),
- (2, 0.248680, 0.433130, 0.196985),
- (3, 0.248853, 0.398547, 0.187603),
- (4, 0.248648, 0.405913, 0.188482),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.451387, 0.687142, 0.597211),
- (1, 1.446637, 0.676693, 0.591064),
- (2, 1.449276, 0.677468, 0.591800),
- (3, 1.444318, 0.671687, 0.589322),
- (4, 1.444476, 0.681194, 0.592248),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.264736, 1.132651, 1.424788),
- (1, 4.261695, 1.143089, 1.416857),
- (2, 4.264731, 1.138831, 1.422684),
- (3, 4.264711, 1.140477, 1.417779),
- (4, 4.260991, 1.147619, 1.419141),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.837203, 1.035623, 1.327415),
- (1, 3.869828, 1.033702, 1.331966),
- (2, 3.878679, 1.043199, 1.336928),
- (3, 3.865577, 1.033086, 1.330496),
- (4, 3.854501, 1.024146, 1.328011),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 6.576067, 1.224910, 2.082887),
- (1, 6.555647, 1.214275, 2.066679),
- (2, 6.564496, 1.225676, 2.082281),
- (3, 6.563023, 1.202289, 2.074234),
- (4, 6.574312, 1.203879, 2.075939),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 9.320291, 1.388042, 2.820785),
- (1, 9.321238, 1.374025, 2.817582),
- (2, 9.312721, 1.370752, 2.815972),
- (3, 9.321560, 1.382464, 2.905396),
- (4, 9.315155, 1.367614, 2.814303),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.799699, 1.445598, 2.532217),
- (1, 7.793440, 1.427494, 2.537293),
- (2, 7.794819, 1.451267, 2.540644),
- (3, 7.802867, 1.449885, 2.537256),
- (4, 7.811558, 1.454217, 2.549762),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.518288, 1.557086, 3.158364),
- (1, 10.524251, 1.541390, 3.138438),
- (2, 10.526541, 1.538375, 3.142480),
- (3, 10.516332, 1.562218, 3.192590),
- (4, 10.526898, 1.540009, 3.152245),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 7.894470, 1.472428, 2.647063),
- (1, 7.880948, 1.497803, 2.666059),
- (2, 7.877924, 1.457295, 2.623934),
- (3, 7.880090, 1.463151, 2.671976),
- (4, 7.876586, 1.463586, 2.653038),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"no_pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 10.608510, 1.562882, 3.262625),
- (1, 10.609805, 1.556848, 3.285292),
- (2, 10.618056, 1.550407, 3.276770),
- (3, 10.618343, 1.584988, 3.335703),
- (4, 10.613029, 1.560418, 3.287023),
-]}
-))
-finished = """2009-06-26_10-31"""
diff --git a/www/timing-data/2009-06-26/sketch.pdf b/www/timing-data/2009-06-26/sketch.pdf
deleted file mode 100644
index 0bcf4c3b47fc..000000000000
--- a/www/timing-data/2009-06-26/sketch.pdf
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-06-26/sketch.png b/www/timing-data/2009-06-26/sketch.png
deleted file mode 100644
index 02a63215191f..000000000000
--- a/www/timing-data/2009-06-26/sketch.png
+++ /dev/null
Binary files differ
diff --git a/www/timing-data/2009-06-26/sketch.txt b/www/timing-data/2009-06-26/sketch.txt
deleted file mode 100644
index 5e2331cdea07..000000000000
--- a/www/timing-data/2009-06-26/sketch.txt
+++ /dev/null
@@ -1,803 +0,0 @@
-start = """2009-06-26_10-04"""
-clang = """/Volumes/Data/ddunbar/llvm.install/bin/clang"""
-gcc = """/usr/bin/gcc-4.2"""
-clang_info = """
-clang version 1.0 (https://ddunbar@llvm.org/svn/llvm-project/cfe/trunk 70266M)
-Target: x86_64-apple-darwin10
- "/Volumes/Data/ddunbar/llvm.install/bin/../libexec/clang-cc" "-triple" "x86_64-apple-darwin10" "-S" "-disable-free" "-main-file-name" "null" "--relocation-model" "pic" "-pic-level=1" "--disable-fp-elim" "--unwind-tables=1" "--fmath-errno=0" "-mmacosx-version-min=10.6.0" "-fdiagnostics-show-option" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-vpL9h3.s" "-x" "c" "/dev/null"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-qdRbcC.o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-vpL9h3.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-/cc-qdRbcC.o" "-lSystem" "-lgcc"
-"""
-gcc_info = """
-Using built-in specs.
-Target: i686-apple-darwin10
-Configured with: /var/tmp/gcc/gcc-5646~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
-Thread model: posix
-gcc version 4.2.1 (Apple Inc. build 5646)
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/cc1" "-quiet" "-imultilib" "x86_64" "-D__DYNAMIC__" "/dev/null" "-fPIC" "-quiet" "-dumpbase" "null" "-mmacosx-version-min=10.6.0" "-m64" "-mtune=core2" "-auxbase" "null" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccvaleXF.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/as" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccV9sWHa.o" "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccvaleXF.s"
- "/usr/libexec/gcc/i686-apple-darwin10/4.2.1/collect2" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.6.0" "-weak_reference_mismatches" "non-weak" "-o" "a.out" "-lcrt1.10.6.o" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/x86_64" "-L/usr/lib/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../../i686-apple-darwin10/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin10/4.2.1/../../.." "/var/folders/cl/clrOX6SaG+moCeRKEI4PtU+++TI/-Tmp-//ccV9sWHa.o" "-lSystem" "-lgcc" "-lSystem"
-"""
-style = """xcb"""
-runs = []
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.454775, 0.429118, 0.894442),
- (1, 0.456816, 0.263663, 0.473584),
- (2, 0.455418, 0.263616, 0.471947),
- (3, 0.457123, 0.264847, 0.476358),
- (4, 0.455484, 0.265836, 0.472721),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.456015, 0.267448, 0.475121),
- (1, 0.457929, 0.266122, 0.474585),
- (2, 0.457145, 0.265216, 0.474808),
- (3, 0.458294, 0.263764, 0.475413),
- (4, 0.457468, 0.262464, 0.475923),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.486632, 0.345058, 0.560472),
- (1, 0.493027, 0.344064, 0.516340),
- (2, 0.492830, 0.342958, 0.515723),
- (3, 0.490442, 0.345107, 0.516254),
- (4, 0.496280, 0.343245, 0.518030),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.514260, 0.372418, 0.544621),
- (1, 0.513040, 0.372859, 0.536797),
- (2, 0.512094, 0.370682, 0.534324),
- (3, 0.512872, 0.373514, 0.535788),
- (4, 0.514620, 0.371925, 0.536016),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_pch",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.913210, 0.501577, 4.006777),
- (1, 0.887095, 0.443278, 1.071434),
- (2, 0.889139, 0.440980, 1.078436),
- (3, 0.887708, 0.443451, 1.070797),
- (4, 0.890721, 0.442759, 1.079390),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.388931, 0.727417, 3.522403),
- (1, 2.383308, 0.731864, 3.460458),
- (2, 2.387928, 0.735731, 3.453216),
- (3, 2.378387, 0.727654, 3.672474),
- (4, 2.381366, 0.724858, 3.474937),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.037409, 0.613406, 1.215209),
- (1, 1.040770, 0.634141, 1.205919),
- (2, 1.034234, 0.618161, 1.210088),
- (3, 1.035743, 0.626183, 1.194313),
- (4, 1.035466, 0.621088, 1.181653),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.151380, 2.414929, 4.130644),
- (1, 3.152197, 2.432369, 4.145959),
- (2, 3.169057, 2.386287, 4.135253),
- (3, 3.146057, 2.403489, 4.493451),
- (4, 3.152363, 2.441579, 4.118788),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.400262, 0.704892, 1.375730),
- (1, 1.404950, 0.676989, 1.295341),
- (2, 1.395974, 0.686132, 1.318555),
- (3, 1.402644, 0.668249, 1.302908),
- (4, 1.394704, 0.675209, 1.326093),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.616115, 0.717480, 1.452331),
- (1, 1.624647, 0.706313, 1.364950),
- (2, 1.621780, 0.711227, 1.364399),
- (3, 1.615129, 0.708090, 1.350312),
- (4, 1.627133, 0.705681, 1.380502),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.021269, 2.613351, 4.403274),
- (1, 3.972482, 2.627701, 4.451196),
- (2, 3.966213, 2.540204, 4.303024),
- (3, 3.951820, 2.599589, 4.339412),
- (4, 3.980372, 2.566508, 4.337338),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.735196, 0.782129, 1.452587),
- (1, 1.739009, 0.764330, 1.425707),
- (2, 1.740858, 0.769880, 1.437086),
- (3, 1.741419, 0.762191, 1.403820),
- (4, 1.747043, 0.780665, 1.420343),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.102902, 2.665367, 4.390574),
- (1, 4.097269, 2.666010, 4.359247),
- (2, 4.147762, 2.644022, 4.382155),
- (3, 4.196482, 2.724179, 4.465809),
- (4, 4.137713, 2.652589, 4.396584),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.778593, 0.860038, 1.933043),
- (1, 1.783723, 0.779371, 1.463440),
- (2, 1.776279, 0.782745, 1.449608),
- (3, 1.776952, 0.782233, 1.478619),
- (4, 1.770755, 0.782444, 1.652835),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"8",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.133649, 2.666723, 4.502220),
- (1, 4.164545, 2.606363, 4.423237),
- (2, 4.141087, 2.729139, 4.466176),
- (3, 4.186804, 2.692518, 4.448523),
- (4, 4.135804, 2.680580, 4.428858),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.645824, 0.336540, 1.040349),
- (1, 0.758601, 0.377669, 1.198545),
- (2, 0.802384, 0.385620, 1.256802),
- (3, 0.667186, 0.257789, 0.986552),
- (4, 0.677381, 0.323771, 1.067715),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.654302, 0.326431, 1.043052),
- (1, 0.610937, 0.202433, 0.879312),
- (2, 0.821695, 0.241481, 1.127804),
- (3, 0.633888, 0.315185, 1.009161),
- (4, 0.606823, 0.209530, 0.874705),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.543719, 0.249359, 0.878529),
- (1, 0.864268, 0.407639, 1.357842),
- (2, 0.505443, 0.253217, 0.842801),
- (3, 1.168525, 0.628933, 1.885143),
- (4, 0.860483, 0.294474, 1.244566),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.730678, 0.350816, 1.158314),
- (1, 0.833076, 0.402332, 1.310570),
- (2, 0.626271, 0.280957, 0.987633),
- (3, 0.705011, 0.360332, 1.149777),
- (4, 0.708342, 0.304606, 1.086816),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_pch",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.243931, 0.544136, 1.943868),
- (1, 1.178064, 0.357476, 1.703040),
- (2, 0.921374, 0.438177, 1.525808),
- (3, 1.153771, 0.486733, 1.796961),
- (4, 0.968192, 0.355170, 1.483673),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.493859, 0.712226, 4.011872),
- (1, 2.940300, 0.921172, 4.652497),
- (2, 2.715094, 0.893861, 4.490923),
- (3, 2.610419, 0.709403, 4.118227),
- (4, 2.526798, 0.679792, 3.994116),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.458838, 0.694208, 2.378138),
- (1, 1.817837, 0.740143, 2.805735),
- (2, 1.300085, 0.703071, 2.229211),
- (3, 1.262175, 0.539189, 2.048597),
- (4, 1.191437, 0.497072, 1.923328),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.120749, 1.789574, 5.789810),
- (1, 3.273377, 1.967923, 6.133188),
- (2, 3.037123, 1.733381, 5.596823),
- (3, 3.042984, 1.730581, 5.650857),
- (4, 3.188306, 1.759639, 5.884737),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.542473, 0.612384, 2.425046),
- (1, 1.545307, 0.697333, 2.515996),
- (2, 1.600507, 0.604696, 2.460228),
- (3, 1.632270, 0.718514, 2.592235),
- (4, 1.928976, 0.629692, 2.794199),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.770525, 0.684705, 2.712227),
- (1, 1.887006, 0.676721, 2.808092),
- (2, 1.625953, 0.651827, 2.513331),
- (3, 1.773543, 0.671273, 2.695842),
- (4, 1.601478, 0.621009, 2.649159),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.114128, 2.094426, 7.063334),
- (1, 4.025352, 1.957465, 6.838969),
- (2, 3.821735, 1.946024, 6.632936),
- (3, 3.907138, 2.007547, 7.016114),
- (4, 4.024595, 2.043679, 6.922250),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.056124, 0.710399, 3.025185),
- (1, 1.804336, 0.726053, 2.772563),
- (2, 1.967191, 0.656225, 2.892478),
- (3, 2.201167, 1.485126, 3.955987),
- (4, 1.994297, 0.676570, 2.914002),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.153794, 1.918740, 6.996844),
- (1, 4.211883, 1.937034, 7.076586),
- (2, 4.084567, 1.959342, 6.944548),
- (3, 4.648222, 2.460079, 7.979059),
- (4, 4.136109, 1.985068, 6.960107),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.028821, 0.718882, 3.022737),
- (1, 1.843870, 0.711606, 2.811073),
- (2, 1.985330, 0.640222, 2.873062),
- (3, 2.060936, 0.694181, 3.004850),
- (4, 1.897412, 0.741471, 2.895000),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"1",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.126488, 1.921937, 7.213964),
- (1, 4.030952, 2.008876, 6.892632),
- (2, 4.003183, 1.903866, 6.818411),
- (3, 4.002316, 1.899865, 6.714604),
- (4, 4.241685, 2.074201, 7.178083),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.438307, 0.207037, 0.506107),
- (1, 0.443102, 0.205874, 0.504716),
- (2, 0.439711, 0.209035, 0.506141),
- (3, 0.436863, 0.206002, 0.504331),
- (4, 0.439627, 0.206224, 0.505025),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.439477, 0.207192, 0.504912),
- (1, 0.437463, 0.209372, 0.504820),
- (2, 0.437903, 0.206376, 0.506661),
- (3, 0.442930, 0.207493, 0.505236),
- (4, 0.437359, 0.206906, 0.505647),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.476966, 0.260986, 0.572957),
- (1, 0.478184, 0.263035, 0.573059),
- (2, 0.469230, 0.262187, 0.571016),
- (3, 0.469081, 0.262310, 0.570270),
- (4, 0.487872, 0.261247, 0.573296),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.500065, 0.287104, 0.600696),
- (1, 0.490454, 0.288579, 0.599350),
- (2, 0.489178, 0.290420, 0.595453),
- (3, 0.504358, 0.305761, 0.621200),
- (4, 0.488484, 0.284586, 0.593988),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_pch",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.863838, 0.365213, 1.134056),
- (1, 0.879504, 0.384604, 1.159071),
- (2, 0.865340, 0.363764, 1.135322),
- (3, 0.870478, 0.367344, 1.160674),
- (4, 0.872049, 0.365320, 1.137567),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.356240, 0.639645, 3.459472),
- (1, 2.360200, 0.659262, 3.524492),
- (2, 2.357683, 0.643919, 3.503642),
- (3, 2.356418, 0.645647, 3.487224),
- (4, 2.373107, 0.644771, 3.481359),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.020421, 0.527766, 1.342095),
- (1, 1.015704, 0.514000, 1.336929),
- (2, 1.012705, 0.511238, 1.355272),
- (3, 1.017781, 0.525921, 1.395570),
- (4, 1.018256, 0.517513, 1.810392),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.236664, 1.833475, 5.064647),
- (1, 3.116394, 1.846229, 4.585106),
- (2, 3.109082, 1.861524, 4.545915),
- (3, 3.105011, 1.846408, 4.555086),
- (4, 3.098872, 1.865976, 4.564655),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.380699, 0.583314, 1.565867),
- (1, 1.388951, 0.550808, 1.551250),
- (2, 1.413442, 0.605844, 2.090865),
- (3, 1.387903, 0.560118, 1.544868),
- (4, 1.380258, 0.556370, 1.545919),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.594818, 0.585227, 1.667099),
- (1, 1.592606, 0.587092, 1.672961),
- (2, 1.593256, 0.589412, 1.669080),
- (3, 1.593986, 0.587601, 1.669540),
- (4, 1.596080, 0.588672, 1.661919),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.936649, 2.035445, 5.031351),
- (1, 3.945642, 1.975630, 5.060494),
- (2, 3.944102, 1.986388, 5.217065),
- (3, 3.942765, 1.958722, 5.007943),
- (4, 3.942774, 1.998893, 5.220903),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.712580, 0.646710, 1.767951),
- (1, 1.726718, 0.639926, 1.762359),
- (2, 1.715856, 0.663728, 1.801439),
- (3, 1.710717, 0.642142, 1.748022),
- (4, 1.711775, 0.639969, 1.762574),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.100132, 2.051387, 5.193869),
- (1, 4.080168, 2.011265, 5.256560),
- (2, 4.081965, 2.023322, 5.162267),
- (3, 4.095547, 2.044797, 5.131689),
- (4, 4.083693, 2.027487, 5.067421),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.750192, 0.645773, 1.781508),
- (1, 1.751823, 0.651023, 1.799043),
- (2, 1.746203, 0.648456, 1.799824),
- (3, 1.743422, 0.650594, 1.813096),
- (4, 1.743223, 0.647433, 1.804423),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"2",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.112210, 2.030036, 5.210062),
- (1, 4.134068, 2.036290, 5.134560),
- (2, 4.106223, 2.031620, 5.167160),
- (3, 4.111138, 2.067136, 5.242598),
- (4, 4.114321, 2.105259, 5.219405),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"null",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.450242, 0.234466, 0.468920),
- (1, 0.452251, 0.234237, 0.472734),
- (2, 0.449428, 0.230498, 0.469181),
- (3, 0.451854, 0.234653, 0.471594),
- (4, 0.450034, 0.233853, 0.470746),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"null",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.451976, 0.237066, 0.471837),
- (1, 0.451032, 0.232549, 0.469509),
- (2, 0.450837, 0.235248, 0.469812),
- (3, 0.451435, 0.236156, 0.471181),
- (4, 0.454297, 0.235811, 0.472732),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"###",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.487874, 0.301226, 0.520971),
- (1, 0.485966, 0.302353, 0.522738),
- (2, 0.487933, 0.320309, 0.538211),
- (3, 0.484292, 0.301703, 0.518200),
- (4, 0.485094, 0.300915, 0.519927),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"###",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.507246, 0.328269, 0.538592),
- (1, 0.504679, 0.327246, 0.536575),
- (2, 0.506116, 0.325455, 0.534917),
- (3, 0.504966, 0.325033, 0.535512),
- (4, 0.504264, 0.325877, 0.537850),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_pch",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 0.878871, 0.406325, 1.083290),
- (1, 0.881664, 0.406706, 1.089465),
- (2, 0.879953, 0.403525, 1.089816),
- (3, 0.880059, 0.403838, 1.081420),
- (4, 0.882767, 0.404104, 1.081738),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_pch",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 2.376690, 0.683461, 3.481408),
- (1, 2.371811, 0.678423, 3.554769),
- (2, 2.373430, 0.687361, 3.496073),
- (3, 2.371478, 0.675612, 3.438700),
- (4, 2.377505, 0.688872, 3.424400),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.042312, 0.579073, 1.213381),
- (1, 1.044438, 0.584515, 1.205995),
- (2, 1.038797, 0.582026, 1.219606),
- (3, 1.040786, 0.577159, 1.215521),
- (4, 1.043000, 0.577868, 1.223773),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"syntax",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 3.231130, 2.567647, 4.158387),
- (1, 3.235798, 2.498238, 4.418977),
- (2, 3.238465, 2.529717, 4.211575),
- (3, 3.239709, 2.495562, 4.156266),
- (4, 3.231558, 2.493020, 4.108168),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"irgen",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.421647, 0.642906, 1.341418),
- (1, 1.421549, 0.646429, 1.343189),
- (2, 1.433072, 0.641680, 1.327081),
- (3, 1.428600, 0.639478, 1.332256),
- (4, 1.427077, 0.643784, 1.322933),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.654124, 0.663628, 1.402498),
- (1, 1.643467, 0.662131, 1.386214),
- (2, 1.653972, 0.671458, 1.393807),
- (3, 1.646365, 0.671024, 1.395913),
- (4, 1.651021, 0.662302, 1.404011),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_asm",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.297588, 2.725803, 4.463298),
- (1, 4.286029, 2.678946, 4.487945),
- (2, 4.280374, 2.696217, 4.492516),
- (3, 4.305121, 2.681000, 4.491615),
- (4, 4.290141, 2.697022, 4.485084),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.763493, 0.720256, 1.438810),
- (1, 1.766202, 0.720674, 1.581947),
- (2, 1.766634, 0.722865, 1.439302),
- (3, 1.767231, 0.726466, 1.455122),
- (4, 1.765071, 0.725319, 1.443411),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"only_compile",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.439486, 2.767478, 4.493862),
- (1, 4.450584, 2.723827, 4.523759),
- (2, 4.446754, 2.728436, 4.522514),
- (3, 4.418589, 2.747071, 4.539960),
- (4, 4.449233, 2.763071, 4.578583),
-]}
-))
-runs.append(( { 'cc':"clang_pch",
- 'script':"all",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 1.796239, 0.738339, 1.484091),
- (1, 1.804887, 0.734832, 1.484408),
- (2, 1.799010, 0.745599, 1.487400),
- (3, 1.795834, 0.735356, 1.480006),
- (4, 1.806408, 0.745381, 1.483771),
-]}
-))
-runs.append(( { 'cc':"gcc",
- 'script':"all",
- 'threads':"4",
- 'pch':"pch" },
-{ 'version' : 0,
- 'samples' : [
- (0, 4.450745, 2.820108, 4.598335),
- (1, 4.492508, 2.802745, 4.608004),
- (2, 4.484814, 2.762586, 4.664950),
- (3, 4.428110, 2.724648, 4.700769),
- (4, 4.451598, 2.814003, 4.559797),
-]}
-))
-finished = """2009-06-26_10-19"""